Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
8048265
Initial placement of review prompt in post publish panel
jboland88 Dec 12, 2022
c847359
Add ability to dismiss review prompt
jboland88 Dec 13, 2022
901e2bc
Update the permission check function name
jboland88 Dec 13, 2022
c6e97d5
changelog
jboland88 Dec 13, 2022
9b3aa6d
Update conditions for showing the review prompt
jboland88 Dec 13, 2022
42e7dd4
Merge branch 'trunk' into add/review-prompt-for-social-plugin
jboland88 Dec 13, 2022
f33df82
Fix project versions
jboland88 Dec 13, 2022
9cb73e6
Add analytics to review prompt
jboland88 Dec 14, 2022
34c81e5
Swap out typed URL
jboland88 Dec 14, 2022
86c196c
Conditionally load the connection state
jboland88 Dec 14, 2022
e0f1af0
Merge branch 'trunk' into add/review-prompt-for-social-plugin
jboland88 Dec 16, 2022
758f901
Updates based on feedback, performance improvements
jboland88 Dec 16, 2022
238ab43
Fix connection package JS error
jboland88 Dec 16, 2022
8a229b5
move analytics functionality into an existing hook, fix logic error
jboland88 Dec 16, 2022
aa17799
changelog
jboland88 Dec 16, 2022
22df7ae
Refine conditions for when the review request should show
jboland88 Dec 16, 2022
ca735f8
Merge branch 'trunk' into add/review-prompt-for-social-plugin
jboland88 Dec 20, 2022
c7085a2
Allow review prompt to be disabled via filter, add check for post alr…
jboland88 Dec 20, 2022
a968251
Change method for checking whether post is already shared
jboland88 Dec 20, 2022
a51e859
changelog
jboland88 Dec 20, 2022
08dcd1a
Fix meta default for already shared
jboland88 Dec 20, 2022
bb7faf3
version management
jboland88 Dec 20, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: added

Add a review request prompt for Jetpack Social plugin
1 change: 1 addition & 0 deletions projects/js-packages/publicize-components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export { default as TwitterOptions } from './src/components/twitter/options';
export { default as SocialPreviewsModal } from './src/components/social-previews/modal';
export { default as SocialPreviewsPanel } from './src/components/social-previews/panel';
export { default as PublicizePanel } from './src/components/panel';
export { default as ReviewPrompt } from './src/components/review-prompt';

