From 01fd8c9873e0f58543d4e38bd1be54bc7639044d Mon Sep 17 00:00:00 2001 From: Dylan Munson <65001528+CodeyGuyDylan@users.noreply.github.com> Date: Tue, 19 Nov 2024 13:04:07 -0700 Subject: [PATCH 1/2] Add/growth upsells to social and stats interstials (#40236) * Remove creator card and update checks for paid plans to include growth * Add changelog * Add growth upsell to stats and social interstitial * changelog * Remove unnecessary changes * Add changelog --- ...th-upsells-to-social-and-stats-interstials | 4 + .../components/components/icons/index.tsx | 13 ++ .../components/product-cards-section/all.ts | 1 + .../product-cards-section/index.tsx | 9 +- .../components/product-interstitial/index.jsx | 25 +-- .../my-jetpack/_inc/data/constants.ts | 1 + ...th-upsells-to-social-and-stats-interstials | 4 + projects/packages/my-jetpack/global.d.ts | 3 +- .../my-jetpack/src/class-products.php | 1 + .../my-jetpack/src/products/class-growth.php | 209 ++++++++++++++++++ .../src/products/class-security.php | 11 +- .../my-jetpack/src/products/class-social.php | 10 + .../my-jetpack/src/products/class-stats.php | 10 + 13 files changed, 271 insertions(+), 30 deletions(-) create mode 100644 projects/js-packages/components/changelog/add-growth-upsells-to-social-and-stats-interstials create mode 100644 projects/packages/my-jetpack/changelog/add-growth-upsells-to-social-and-stats-interstials create mode 100644 projects/packages/my-jetpack/src/products/class-growth.php diff --git a/projects/js-packages/components/changelog/add-growth-upsells-to-social-and-stats-interstials b/projects/js-packages/components/changelog/add-growth-upsells-to-social-and-stats-interstials new file mode 100644 index 0000000000000..dda6e2d1a89aa --- /dev/null +++ b/projects/js-packages/components/changelog/add-growth-upsells-to-social-and-stats-interstials @@ -0,0 +1,4 @@ +Significance: patch +Type: added + +Add Stats icon diff --git a/projects/js-packages/components/components/icons/index.tsx b/projects/js-packages/components/components/icons/index.tsx index a390b8a3a3f6f..892e03dee4997 100644 --- a/projects/js-packages/components/components/icons/index.tsx +++ b/projects/js-packages/components/components/icons/index.tsx @@ -234,6 +234,18 @@ export const AiIcon: React.FC< BaseIconProps > = ( { ); }; +export const StatsIcon: React.FC< BaseIconProps > = ( { opacity = 1, size, color } ) => { + return ( + + + + ); +}; + const jetpackIcons = { 'anti-spam': AntiSpamIcon, backup: BackupIcon, @@ -249,6 +261,7 @@ const jetpackIcons = { jetpack: JetpackIcon, share: ShareIcon, ai: AiIcon, + stats: StatsIcon, }; const iconsMap = { diff --git a/projects/packages/my-jetpack/_inc/components/product-cards-section/all.ts b/projects/packages/my-jetpack/_inc/components/product-cards-section/all.ts index 10e29b7fbca76..880d6e7ea0a21 100644 --- a/projects/packages/my-jetpack/_inc/components/product-cards-section/all.ts +++ b/projects/packages/my-jetpack/_inc/components/product-cards-section/all.ts @@ -28,4 +28,5 @@ export const JetpackModuleToProductCard: { scan: null, security: null, creator: null, + growth: null, }; diff --git a/projects/packages/my-jetpack/_inc/components/product-cards-section/index.tsx b/projects/packages/my-jetpack/_inc/components/product-cards-section/index.tsx index ff10798442fc2..855ba5e234b12 100644 --- a/projects/packages/my-jetpack/_inc/components/product-cards-section/index.tsx +++ b/projects/packages/my-jetpack/_inc/components/product-cards-section/index.tsx @@ -26,7 +26,7 @@ type DisplayItemType = Record< // We don't have a card for Security or Extras, and scan is displayed as protect. // 'jetpack-ai' is the official slug for the AI module, so we also exclude 'ai'. // The backend still supports the 'ai' slug, so it is part of the JetpackModule type. - Exclude< JetpackModule, 'extras' | 'scan' | 'security' | 'ai' | 'creator' >, + Exclude< JetpackModule, 'extras' | 'scan' | 'security' | 'ai' | 'creator' | 'growth' >, FC< { admin: boolean } > >; @@ -104,7 +104,12 @@ const ProductCardsSection: FC< ProductCardsSectionProps > = ( { noticeMessage } const filterProducts = ( products: JetpackModule[] ) => { return products.filter( product => { - if ( product === 'scan' || product === 'security' || product === 'extras' ) { + if ( + product === 'scan' || + product === 'security' || + product === 'growth' || + product === 'extras' + ) { return false; } return true; diff --git a/projects/packages/my-jetpack/_inc/components/product-interstitial/index.jsx b/projects/packages/my-jetpack/_inc/components/product-interstitial/index.jsx index 60cd848f1f817..a2da42c2af781 100644 --- a/projects/packages/my-jetpack/_inc/components/product-interstitial/index.jsx +++ b/projects/packages/my-jetpack/_inc/components/product-interstitial/index.jsx @@ -32,8 +32,6 @@ import boostImage from './boost.png'; import crmImage from './crm.png'; import extrasImage from './extras.png'; import searchImage from './search.png'; -import socialImage from './social.png'; -import statsImage from './stats.png'; import styles from './style.module.scss'; import videoPressImage from './videopress.png'; @@ -408,17 +406,7 @@ export function ScanInterstitial() { * @return {object} SocialInterstitial react component. */ export function SocialInterstitial() { - return ( - - { - - ); + return ; } /** @@ -462,15 +450,8 @@ export function StatsInterstitial() { directCheckout={ true } installsPlugin={ true } ctaButtonLabel={ __( 'Get Stats', 'jetpack-my-jetpack' ) } - > - { - + bundle="growth" + /> ); } diff --git a/projects/packages/my-jetpack/_inc/data/constants.ts b/projects/packages/my-jetpack/_inc/data/constants.ts index c11217819409d..c55a4a6b24f61 100644 --- a/projects/packages/my-jetpack/_inc/data/constants.ts +++ b/projects/packages/my-jetpack/_inc/data/constants.ts @@ -51,4 +51,5 @@ export const PRODUCT_SLUGS = { PROTECT: 'protect', VIDEOPRESS: 'videopress', STATS: 'stats', + GROWTH: 'growth', } satisfies Record< string, JetpackModule >; diff --git a/projects/packages/my-jetpack/changelog/add-growth-upsells-to-social-and-stats-interstials b/projects/packages/my-jetpack/changelog/add-growth-upsells-to-social-and-stats-interstials new file mode 100644 index 0000000000000..5d0c9263fc127 --- /dev/null +++ b/projects/packages/my-jetpack/changelog/add-growth-upsells-to-social-and-stats-interstials @@ -0,0 +1,4 @@ +Significance: patch +Type: added + +Add growth upsell to Stats and Social interstitials diff --git a/projects/packages/my-jetpack/global.d.ts b/projects/packages/my-jetpack/global.d.ts index 49d4563fabc82..ec2870487c89d 100644 --- a/projects/packages/my-jetpack/global.d.ts +++ b/projects/packages/my-jetpack/global.d.ts @@ -39,7 +39,8 @@ type JetpackModule = | 'security' | 'protect' | 'videopress' - | 'stats'; + | 'stats' + | 'growth'; type ThreatItem = { // Protect API properties (free plan) diff --git a/projects/packages/my-jetpack/src/class-products.php b/projects/packages/my-jetpack/src/class-products.php index dcd3fcc28b3cd..7d17c464804cd 100644 --- a/projects/packages/my-jetpack/src/class-products.php +++ b/projects/packages/my-jetpack/src/class-products.php @@ -120,6 +120,7 @@ public static function get_products_classes() { 'videopress' => Products\Videopress::class, 'stats' => Products\Stats::class, 'ai' => Products\Jetpack_Ai::class, + 'growth' => Products\Growth::class, ); /** diff --git a/projects/packages/my-jetpack/src/products/class-growth.php b/projects/packages/my-jetpack/src/products/class-growth.php new file mode 100644 index 0000000000000..7478574449aa0 --- /dev/null +++ b/projects/packages/my-jetpack/src/products/class-growth.php @@ -0,0 +1,209 @@ + true, + 'wpcom_product_slug' => $product_slug, + ), + Wpcom_Products::get_product_pricing( $product_slug ) + ); + } + + /** + * Get the WPCOM product slug used to make the purchase + * + * @return string + */ + public static function get_wpcom_product_slug() { + return 'jetpack_growth_yearly'; + } + + /** + * Checks whether the Jetpack module is active + * + * This is a bundle and not a product. We should not use this information for anything + * + * @return bool + */ + public static function is_module_active() { + return false; + } + + /** + * Activates the product by installing and activating its plugin + * + * @param WP_Error|bool $current_result Is the result of the top level activation actions. You probably won't do anything if it is an WP_Error. + * @return bool|\WP_Error + */ + public static function do_product_specific_activation( $current_result ) { + $product_activation = parent::do_product_specific_activation( $current_result ); + + // A bundle is not a module. There's nothing in the plugin to be activated, so it's ok to fail to activate the module. + if ( is_wp_error( $product_activation ) && 'module_activation_failed' === $product_activation->get_error_code() ) { + return $product_activation; + } + + // At this point, Jetpack plugin is installed. Let's activate each individual product. + $activation = Social::activate(); + if ( is_wp_error( $activation ) ) { + return $activation; + } + + $activation = Stats::activate(); + if ( is_wp_error( $activation ) ) { + return $activation; + } + + return $activation; + } + + /** + * Checks whether the Product is active + * + * Growth is a bundle and not a module. Activation takes place on WPCOM. So lets consider it active if jetpack is active and has the plan. + * + * @return bool + */ + public static function is_active() { + return static::is_jetpack_plugin_active() && static::has_required_plan(); + } + + /** + * Checks whether the current plan (or purchase) of the site already supports the product + * + * @return bool + */ + public static function has_required_plan() { + $purchases_data = Wpcom_Products::get_site_current_purchases(); + if ( is_wp_error( $purchases_data ) ) { + return false; + } + if ( is_array( $purchases_data ) && ! empty( $purchases_data ) ) { + foreach ( $purchases_data as $purchase ) { + if ( + str_starts_with( $purchase->product_slug, 'jetpack_growth' ) || + str_starts_with( $purchase->product_slug, 'jetpack_complete' ) + ) { + return true; + } + } + } + return false; + } + + /** + * Checks whether the product is a bundle + * + * @return bool + */ + public static function is_bundle_product() { + return true; + } + + /** + * Returns all products it contains. + * + * @return array Product slugs + */ + public static function get_supported_products() { + return array( 'social', 'stats' ); + } + + /** + * Get the URL where the user manages the product + * + * @return string + */ + public static function get_manage_url() { + return ''; + } +} diff --git a/projects/packages/my-jetpack/src/products/class-security.php b/projects/packages/my-jetpack/src/products/class-security.php index 866899cb81223..7e7005ea9d034 100644 --- a/projects/packages/my-jetpack/src/products/class-security.php +++ b/projects/packages/my-jetpack/src/products/class-security.php @@ -69,7 +69,7 @@ public static function get_long_description() { /** * Get the internationalized features list * - * @return array Boost features list + * @return array Security features list */ public static function get_features() { return array( @@ -81,17 +81,18 @@ public static function get_features() { } /** - * Get the product princing details + * Get the product pricing details * * @return array Pricing details */ public static function get_pricing_for_ui() { + $product_slug = static::get_wpcom_product_slug(); return array_merge( array( 'available' => true, - 'wpcom_product_slug' => static::get_wpcom_product_slug(), + 'wpcom_product_slug' => $product_slug, ), - Wpcom_Products::get_product_pricing( static::get_wpcom_product_slug() ) + Wpcom_Products::get_product_pricing( $product_slug ) ); } @@ -195,7 +196,7 @@ public static function is_bundle_product() { /** * Return all the products it contains. * - * @return Array Product slugs + * @return array Product slugs */ public static function get_supported_products() { return array( 'backup', 'scan', 'anti-spam' ); diff --git a/projects/packages/my-jetpack/src/products/class-social.php b/projects/packages/my-jetpack/src/products/class-social.php index 317eeaf303a01..ae1d3ee6f76c0 100644 --- a/projects/packages/my-jetpack/src/products/class-social.php +++ b/projects/packages/my-jetpack/src/products/class-social.php @@ -197,4 +197,14 @@ public static function get_manage_url() { return admin_url( 'admin.php?page=jetpack#/settings?term=publicize' ); } + + /** + * Return product bundles list + * that supports the product. + * + * @return boolean|array Products bundle list. + */ + public static function is_upgradable_by_bundle() { + return array( 'growth' ); + } } diff --git a/projects/packages/my-jetpack/src/products/class-stats.php b/projects/packages/my-jetpack/src/products/class-stats.php index fa9aaf61f5561..c361bd6737f39 100644 --- a/projects/packages/my-jetpack/src/products/class-stats.php +++ b/projects/packages/my-jetpack/src/products/class-stats.php @@ -314,4 +314,14 @@ public static function get_purchase_url() { public static function get_manage_url() { return admin_url( 'admin.php?page=stats' ); } + + /** + * Return product bundles list + * that supports the product. + * + * @return boolean|array Products bundle list. + */ + public static function is_upgradable_by_bundle() { + return array( 'growth' ); + } } From d438fb8556858eff768b2a10a7394bcc3c8b1e67 Mon Sep 17 00:00:00 2001 From: Calypso Bot Date: Tue, 19 Nov 2024 21:39:53 +0100 Subject: [PATCH 2/2] Update dependency automattic/custom-fonts to v3.0.6 (#40261) Co-authored-by: Renovate Bot --- .../renovate-automattic-custom-fonts-3.x-lockfile | 4 ++++ projects/plugins/wpcomsh/composer.lock | 10 +++++----- 2 files changed, 9 insertions(+), 5 deletions(-) create mode 100644 projects/plugins/wpcomsh/changelog/renovate-automattic-custom-fonts-3.x-lockfile diff --git a/projects/plugins/wpcomsh/changelog/renovate-automattic-custom-fonts-3.x-lockfile b/projects/plugins/wpcomsh/changelog/renovate-automattic-custom-fonts-3.x-lockfile new file mode 100644 index 0000000000000..c47cb18e82997 --- /dev/null +++ b/projects/plugins/wpcomsh/changelog/renovate-automattic-custom-fonts-3.x-lockfile @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Updated package dependencies. diff --git a/projects/plugins/wpcomsh/composer.lock b/projects/plugins/wpcomsh/composer.lock index 901e1573a5401..0803e22af3189 100644 --- a/projects/plugins/wpcomsh/composer.lock +++ b/projects/plugins/wpcomsh/composer.lock @@ -28,16 +28,16 @@ }, { "name": "automattic/custom-fonts", - "version": "v3.0.5", + "version": "v3.0.6", "source": { "type": "git", "url": "https://github.com/Automattic/custom-fonts.git", - "reference": "e9236c34a6ecbee3bb9d2bebe698f086dd339258" + "reference": "63d0a9251a252b74ab0862ac00f4d4d4c1d6b320" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Automattic/custom-fonts/zipball/e9236c34a6ecbee3bb9d2bebe698f086dd339258", - "reference": "e9236c34a6ecbee3bb9d2bebe698f086dd339258", + "url": "https://api.github.com/repos/Automattic/custom-fonts/zipball/63d0a9251a252b74ab0862ac00f4d4d4c1d6b320", + "reference": "63d0a9251a252b74ab0862ac00f4d4d4c1d6b320", "shasum": "" }, "require-dev": { @@ -49,7 +49,7 @@ "GPL-2.0-or-later" ], "description": "A provider-agnostic WordPress plugin for changing theme fonts.", - "time": "2024-06-26T18:47:13+00:00" + "time": "2024-11-19T20:05:23+00:00" }, { "name": "automattic/custom-fonts-typekit",