From dc156d034755b4e3ed0f2ebc1e54b831a81d66b4 Mon Sep 17 00:00:00 2001 From: Dylan Munson <65001528+CodeyGuyDylan@users.noreply.github.com> Date: Mon, 10 Jun 2024 14:12:39 -0600 Subject: [PATCH] Update/conditionally hide connection banner (#37707) * Add mechanism to track previously working plugins * Update project version * Rework how and when list is updated * Update array update on my jetpack and get only array values for the array * Remove new action * Link connection banner to broken modules data * Separate broken modules into site and user connection issues * Fix a few issues with determining user vs site connection * changelog * Show connection banner as info conditionally * Add constants for statuses * Show errors before info * Add additional tracking fields to notice if red bubble slug has additional info * Change how additional tracks args are added * Add all_statuses variable * Early return red bubble connection slug if possible --- .../components/my-jetpack-screen/index.jsx | 5 +- .../my-jetpack/_inc/context/notices/types.ts | 20 ++-- ...duct-slugs-that-require-user-connection.ts | 2 +- .../use-bad-install-notice.ts | 3 +- .../use-connection-errors-notice.tsx | 3 +- .../use-site-connection-notice.tsx | 32 +++--- ...ate-conditionally-render-connection-banner | 4 + projects/packages/my-jetpack/global.d.ts | 7 +- .../my-jetpack/src/class-initializer.php | 97 +++++++++++++------ .../my-jetpack/src/class-products.php | 74 +++++++++++++- .../src/products/class-module-product.php | 4 +- .../my-jetpack/src/products/class-product.php | 34 +++---- .../my-jetpack/src/products/class-stats.php | 5 +- 13 files changed, 213 insertions(+), 77 deletions(-) create mode 100644 projects/packages/my-jetpack/changelog/update-conditionally-render-connection-banner diff --git a/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/index.jsx b/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/index.jsx index 02e44da80d94b..b152060794a17 100644 --- a/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/index.jsx +++ b/projects/packages/my-jetpack/_inc/components/my-jetpack-screen/index.jsx @@ -46,10 +46,13 @@ const GlobalNotice = ( { message, title, options } ) => { const { recordEvent } = useAnalytics(); useEffect( () => { + const tracksArgs = options?.tracksArgs || {}; + recordEvent( 'jetpack_myjetpack_global_notice_view', { noticeId: options.id, + ...tracksArgs, } ); - }, [ options.id, recordEvent ] ); + }, [ options.id, recordEvent, options?.tracksArgs ] ); const [ isBiggerThanMedium ] = useBreakpointMatch( [ 'md' ], [ '>' ] ); diff --git a/projects/packages/my-jetpack/_inc/context/notices/types.ts b/projects/packages/my-jetpack/_inc/context/notices/types.ts index 55128dff2febc..a357ac6f6b352 100644 --- a/projects/packages/my-jetpack/_inc/context/notices/types.ts +++ b/projects/packages/my-jetpack/_inc/context/notices/types.ts @@ -10,14 +10,18 @@ export type NoticeButtonAction = NoticeAction & { export type Notice = { message: string | ReactNode; title?: string; - options: { - id?: string; - level: string; - actions?: NoticeButtonAction[]; - priority: number; - hideCloseButton?: boolean; - onClose?: () => void; - }; + options: NoticeOptions; +}; + +export type NoticeOptions = { + id?: string; + level: 'error' | 'warning' | 'success' | 'info'; + actions?: NoticeButtonAction[]; + priority: number; + hideCloseButton?: boolean; + onClose?: () => void; + isRedBubble?: boolean; + tracksArgs?: Record< string, unknown >; }; export type NoticeContextType< T = Notice > = { diff --git a/projects/packages/my-jetpack/_inc/data/utils/get-product-slugs-that-require-user-connection.ts b/projects/packages/my-jetpack/_inc/data/utils/get-product-slugs-that-require-user-connection.ts index 337d95935894a..0465ad98dfa6a 100644 --- a/projects/packages/my-jetpack/_inc/data/utils/get-product-slugs-that-require-user-connection.ts +++ b/projects/packages/my-jetpack/_inc/data/utils/get-product-slugs-that-require-user-connection.ts @@ -8,7 +8,7 @@ const getProductSlugsThatRequireUserConnection = ( products: { .filter( ( { requiresUserConnection, status } ) => requiresUserConnection && - ( status === PRODUCT_STATUSES.ACTIVE || status === PRODUCT_STATUSES.ERROR ) + ( status === PRODUCT_STATUSES.ACTIVE || PRODUCT_STATUSES.USER_CONNECTION_ERROR ) ) .map( ( { name } ) => name ); diff --git a/projects/packages/my-jetpack/_inc/hooks/use-notification-watcher/use-bad-install-notice.ts b/projects/packages/my-jetpack/_inc/hooks/use-notification-watcher/use-bad-install-notice.ts index 69fdc76b9c558..f1e99d6d70cdb 100644 --- a/projects/packages/my-jetpack/_inc/hooks/use-notification-watcher/use-bad-install-notice.ts +++ b/projects/packages/my-jetpack/_inc/hooks/use-notification-watcher/use-bad-install-notice.ts @@ -3,6 +3,7 @@ import { useContext, useEffect } from 'react'; import { NOTICE_PRIORITY_MEDIUM } from '../../context/constants'; import { NoticeContext } from '../../context/notices/noticeContext'; import useAnalytics from '../use-analytics'; +import type { NoticeOptions } from '../../context/notices/types'; type RedBubbleAlerts = Window[ 'myJetpackInitialState' ][ 'redBubbleAlerts' ]; @@ -40,7 +41,7 @@ const useBadInstallNotice = ( redBubbleAlerts: RedBubbleAlerts ) => { } ); }; - const noticeOptions = { + const noticeOptions: NoticeOptions = { id: 'bad-installation-notice', level: 'error', actions: [ diff --git a/projects/packages/my-jetpack/_inc/hooks/use-notification-watcher/use-connection-errors-notice.tsx b/projects/packages/my-jetpack/_inc/hooks/use-notification-watcher/use-connection-errors-notice.tsx index 4b3b09225c8d6..fc61d15f38b13 100644 --- a/projects/packages/my-jetpack/_inc/hooks/use-notification-watcher/use-connection-errors-notice.tsx +++ b/projects/packages/my-jetpack/_inc/hooks/use-notification-watcher/use-connection-errors-notice.tsx @@ -5,6 +5,7 @@ import { useContext, useEffect } from 'react'; import { NOTICE_PRIORITY_HIGH } from '../../context/constants'; import { NoticeContext } from '../../context/notices/noticeContext'; import useAnalytics from '../use-analytics'; +import type { NoticeOptions } from '../../context/notices/types'; const useConnectionErrorsNotice = () => { const { setNotice, resetNotice } = useContext( NoticeContext ); @@ -48,7 +49,7 @@ const useConnectionErrorsNotice = () => { const loadingButtonLabel = __( 'Reconnecting Jetpackā€¦', 'jetpack-my-jetpack' ); const restoreButtonLabel = __( 'Restore Connection', 'jetpack-my-jetpack' ); - const noticeOptions = { + const noticeOptions: NoticeOptions = { id: 'connection-error-notice', level: 'error', actions: [ diff --git a/projects/packages/my-jetpack/_inc/hooks/use-notification-watcher/use-site-connection-notice.tsx b/projects/packages/my-jetpack/_inc/hooks/use-notification-watcher/use-site-connection-notice.tsx index a55953defea74..99163c80c0885 100644 --- a/projects/packages/my-jetpack/_inc/hooks/use-notification-watcher/use-site-connection-notice.tsx +++ b/projects/packages/my-jetpack/_inc/hooks/use-notification-watcher/use-site-connection-notice.tsx @@ -9,8 +9,8 @@ import { useAllProducts } from '../../data/products/use-product'; import { getMyJetpackWindowRestState } from '../../data/utils/get-my-jetpack-window-state'; import getProductSlugsThatRequireUserConnection from '../../data/utils/get-product-slugs-that-require-user-connection'; import useAnalytics from '../use-analytics'; -import useMyJetpackConnection from '../use-my-jetpack-connection'; import useMyJetpackNavigate from '../use-my-jetpack-navigate'; +import type { NoticeOptions } from '../../context/notices/types'; type RedBubbleAlerts = Window[ 'myJetpackInitialState' ][ 'redBubbleAlerts' ]; @@ -18,29 +18,27 @@ const useSiteConnectionNotice = ( redBubbleAlerts: RedBubbleAlerts ) => { const { recordEvent } = useAnalytics(); const { setNotice, resetNotice } = useContext( NoticeContext ); const { apiRoot, apiNonce } = getMyJetpackWindowRestState(); - const { isRegistered, isUserConnected, hasConnectedOwner } = useMyJetpackConnection(); const { siteIsRegistering, handleRegisterSite } = useConnection( { skipUserConnection: true, apiRoot, apiNonce, from: 'my-jetpack', + redirectUri: null, + autoTrigger: false, } ); const products = useAllProducts(); const navToConnection = useMyJetpackNavigate( MyJetpackRoutes.Connection ); + const redBubbleSlug = 'missing-connection'; + const connectionError = redBubbleAlerts[ redBubbleSlug ]; useEffect( () => { - if ( ! Object.keys( redBubbleAlerts ).includes( 'missing-site-connection' ) ) { + if ( ! connectionError ) { return; } const productSlugsThatRequireUserConnection = getProductSlugsThatRequireUserConnection( products ); - const requiresUserConnection = - ! hasConnectedOwner && ! isUserConnected && productSlugsThatRequireUserConnection.length > 0; - - if ( ! requiresUserConnection && isRegistered ) { - return; - } + const requiresUserConnection = connectionError.type === 'user'; const onActionButtonClick = () => { if ( requiresUserConnection ) { @@ -62,6 +60,8 @@ const useSiteConnectionNotice = ( redBubbleAlerts: RedBubbleAlerts ) => { onClose: resetNotice, }, } ); + delete redBubbleAlerts[ redBubbleSlug ]; + window.myJetpackInitialState.redBubbleAlerts = redBubbleAlerts; } ); }; @@ -95,9 +95,9 @@ const useSiteConnectionNotice = ( redBubbleAlerts: RedBubbleAlerts ) => { title: __( 'Missing site connection', 'jetpack-my-jetpack' ), }; - const noticeOptions = { - id: requiresUserConnection ? 'user-connection-notice' : 'site-connection-notice', - level: 'info', + const noticeOptions: NoticeOptions = { + id: redBubbleSlug, + level: connectionError.is_error ? 'error' : 'info', actions: [ { label: requiresUserConnection @@ -112,6 +112,10 @@ const useSiteConnectionNotice = ( redBubbleAlerts: RedBubbleAlerts ) => { // If this notice gets into a loading state, we want to show it above the rest priority: NOTICE_PRIORITY_HIGH + ( siteIsRegistering ? 1 : 0 ), isRedBubble: true, + tracksArgs: { + type: connectionError.type, + isError: connectionError.is_error, + }, }; const messageContent = requiresUserConnection ? ( @@ -130,9 +134,6 @@ const useSiteConnectionNotice = ( redBubbleAlerts: RedBubbleAlerts ) => { } ); }, [ handleRegisterSite, - hasConnectedOwner, - isRegistered, - isUserConnected, navToConnection, products, recordEvent, @@ -140,6 +141,7 @@ const useSiteConnectionNotice = ( redBubbleAlerts: RedBubbleAlerts ) => { resetNotice, setNotice, siteIsRegistering, + connectionError, ] ); }; diff --git a/projects/packages/my-jetpack/changelog/update-conditionally-render-connection-banner b/projects/packages/my-jetpack/changelog/update-conditionally-render-connection-banner new file mode 100644 index 0000000000000..502d7e52f9d2b --- /dev/null +++ b/projects/packages/my-jetpack/changelog/update-conditionally-render-connection-banner @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Conditionally show connection banner as error or info diff --git a/projects/packages/my-jetpack/global.d.ts b/projects/packages/my-jetpack/global.d.ts index f5dece035fb67..33ac348be2fae 100644 --- a/projects/packages/my-jetpack/global.d.ts +++ b/projects/packages/my-jetpack/global.d.ts @@ -43,6 +43,8 @@ interface Window { videoPressStats: boolean; }; lifecycleStats: { + historicallyActiveModules: Array< string >; + brokenModules: Array< string >; isSiteConnected: boolean; isUserConnected: boolean; jetpackPlugins: Array< string >; @@ -195,7 +197,10 @@ interface Window { } >; }; redBubbleAlerts: { - 'missing-site-connection'?: null; + 'missing-connection'?: { + type: string; + is_error: boolean; + }; 'welcome-banner-active'?: null; [ key: `${ string }-bad-installation` ]: { data: { diff --git a/projects/packages/my-jetpack/src/class-initializer.php b/projects/packages/my-jetpack/src/class-initializer.php index ef1ad84bca23d..e94955e353c28 100644 --- a/projects/packages/my-jetpack/src/class-initializer.php +++ b/projects/packages/my-jetpack/src/class-initializer.php @@ -59,7 +59,7 @@ class Initializer { const UPDATE_HISTORICALLY_ACTIVE_JETPACK_MODULES_KEY = 'update-historically-active-jetpack-modules'; - const MISSING_SITE_CONNECTION_NOTIFICATION_KEY = 'missing-site-connection'; + const MISSING_CONNECTION_NOTIFICATION_KEY = 'missing-connection'; /** * Holds info/data about the site (from the /sites/%d endpoint) @@ -238,6 +238,7 @@ public static function enqueue_scripts() { 'lifecycleStats' => array( 'jetpackPlugins' => self::get_installed_jetpack_plugins(), 'historicallyActiveModules' => \Jetpack_Options::get_option( 'historically_active_modules', array() ), + 'brokenModules' => self::check_for_broken_modules(), 'isSiteConnected' => $connection->is_connected(), 'isUserConnected' => $connection->is_user_connected(), 'purchases' => self::get_purchases(), @@ -538,38 +539,19 @@ public static function setup_historically_active_jetpack_modules_sync() { public static function update_historically_active_jetpack_modules() { $historically_active_modules = \Jetpack_Options::get_option( 'historically_active_modules', array() ); $products = Products::get_products(); - $active_module_statuses = array( - 'active', - 'can_upgrade', - ); - $broken_module_statuses = array( - 'site_connection_error', - 'user_connection_error', - ); - // This is defined as the statuses in which the user willingly has the module disabled whether it be by - // default, uninstalling the plugin, disabling the module, or not renewing their plan. - $disabled_module_statuses = array( - 'inactive', - 'module_disabled', - 'plugin_absent', - 'plugin_absent_with_plan', - 'needs_purchase', - 'needs_purchase_or_free', - 'needs_first_site_connection', - ); foreach ( $products as $product ) { $status = $product['status']; $product_slug = $product['slug']; // We want to leave modules in the array if they've been active in the past // and were not manually disabled by the user. - if ( in_array( $status, $broken_module_statuses, true ) ) { + if ( in_array( $status, Products::$broken_module_statuses, true ) ) { continue; } // If the module is active and not already in the array, add it if ( - in_array( $status, $active_module_statuses, true ) && + in_array( $status, Products::$active_module_statuses, true ) && ! in_array( $product_slug, $historically_active_modules, true ) ) { $historically_active_modules[] = $product_slug; @@ -577,7 +559,7 @@ public static function update_historically_active_jetpack_modules() { // If the module has been disabled due to a manual user action, // or because of a missing plan error, remove it from the array - if ( in_array( $status, $disabled_module_statuses, true ) ) { + if ( in_array( $status, Products::$disabled_module_statuses, true ) ) { $historically_active_modules = array_values( array_diff( $historically_active_modules, array( $product_slug ) ) ); } } @@ -668,7 +650,7 @@ public static function dismiss_welcome_banner() { /** * Returns true if the site has file write access to the plugins folder, false otherwise. * - * @return bool + * @return string **/ public static function has_file_system_write_access() { @@ -756,6 +738,34 @@ public static function get_red_bubble_alerts() { return $red_bubble_alerts; } + /** + * Check for features broken by a disconnected user or site + * + * @return array + */ + public static function check_for_broken_modules() { + $broken_modules = array( + 'needs_site_connection' => array(), + 'needs_user_connection' => array(), + ); + $products = Products::get_products(); + $historically_active_modules = \Jetpack_Options::get_option( 'historically_active_modules', array() ); + + foreach ( $historically_active_modules as $module ) { + $product = $products[ $module ]; + + // If the site or user is disconnected, and the product requires a user connection + // mark the product as a broken module needing user connection + if ( in_array( $product['status'], Products::$broken_module_statuses, true ) && $product['requires_user_connection'] ) { + $broken_modules['needs_user_connection'][] = $module; + } elseif ( $product['status'] === Products::STATUS_SITE_CONNECTION_ERROR ) { + $broken_modules['needs_site_connection'][] = $module; + } + } + + return $broken_modules; + } + /** * Add relevant red bubble notifications * @@ -768,7 +778,7 @@ public static function add_red_bubble_alerts( array $red_bubble_slugs ) { $red_bubble_slugs['welcome-banner-active'] = null; return $red_bubble_slugs; } else { - return self::alert_if_missing_site_connection( $red_bubble_slugs ); + return self::alert_if_missing_connection( $red_bubble_slugs ); } } @@ -778,9 +788,42 @@ public static function add_red_bubble_alerts( array $red_bubble_slugs ) { * @param array $red_bubble_slugs - slugs that describe the reasons the red bubble is showing. * @return array */ - public static function alert_if_missing_site_connection( array $red_bubble_slugs ) { + public static function alert_if_missing_connection( array $red_bubble_slugs ) { + $broken_modules = self::check_for_broken_modules(); + + if ( ! empty( $broken_modules['needs_user_connection'] ) ) { + $red_bubble_slugs[ self::MISSING_CONNECTION_NOTIFICATION_KEY ] = array( + 'type' => 'user', + 'is_error' => true, + ); + return $red_bubble_slugs; + } + + if ( ! empty( $broken_modules['needs_site_connection'] ) ) { + $red_bubble_slugs[ self::MISSING_CONNECTION_NOTIFICATION_KEY ] = array( + 'type' => 'site', + 'is_error' => true, + ); + return $red_bubble_slugs; + } + + if ( + ! ( new Connection_Manager() )->is_user_connected() && + ! ( new Connection_Manager() )->has_connected_owner() + ) { + $red_bubble_slugs[ self::MISSING_CONNECTION_NOTIFICATION_KEY ] = array( + 'type' => 'user', + 'is_error' => false, + ); + return $red_bubble_slugs; + } + if ( ! ( new Connection_Manager() )->is_connected() ) { - $red_bubble_slugs[ self::MISSING_SITE_CONNECTION_NOTIFICATION_KEY ] = null; + $red_bubble_slugs[ self::MISSING_CONNECTION_NOTIFICATION_KEY ] = array( + 'type' => 'site', + 'is_error' => false, + ); + return $red_bubble_slugs; } return $red_bubble_slugs; diff --git a/projects/packages/my-jetpack/src/class-products.php b/projects/packages/my-jetpack/src/class-products.php index 35f798ac5f7c1..08d018d18b70d 100644 --- a/projects/packages/my-jetpack/src/class-products.php +++ b/projects/packages/my-jetpack/src/class-products.php @@ -11,6 +11,78 @@ * A class for everything related to product handling in My Jetpack */ class Products { + /** + * Constants for the status of a product on a site + * + * @var string + */ + const STATUS_SITE_CONNECTION_ERROR = 'site_connection_error'; + const STATUS_USER_CONNECTION_ERROR = 'user_connection_error'; + const STATUS_ACTIVE = 'active'; + const STATUS_CAN_UPGRADE = 'can_upgrade'; + const STATUS_INACTIVE = 'inactive'; + const STATUS_MODULE_DISABLED = 'module_disabled'; + const STATUS_PLUGIN_ABSENT = 'plugin_absent'; + const STATUS_PLUGIN_ABSENT_WITH_PLAN = 'plugin_absent_with_plan'; + const STATUS_NEEDS_PURCHASE = 'needs_purchase'; + const STATUS_NEEDS_PURCHASE_OR_FREE = 'needs_purchase_or_free'; + const STATUS_NEEDS_FIRST_SITE_CONNECTION = 'needs_first_site_connection'; + + /** + * List of statuses that display the module as disabled + * This is defined as the statuses in which the user willingly has the module disabled whether it be by + * default, uninstalling the plugin, disabling the module, or not renewing their plan. + * + * @var array + */ + public static $disabled_module_statuses = array( + self::STATUS_INACTIVE, + self::STATUS_MODULE_DISABLED, + self::STATUS_PLUGIN_ABSENT, + self::STATUS_PLUGIN_ABSENT_WITH_PLAN, + self::STATUS_NEEDS_PURCHASE, + self::STATUS_NEEDS_PURCHASE_OR_FREE, + self::STATUS_NEEDS_FIRST_SITE_CONNECTION, + ); + + /** + * List of statuses that display the module as broken + * + * @var array + */ + public static $broken_module_statuses = array( + self::STATUS_SITE_CONNECTION_ERROR, + self::STATUS_USER_CONNECTION_ERROR, + ); + + /** + * List of statuses that display the module as active + * + * @var array + */ + public static $active_module_statuses = array( + self::STATUS_ACTIVE, + self::STATUS_CAN_UPGRADE, + ); + + /** + * List of all statuses that a product can have + * + * @var array + */ + public static $all_statuses = array( + self::STATUS_SITE_CONNECTION_ERROR, + self::STATUS_USER_CONNECTION_ERROR, + self::STATUS_ACTIVE, + self::STATUS_CAN_UPGRADE, + self::STATUS_INACTIVE, + self::STATUS_MODULE_DISABLED, + self::STATUS_PLUGIN_ABSENT, + self::STATUS_PLUGIN_ABSENT_WITH_PLAN, + self::STATUS_NEEDS_PURCHASE, + self::STATUS_NEEDS_PURCHASE_OR_FREE, + self::STATUS_NEEDS_FIRST_SITE_CONNECTION, + ); /** * Get the list of Products classes @@ -156,7 +228,7 @@ public static function get_product_data_schema() { 'status' => array( 'title' => 'The product status', 'type' => 'string', - 'enum' => array( 'active', 'inactive', 'plugin_absent', 'needs_purchase', 'needs_purchase_or_free', 'needs_first_site_connection', 'user_connection_error', 'site_connection_error' ), + 'enum' => self::$all_statuses, ), 'class' => array( 'title' => 'The product class handler', diff --git a/projects/packages/my-jetpack/src/products/class-module-product.php b/projects/packages/my-jetpack/src/products/class-module-product.php index 37f9860119f87..5472cfec02e26 100644 --- a/projects/packages/my-jetpack/src/products/class-module-product.php +++ b/projects/packages/my-jetpack/src/products/class-module-product.php @@ -86,8 +86,8 @@ public static function is_module_active() { */ public static function get_status() { $status = parent::get_status(); - if ( 'inactive' === $status && ! static::is_module_active() ) { - $status = 'module_disabled'; + if ( Products::STATUS_INACTIVE === $status && ! static::is_module_active() ) { + $status = Products::STATUS_MODULE_DISABLED; } return $status; } diff --git a/projects/packages/my-jetpack/src/products/class-product.php b/projects/packages/my-jetpack/src/products/class-product.php index 8ac5ede299767..928ffda95f545 100644 --- a/projects/packages/my-jetpack/src/products/class-product.php +++ b/projects/packages/my-jetpack/src/products/class-product.php @@ -432,7 +432,7 @@ public static function is_upgradable_by_bundle() { * return all the products it contains. * Empty array by default. * - * @return Array Product slugs + * @return array Product slugs */ public static function get_supported_products() { return array(); @@ -445,48 +445,48 @@ public static function get_supported_products() { */ public static function get_status() { if ( ! static::is_plugin_installed() ) { - $status = 'plugin_absent'; + $status = Products::STATUS_PLUGIN_ABSENT; if ( static::has_paid_plan_for_product() ) { - $status = 'plugin_absent_with_plan'; + $status = Products::STATUS_PLUGIN_ABSENT_WITH_PLAN; } } elseif ( static::is_active() ) { - $status = 'active'; + $status = Products::STATUS_ACTIVE; // We only consider missing site & user connection an error when the Product is active. if ( static::$requires_site_connection && ! ( new Connection_Manager() )->is_connected() ) { // Site has never been connected before - if ( ! \Jetpack_Options::get_option( 'id' ) ) { - $status = 'needs_first_site_connection'; + if ( ! Jetpack_Options::get_option( 'id' ) ) { + $status = Products::STATUS_NEEDS_FIRST_SITE_CONNECTION; } else { - $status = 'site_connection_error'; + $status = Products::STATUS_SITE_CONNECTION_ERROR; } } elseif ( static::$requires_user_connection && ! ( new Connection_Manager() )->has_connected_owner() ) { - $status = 'user_connection_error'; + $status = Products::STATUS_USER_CONNECTION_ERROR; } elseif ( static::is_upgradable() ) { - $status = 'can_upgrade'; + $status = Products::STATUS_CAN_UPGRADE; } // Check specifically for inactive modules, which will prevent a product from being active } elseif ( static::$module_name && ! static::is_module_active() ) { - $status = 'module_disabled'; + $status = Products::STATUS_MODULE_DISABLED; // If there is not a plan associated with the disabled module, encourage a plan first // Getting a plan set up should help resolve any connection issues // However if the standalone plugin for this product is active, then we will defer to showing errors that prevent the module from being active // This is because if a standalone plugin is installed, we expect the product to not show as "inactive" on My Jetpack if ( static::$requires_plan || ( ! static::has_any_plan_for_product() && static::$has_standalone_plugin && ! self::is_plugin_active() ) ) { - $status = static::$has_free_offering ? 'needs_purchase_or_free' : 'needs_purchase'; + $status = static::$has_free_offering ? Products::STATUS_NEEDS_PURCHASE_OR_FREE : Products::STATUS_NEEDS_PURCHASE; } elseif ( static::$requires_site_connection && ! ( new Connection_Manager() )->is_connected() ) { // Site has never been connected before - if ( ! \Jetpack_Options::get_option( 'id' ) ) { - $status = 'needs_first_site_connection'; + if ( ! Jetpack_Options::get_option( 'id' ) ) { + $status = Products::STATUS_NEEDS_FIRST_SITE_CONNECTION; } else { - $status = 'site_connection_error'; + $status = Products::STATUS_SITE_CONNECTION_ERROR; } } elseif ( static::$requires_user_connection && ! ( new Connection_Manager() )->has_connected_owner() ) { - $status = 'user_connection_error'; + $status = Products::STATUS_USER_CONNECTION_ERROR; } } elseif ( ! static::has_any_plan_for_product() ) { - $status = static::$has_free_offering ? 'needs_purchase_or_free' : 'needs_purchase'; + $status = static::$has_free_offering ? Products::STATUS_NEEDS_PURCHASE_OR_FREE : Products::STATUS_NEEDS_PURCHASE; } else { - $status = 'inactive'; + $status = Products::STATUS_INACTIVE; } return $status; } diff --git a/projects/packages/my-jetpack/src/products/class-stats.php b/projects/packages/my-jetpack/src/products/class-stats.php index 6960c7e73bb49..04d42cfc1f8da 100644 --- a/projects/packages/my-jetpack/src/products/class-stats.php +++ b/projects/packages/my-jetpack/src/products/class-stats.php @@ -9,6 +9,7 @@ use Automattic\Jetpack\My_Jetpack\Initializer; use Automattic\Jetpack\My_Jetpack\Module_Product; +use Automattic\Jetpack\My_jetpack\Products; use Automattic\Jetpack\My_Jetpack\Wpcom_Products; use Automattic\Jetpack\Status\Host; use Jetpack_Options; @@ -169,10 +170,10 @@ public static function get_wpcom_free_product_slug() { */ public static function get_status() { $status = parent::get_status(); - if ( 'module_disabled' === $status && ! Initializer::is_registered() ) { + if ( Products::STATUS_MODULE_DISABLED === $status && ! Initializer::is_registered() ) { // If the site has never been connected before, show the "Learn more" CTA, // that points to the add Stats product interstitial. - $status = 'needs_purchase_or_free'; + $status = Products::STATUS_NEEDS_PURCHASE_OR_FREE; } return $status; }