export { default as useSocialMediaConnections } from './src/hooks/use-social-media-connections';
export { default as useSocialMediaMessage } from './src/hooks/use-social-media-message';
Expand Down
4 changes: 3 additions & 1 deletion projects/js-packages/publicize-components/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"private": true,
"name": "@automattic/jetpack-publicize-components",
"version": "0.11.1-alpha",
"version": "0.12.0-alpha",
"description": "A library of JS components required by the Publicize editor plugin",
"homepage": "https://github.com/Automattic/jetpack/tree/HEAD/projects/js-packages/publicize-components/#readme",
"bugs": {
Expand All @@ -21,6 +21,8 @@
"dependencies": {
"@automattic/jetpack-components": "workspace:*",
"@automattic/jetpack-shared-extension-utils": "workspace:*",
"@automattic/jetpack-analytics": "workspace:*",
"@automattic/jetpack-connection": "workspace:*",
"@automattic/social-previews": "1.1.5",
"@wordpress/api-fetch": "6.19.0",
"@wordpress/blocks": "11.21.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* Panel that requests a review of the Jetpack Social Plugin
* Shows in the post publish panel of the editor
*/

import { Button, ThemeProvider } from '@automattic/jetpack-components';
import { __, sprintf } from '@wordpress/i18n';
import { useCallback } from 'react';
import useAnalyticsTracksForConnectedUser from '../../hooks/use-anaytics-tracks-for-connected-user';
import styles from './styles.module.scss';

const ReviewPrompt = ( { href, onClose } ) => {
const { recordEvent } = useAnalyticsTracksForConnectedUser( {
pageViewEventName: 'social_plugin_review_prompt',
pageViewNamespace: 'jetpack',
pageViewSuffix: 'view',
} );

const recordReviewClick = useCallback( () => {
recordEvent( 'jetpack_social_plugin_review_prompt_new_review_click' );
}, [ recordEvent ] );

const handleDismiss = useCallback( () => {
recordEvent( 'jetpack_social_plugin_review_prompt_dismiss_click' );
onClose();
}, [ recordEvent, onClose ] );

return (
<ThemeProvider>
<div className={ styles.prompt }>
<h2 className={ styles.header }>
{
/* translators: %s is the celebration emoji */
sprintf( __( 'Presto! %s', 'jetpack' ), String.fromCodePoint( 0x1f389 ) )
}
</h2>
<p>
{ __(
'Just like that, Jetpack Social has shared your post to your connected social accounts.',
'jetpack'
) }
</p>
<p>
{ __(
'Please leave a review to let others know how easy getting your posts on social media can be!',
'jetpack'
) }
</p>
<div className={ styles.buttons }>
<Button
onClick={ recordReviewClick }
isExternalLink
href={ href }
className={ styles.button }
>
{ __( 'Leave a Review', 'jetpack' ) }
</Button>
<Button onClick={ handleDismiss } variant="link" className={ styles.button }>
{ __( 'Dismiss', 'jetpack' ) }
</Button>
</div>
</div>
</ThemeProvider>
);
};

export default ReviewPrompt;
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
.prompt {
border: 2px solid var( --jp-green-40 );
border-radius: 4px;
padding: calc( var( --spacing-base ) * 2 ) calc( var( --spacing-base ) * 3 );
display: block;
justify-content: space-between;
align-items: center;
gap: calc( var( --spacing-base ) * 3 );
text-align: left;
background: none;
margin: 0;
width: 100%;
text-decoration: none;
color: var( --jp-gray-90 );

&:focus, &:active {
outline-color: var( --jp-black );
}

// somewhat unfortunate specificity override
.buttons button.button {
font-size: var( --font-body-small );
}
}

.header {
font-size: var( --font-body );
}

.buttons {
display: flex;
flex-direction: column;
gap: var(--spacing-base);
align-content: space-between;
}

.button {
width: 100%;
align-items: center;
justify-content: space-between;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# useAnalyticsTracksForConnectedUser hook

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just happened to create useAnalytics() that was merged yesterday. :) Maybe we could use that / expand on it in this PR instead of a new hook?

I reached out to the Reach team about this here, and they seemed interested:
p1671107976320099-slack-C02JJ910CNL

Maybe that'd be the opportunity to start using in Jetpack Social?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, nice. Yeah seems like your hook is in the same spirit!
Sounds like a good plan to update the one you added instead of adding a new one.

Do you think the check for a Jetpack connected user in the hook I added is too opinionated for the useAnalytics hook?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It may be fine in useAnalytics as well. I must say I haven't tested with disconnected users until now, since I had assumed the Tracks library wouldn't be enqueued anyway, so nothing would happen.

This hook is used to facilitate recording of tracks analytics events,
limiting recording of events to when a user has a Jetpack connection.

The hook function also accepts parameters to record a "page view" event when the component renders.
```es6

const Component = () => {
const { recordEvent } = useAnalyticsTracks( {
pageViewEventName: 'view_event_name',
pageViewNamespace: 'jetpack',
pageViewSuffix: '',
} );
const recordReviewClick = useCallback( () => { recordEvent( 'event_name', {} ) }, [] );

return (
<Button
onClick={ recordReviewClick }
>
{ __( 'Leave a Review', 'jetpack' ) }
</Button>
)
}
```
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import jetpackAnalytics from '@automattic/jetpack-analytics';
import { useConnection } from '@automattic/jetpack-connection';
import { useState, useCallback, useEffect, useMemo } from 'react';

const { tracks } = jetpackAnalytics;
const { recordEvent } = tracks;

const useAnalyticsTracksForConnectedUser = ( {
pageViewEventName,
pageViewNamespace = 'jetpack',
pageViewSuffix = 'page_view',
pageViewEventProperties = {},
} = {} ) => {
const [ pageViewRecorded, setPageViewRecorded ] = useState( false );
const { isUserConnected, isRegistered, userConnectionData } = useConnection();
const { login, ID } = useMemo( () => {
return userConnectionData.currentUser?.wpcomUser || {};
}, [ userConnectionData.currentUser ] );

const recordEventAsync = useCallback(
async ( event, properties = {} ) => {
// Do nothing if there is not a connected user.
if ( ! ( isUserConnected && ID && login ) ) {
return;
}
recordEvent( event, properties );
},
[ isUserConnected, ID, login ]
);

// Initialize Analytics identifying the user.
useEffect( () => {
if ( ! ( isUserConnected && ID && login ) ) {
return;
}
jetpackAnalytics.initialize( ID, login );
}, [ isUserConnected, ID, login ] );

/*
* Track page-view event.
* It's considered a page view event
* when the component is mounted.
*/
useEffect( () => {
const pageViewEvent = pageViewEventName
? `${ pageViewNamespace }_${ pageViewEventName }_${ pageViewSuffix }`
: null;

// Also, only run if the site is registered.
if ( ! isRegistered ) {
return;
}

if ( ! pageViewEvent ) {
return;
}

// Ensuring we only record the view event once
if ( ! pageViewRecorded ) {
recordEventAsync( pageViewEvent, pageViewEventProperties );
setPageViewRecorded( true );
}
}, [
pageViewRecorded,
pageViewNamespace,
pageViewEventName,
pageViewSuffix,
isRegistered,
pageViewEventProperties,
recordEventAsync,
] );

return {
recordEvent: recordEventAsync,
};
};
export default useAnalyticsTracksForConnectedUser;
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: added

Add a review request prompt for Jetpack Social plugin
1 change: 1 addition & 0 deletions projects/plugins/social/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"@automattic/jetpack-components": "workspace:*",
"@automattic/jetpack-connection": "workspace:*",
"@automattic/jetpack-publicize-components": "workspace:*",
"@automattic/jetpack-shared-extension-utils": "workspace:*",
"@wordpress/api-fetch": "6.19.0",
"@wordpress/components": "22.1.0",
"@wordpress/data": "7.6.0",
Expand Down
31 changes: 30 additions & 1 deletion projects/plugins/social/src/class-jetpack-social.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
use Automattic\Jetpack\Modules;
use Automattic\Jetpack\My_Jetpack\Initializer as My_Jetpack_Initializer;
use Automattic\Jetpack\Status;
use Automattic\Jetpack\Terms_Of_Service;
use Automattic\Jetpack\Tracking;

/**
* Class Jetpack_Social
Expand All @@ -25,6 +27,7 @@ class Jetpack_Social {
const JETPACK_PUBLICIZE_MODULE_SLUG = 'publicize';
const JETPACK_SOCIAL_ACTIVATION_OPTION = JETPACK_SOCIAL_PLUGIN_SLUG . '_activated';
const JETPACK_SOCIAL_SHOW_PRICING_PAGE_OPTION = JETPACK_SOCIAL_PLUGIN_SLUG . '_show_pricing_page';
const JETPACK_SOCIAL_REVIEW_DISMISSED_OPTION = JETPACK_SOCIAL_PLUGIN_SLUG . '_review_prompt_dismissed';

/**
* The connection manager used to check if we have a Jetpack connection.
Expand Down Expand Up @@ -287,7 +290,6 @@ class_exists( 'Jetpack' ) ||
);

Assets::enqueue_script( 'jetpack-social-editor' );

wp_localize_script(
'jetpack-social-editor',
'Jetpack_Editor_Initial_State',
Expand All @@ -296,6 +298,8 @@ class_exists( 'Jetpack' ) ||
'social' => array(
'adminUrl' => esc_url_raw( admin_url( 'admin.php?page=jetpack-social' ) ),
'sharesData' => $publicize->get_publicize_shares_info( Jetpack_Options::get_option( 'id' ) ),
'reviewRequestDismissed' => self::is_review_request_dismissed(),
'dismissReviewRequestPath' => '/jetpack/v4/social/review-dismiss',
'connectionRefreshPath' => '/jetpack/v4/publicize/connection-test-results',
'resharePath' => '/jetpack/v4/publicize/{postId}',
'publicizeConnectionsUrl' => esc_url_raw(
Expand All @@ -307,6 +311,10 @@ class_exists( 'Jetpack' ) ||
)
);

if ( 'draft' === get_post_status() && self::can_use_analytics() && ! self::is_review_request_dismissed() ) {
wp_add_inline_script( 'jetpack-social-editor', Connection_Initial_State::render(), 'before' );
Comment thread
jboland88 marked this conversation as resolved.
Resolved
Tracking::register_tracks_functions_scripts( true );
}
}

/**
Expand Down Expand Up @@ -398,6 +406,27 @@ public static function should_show_pricing_page() {
return (bool) get_option( self::JETPACK_SOCIAL_SHOW_PRICING_PAGE_OPTION, 1 );
}

/**
* Check to see if the request to review the plugin has already been dismissed.
*
* @return bool
*/
public static function is_review_request_dismissed() {
return (bool) get_option( self::JETPACK_SOCIAL_REVIEW_DISMISSED_OPTION, false );
}

/**
* Returns whether we are in condition to track to use
* Analytics functionality like Tracks, MC, or GA.
*/
public static function can_use_analytics() {
$status = new Status();
$connection = new Connection_Manager();
$tracking = new Tracking( 'jetpack', $connection );

return $tracking->should_enable_tracking( new Terms_Of_Service(), $status );
}

/**
* Add a link to the admin page from the plugins page.
*
Expand Down
Loading