Add notice to connect to woocommerce.com in wc settings and marketplace (#45536)

* add a woo.com connect notice in the plugin list for unconnected store

* add an extra notice string for store that runs outdated woo plugins

* add connect page hyoerlink to the plugin notice

* add changelog

* add comment for maybe_show_connect_notice_in_plugin_list()

* fix linter error

* use installed local woo plugin as the counter of extra notices

* only show woo connect notice in the woocommerce settings page

* add woocom connect notice component

* add woocom connect notice component to the content component

* add extra notice in the woocom connect notice component based on the local woo plugins count

* persist dismissal of woo connect notice in the wc admin settings page

* update changelog

* use update-check-public for unconnected stores

* use information from update-check-public API to determine notice show logic

* re-show dismissed connect woocom notice after 1 month

* add re-show notice logic for react admin page of woo connect notice

* fix identation

* differentiate local storage key for notice dismissal

* move woo connect notice script to different file

* rename to connectnotice

* fix linter issue

* fix linter issue

* update woo.com to woocommerce.com

* update woo.com to woocommerce.com in comment

* capitalize the WooCommerce.com

Co-authored-by: Leif Singer <leif@automattic.com>

* capitalize WooCommerce.com

---------

Co-authored-by: Leif Singer <leif@automattic.com>
This commit is contained in:
Prahesa Kusuma Setia 2024-04-17 17:13:24 +07:00 committed by GitHub
parent c0424210ab
commit 1fddbb1001
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 230 additions and 0 deletions

View File

@ -0,0 +1,76 @@
/**
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
/**
* Internal dependencies
*/
import { connectUrl } from '~/marketplace/utils/functions';
import Notice from '~/marketplace/components/notice/notice';
import { getAdminSetting } from '~/utils/admin-settings';
export default function ConnectNotice(): JSX.Element | null {
const localStorageKey = 'woo-connect-notice-marketplace-dismissed';
const wccomSettings = getAdminSetting( 'wccomHelper', {} );
const noticeType = wccomSettings?.woocomConnectNoticeType || 'none';
if ( noticeType === 'none' ) {
return null;
}
const lastDismissed = localStorage.getItem( localStorageKey );
const parsedDismissedDate = new Date( lastDismissed || '' );
const aMonthAgo = new Date();
aMonthAgo.setMonth( aMonthAgo.getMonth() - 1 );
// try to re-show the notice if it was dismissed more than a month ago.
// removing these 2 local storage items will make the notice reappear.
if (
lastDismissed === null ||
isNaN( parsedDismissedDate.valueOf() ) ||
aMonthAgo.valueOf() > parsedDismissedDate.valueOf()
) {
localStorage.removeItem(
'wc-marketplaceNoticeClosed-woo-connect-notice'
);
localStorage.removeItem( localStorageKey );
}
let description = '';
if ( noticeType === 'long' ) {
description = description.concat(
__(
'Your store might be at risk as you are running old versions of WooCommerce plugins.',
'woocommerce'
)
);
description = description.concat( ' ' );
}
description = description.concat(
__(
'<strong>Connect your store to WooCommerce.com</strong> to get updates and streamlined support for your subscriptions.',
'woocommerce'
)
);
return (
<Notice
id="woo-connect-notice"
description={ description }
isDismissible={ true }
variant="error"
onClose={ () => {
localStorage.setItem( localStorageKey, new Date().toString() );
} }
>
<Button href={ connectUrl() } variant="secondary">
{ __( 'Connect', 'woocommerce' ) }
</Button>
</Notice>
);
}

View File

@ -23,6 +23,7 @@ import {
} from '../../utils/tracking'; } from '../../utils/tracking';
import InstallNewProductModal from '../install-flow/install-new-product-modal'; import InstallNewProductModal from '../install-flow/install-new-product-modal';
import Promotions from '../promotions/promotions'; import Promotions from '../promotions/promotions';
import ConnectNotice from '~/marketplace/components/connect-notice/connect-notice';
export default function Content(): JSX.Element { export default function Content(): JSX.Element {
const marketplaceContextValue = useContext( MarketplaceContext ); const marketplaceContextValue = useContext( MarketplaceContext );
@ -137,6 +138,7 @@ export default function Content(): JSX.Element {
<div className="woocommerce-marketplace__content"> <div className="woocommerce-marketplace__content">
<Promotions /> <Promotions />
<InstallNewProductModal products={ products } /> <InstallNewProductModal products={ products } />
<ConnectNotice />
{ renderContent() } { renderContent() }
</div> </div>
); );

View File

@ -18,6 +18,7 @@ export interface NoticeProps {
icon?: string; icon?: string;
isDismissible: boolean; isDismissible: boolean;
variant: string; variant: string;
onClose?: () => void;
} }
type IconKey = keyof typeof iconMap; type IconKey = keyof typeof iconMap;
@ -37,6 +38,7 @@ export default function Notice( props: NoticeProps ): JSX.Element | null {
icon, icon,
isDismissible = true, isDismissible = true,
variant = 'info', variant = 'info',
onClose,
} = props; } = props;
const [ isVisible, setIsVisible ] = useState( const [ isVisible, setIsVisible ] = useState(
localStorage.getItem( `wc-marketplaceNoticeClosed-${ id }` ) !== 'true' localStorage.getItem( `wc-marketplaceNoticeClosed-${ id }` ) !== 'true'
@ -45,6 +47,9 @@ export default function Notice( props: NoticeProps ): JSX.Element | null {
const handleClose = () => { const handleClose = () => {
setIsVisible( false ); setIsVisible( false );
localStorage.setItem( `wc-marketplaceNoticeClosed-${ id }`, 'true' ); localStorage.setItem( `wc-marketplaceNoticeClosed-${ id }`, 'true' );
if ( typeof onClose === 'function' ) {
onClose();
}
}; };
if ( ! isVisible ) return null; if ( ! isVisible ) return null;

View File

@ -0,0 +1,32 @@
window.jQuery( document ).ready( function () {
// hide the notice when the customer clicks the dismiss button up until 1 month, then it will be shown again.
const wooConnectNoticeSelector = '.woo-connect-notice';
const localStorageKey = 'woo-connect-notice-settings-dismissed';
window
.jQuery( wooConnectNoticeSelector )
.on( 'click', 'button.notice-dismiss', function () {
window.localStorage.setItem(
localStorageKey,
new Date().toString()
);
} );
let shouldHideNotice = false;
const savedDismissedDate = window.localStorage.getItem( localStorageKey );
const parsedDismissedDate = new Date( savedDismissedDate || '' );
const aMonthAgo = new Date();
aMonthAgo.setMonth( aMonthAgo.getMonth() - 1 );
if (
savedDismissedDate &&
aMonthAgo.valueOf() < parsedDismissedDate.valueOf()
) {
shouldHideNotice = true;
}
if ( shouldHideNotice ) {
window.jQuery( wooConnectNoticeSelector ).remove();
}
} );

View File

@ -73,6 +73,7 @@ const wpAdminScripts = [
'shipping-settings-region-picker', 'shipping-settings-region-picker',
'command-palette', 'command-palette',
'command-palette-analytics', 'command-palette-analytics',
'woo-connect-notice',
]; ];
const getEntryPoints = () => { const getEntryPoints = () => {
const entryPoints = { const entryPoints = {

View File

@ -0,0 +1,4 @@
Significance: minor
Type: add
Add a connect to woocommerce.com notices for unconnected stores in the wc settings and wc marketplace page.

View File

@ -50,6 +50,8 @@ class WC_Helper_Admin {
$installed_products $installed_products
); );
$woo_connect_notice_type = WC_Helper_Updater::get_woo_connect_notice_type();
$settings['wccomHelper'] = array( $settings['wccomHelper'] = array(
'isConnected' => WC_Helper::is_site_connected(), 'isConnected' => WC_Helper::is_site_connected(),
'connectURL' => self::get_connection_url(), 'connectURL' => self::get_connection_url(),
@ -63,6 +65,7 @@ class WC_Helper_Admin {
'wooUpdateManagerInstallUrl' => WC_Woo_Update_Manager_Plugin::generate_install_url(), 'wooUpdateManagerInstallUrl' => WC_Woo_Update_Manager_Plugin::generate_install_url(),
'wooUpdateManagerPluginSlug' => WC_Woo_Update_Manager_Plugin::WOO_UPDATE_MANAGER_SLUG, 'wooUpdateManagerPluginSlug' => WC_Woo_Update_Manager_Plugin::WOO_UPDATE_MANAGER_SLUG,
'wooUpdateCount' => WC_Helper_Updater::get_updates_count_based_on_site_status(), 'wooUpdateCount' => WC_Helper_Updater::get_updates_count_based_on_site_status(),
'woocomConnectNoticeType' => $woo_connect_notice_type,
); );
return $settings; return $settings;

View File

@ -557,6 +557,45 @@ class WC_Helper_Updater {
return $count; return $count;
} }
/**
* Get the type of woo connect notice to be shown in the WC Settings and Marketplace pages.
* - If a store is connected to woocommerce.com or has no installed woo plugins, return 'none'.
* - If a store has installed woo plugins but no updates, return 'short'.
* - If a store has an installed woo plugin with update, return 'long'.
*
* @return string The notice type, 'none', 'short', or 'long'.
*/
public static function get_woo_connect_notice_type() {
if ( WC_Helper::is_site_connected() ) {
return 'none';
}
$woo_plugins = WC_Helper::get_local_woo_plugins();
if ( empty( $woo_plugins ) ) {
return 'none';
}
$update_data = self::get_update_data();
if ( empty( $update_data ) ) {
return 'short';
}
// Scan local plugins.
foreach ( $woo_plugins as $plugin ) {
if ( empty( $update_data[ $plugin['_product_id'] ] ) ) {
continue;
}
if ( version_compare( $plugin['Version'], $update_data[ $plugin['_product_id'] ]['version'], '<' ) ) {
return 'long';
}
}
return 'short';
}
/** /**
* Return the updates count markup. * Return the updates count markup.
* *

View File

@ -13,7 +13,10 @@ use ActionScheduler_QueueRunner;
use Automatic_Upgrader_Skin; use Automatic_Upgrader_Skin;
use Automattic\WooCommerce\Admin\PluginsInstallLoggers\AsyncPluginsInstallLogger; use Automattic\WooCommerce\Admin\PluginsInstallLoggers\AsyncPluginsInstallLogger;
use Automattic\WooCommerce\Admin\PluginsInstallLoggers\PluginsInstallLogger; use Automattic\WooCommerce\Admin\PluginsInstallLoggers\PluginsInstallLogger;
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
use Plugin_Upgrader; use Plugin_Upgrader;
use WC_Helper;
use WC_Helper_Updater;
use WP_Error; use WP_Error;
use WP_Upgrader; use WP_Upgrader;
@ -35,6 +38,8 @@ class PluginsHelper {
add_action( 'woocommerce_plugins_install_callback', array( __CLASS__, 'install_plugins' ), 10, 2 ); add_action( 'woocommerce_plugins_install_callback', array( __CLASS__, 'install_plugins' ), 10, 2 );
add_action( 'woocommerce_plugins_install_and_activate_async_callback', array( __CLASS__, 'install_and_activate_plugins_async_callback' ), 10, 2 ); add_action( 'woocommerce_plugins_install_and_activate_async_callback', array( __CLASS__, 'install_and_activate_plugins_async_callback' ), 10, 2 );
add_action( 'woocommerce_plugins_activate_callback', array( __CLASS__, 'activate_plugins' ), 10, 2 ); add_action( 'woocommerce_plugins_activate_callback', array( __CLASS__, 'activate_plugins' ), 10, 2 );
add_action( 'admin_notices', array( __CLASS__, 'maybe_show_connect_notice_in_plugin_list' ) );
add_action( 'admin_enqueue_scripts', array( __CLASS__, 'maybe_enqueue_scripts_for_connect_notice' ) );
} }
/** /**
@ -532,4 +537,67 @@ class PluginsHelper {
return self::get_action_data( $actions ); return self::get_action_data( $actions );
} }
/**
* Show notices to connect to woocommerce.com for unconnected store in the plugin list.
*
* @return void
*/
public static function maybe_show_connect_notice_in_plugin_list() {
if ( 'woocommerce_page_wc-settings' !== get_current_screen()->id ) {
return;
}
$notice_type = WC_Helper_Updater::get_woo_connect_notice_type();
if ( 'none' === $notice_type ) {
return;
}
$notice_string = '';
if ( 'long' === $notice_type ) {
$notice_string .= __( 'Your store might be at risk as you are running old versions of WooCommerce plugins.', 'woocommerce' );
$notice_string .= ' ';
}
$connect_page_url = add_query_arg(
array(
'page' => 'wc-admin',
'tab' => 'my-subscriptions',
'path' => rawurlencode( '/extensions' ),
),
admin_url( 'admin.php' )
);
$notice_string .= sprintf(
/* translators: %s: Connect page URL */
__( '<a href="%s">Connect your store</a> to WooCommerce.com to get updates and streamlined support for your subscriptions.', 'woocommerce' ),
esc_url( $connect_page_url )
);
echo '<div class="woo-connect-notice notice notice-error is-dismissible">
<p class="widefat">' . wp_kses_post( $notice_string ) . '</p>
</div>';
}
/**
* Enqueue scripts for connect notice.
*
* @return void
*/
public static function maybe_enqueue_scripts_for_connect_notice() {
if ( 'woocommerce_page_wc-settings' !== get_current_screen()->id ) {
return;
}
$notice_type = WC_Helper_Updater::get_woo_connect_notice_type();
if ( 'none' === $notice_type ) {
return;
}
WCAdminAssets::register_script( 'wp-admin-scripts', 'woo-connect-notice' );
wp_enqueue_script( 'woo-connect-notice' );
}
} }