Skip to content

Commit

Permalink
My Jetpack: Add "Expired" & "Expires soon" statuses to product cards …
Browse files Browse the repository at this point in the history
…(#39816)

* Add expired statuses to products, WIP.

* changelog

* Update & refine logic to determine if products is expired/expiring.

* Add logic in remaining product classes for expired/expiring functionality.

* Add manage purchase/subscription url for My Jetpack products.

* Fix $status possibly null when checking expiry status.

* Add error/warning border color to expired/expiring product cards.

* Fix how paid products are determined, regarding bundles.

* Refactor/improve how we determine 'has_paid_plan_for_product()'.

* Change product card error & warning border to 1px, per feedback.

* Add option to hide expiration status & and get_renew_url function.

Committed via a GitHub action: https://github.com/Automattic/jetpack/actions/runs/12057303284

Upstream-Ref: Automattic/jetpack@8b04c77
  • Loading branch information
elliottprogrammer authored and matticbot committed Nov 27, 2024
1 parent 47827c6 commit 92987ef
Show file tree
Hide file tree
Showing 29 changed files with 658 additions and 312 deletions.
3 changes: 3 additions & 0 deletions jetpack_vendor/automattic/jetpack-my-jetpack/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

This is an alpha version! The changes listed here are not final.

### Added
- Added "Expired" & "Expires soon" statuses to My Jetpack product cards.

### Changed
- Social | Changed My Jetpack CTA for Social from "Learn more" to "Activate"

Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
<?php return array('dependencies' => array('jetpack-connection', 'jetpack-script-data', 'react', 'react-jsx-runtime', 'wp-api-fetch', 'wp-components', 'wp-compose', 'wp-data', 'wp-date', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => '5a0d80eecc6079f22654');
<?php return array('dependencies' => array('jetpack-connection', 'jetpack-script-data', 'react', 'react-jsx-runtime', 'wp-api-fetch', 'wp-components', 'wp-compose', 'wp-data', 'wp-date', 'wp-element', 'wp-i18n', 'wp-polyfill', 'wp-primitives', 'wp-url'), 'version' => '1d4381175bc946f720d9');

Large diffs are not rendered by default.

36 changes: 18 additions & 18 deletions jetpack_vendor/automattic/jetpack-my-jetpack/build/index.js

Large diffs are not rendered by default.

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions jetpack_vendor/automattic/jetpack-my-jetpack/global.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,8 @@ interface Window {
plugin_slug: string;
post_activation_url: string;
post_checkout_url?: string;
manage_paid_plan_purchase_url?: string;
renew_paid_plan_purchase_url?: string;
pricing_for_ui?: {
available: boolean;
wpcom_product_slug: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ class Products {
const STATUS_USER_CONNECTION_ERROR = 'user_connection_error';
const STATUS_ACTIVE = 'active';
const STATUS_CAN_UPGRADE = 'can_upgrade';
const STATUS_EXPIRING_SOON = 'expiring';
const STATUS_EXPIRED = 'expired';
const STATUS_INACTIVE = 'inactive';
const STATUS_MODULE_DISABLED = 'module_disabled';
const STATUS_PLUGIN_ABSENT = 'plugin_absent';
Expand Down Expand Up @@ -76,6 +78,16 @@ class Products {
self::STATUS_CAN_UPGRADE,
);

/**
* List of statuses that display the module as active
*
* @var array
*/
public static $expiring_or_expired_module_statuses = array(
self::STATUS_EXPIRING_SOON,
self::STATUS_EXPIRED,
);

/**
* List of all statuses that a product can have
*
Expand All @@ -86,6 +98,8 @@ class Products {
self::STATUS_USER_CONNECTION_ERROR,
self::STATUS_ACTIVE,
self::STATUS_CAN_UPGRADE,
self::STATUS_EXPIRING_SOON,
self::STATUS_EXPIRED,
self::STATUS_INACTIVE,
self::STATUS_MODULE_DISABLED,
self::STATUS_PLUGIN_ABSENT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

use Automattic\Jetpack\Connection\Client;
use Automattic\Jetpack\Connection\Manager as Connection_Manager;
use Automattic\Jetpack\Current_Plan;
use Automattic\Jetpack\Status\Visitor;
use Jetpack_Options;
use WP_Error;
Expand Down Expand Up @@ -349,6 +350,15 @@ public static function get_site_current_purchases() {
return $purchases;
}

/**
* Gets the site's currently active "plan" (bundle).
*
* @return array
*/
public static function get_site_current_plan() {
return Current_Plan::get();
}

/**
* Reset the request failures to retry the API requests.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ class Anti_Spam extends Product {
*/
public static $plugin_slug = 'akismet';

/**
* The feature slug that identifies the paid plan
*
* @var string
*/
public static $feature_identifying_paid_plan = 'antispam';

/**
* Whether this product requires a user connection
*
Expand Down Expand Up @@ -107,41 +114,37 @@ public static function get_features() {
}

/**
* Determine if the site has an Akismet plan by checking for an API key
* Note that some Akismet Plans are free - we're just checking for an API key and don't have the perspective of the plan attached to it here
* Get the product-slugs of the paid plans for this product.
* (Do not include bundle plans, unless it's a bundle plan itself).
*
* @return bool - whether an API key was found
* @return array
*/
public static function has_paid_plan_for_product() {
$products_with_anti_spam = array(
public static function get_paid_plan_product_slugs() {
return array(
'jetpack_anti_spam',
'jetpack_complete',
'jetpack_security',
'jetpack_personal',
'jetpack_premium',
'jetpack_business',
'jetpack_anti_spam_monthly',
'jetpack_anti_spam_bi_yearly',
);
// Check if the site has an API key for Akismet
$akismet_api_key = apply_filters( 'akismet_get_api_key', defined( 'WPCOM_API_KEY' ) ? constant( 'WPCOM_API_KEY' ) : get_option( 'wordpress_api_key' ) );
$fallback = ! empty( $akismet_api_key );
}

// Check for existing plans
$purchases_data = Wpcom_Products::get_site_current_purchases();
if ( is_wp_error( $purchases_data ) ) {
return $fallback;
/**
* Determine if the site has an Akismet plan.
*
* @return bool - whether an API key was found
*/
public static function has_paid_plan_for_product() {
if ( parent::has_paid_plan_for_product() ) {
return true;
}
// As a fallback, we're checking if the site has an API key for Akismet.
// Note that some Akismet Plans are free - we're just checking for an API key and don't have the perspective of the plan attached to it here
$akismet_api_key = apply_filters( 'akismet_get_api_key', defined( 'WPCOM_API_KEY' ) ? constant( 'WPCOM_API_KEY' ) : get_option( 'wordpress_api_key' ) );
if ( ! empty( $akismet_api_key ) ) {
return true;

if ( is_array( $purchases_data ) && ! empty( $purchases_data ) ) {
foreach ( $purchases_data as $purchase ) {
foreach ( $products_with_anti_spam as $product ) {
if ( strpos( $purchase->product_slug, $product ) !== false ) {
return true;
}
}
}
}

return $fallback;
return false;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ class Backup extends Hybrid_Product {
*/
public static $requires_plan = true;

/**
* The feature slug that identifies the paid plan
*
* @var string
*/
public static $feature_identifying_paid_plan = 'backups';

/**
* Get the product name
*
Expand Down Expand Up @@ -193,19 +200,6 @@ private static function get_state_from_wpcom() {
return $status;
}

/**
* Checks whether the current plan (or purchases) of the site already supports the product
*
* @return boolean
*/
public static function has_paid_plan_for_product() {
$rewind_data = static::get_state_from_wpcom();
if ( is_wp_error( $rewind_data ) ) {
return false;
}
return is_object( $rewind_data ) && isset( $rewind_data->state ) && 'unavailable' !== $rewind_data->state;
}

/**
* Return product bundles list
* that supports the product.
Expand Down Expand Up @@ -239,4 +233,26 @@ public static function get_manage_url() {
return Redirect::get_url( 'my-jetpack-manage-backup' );
}
}

/**
* Get the product-slugs of the paid plans for this product.
* (Do not include bundle plans, unless it's a bundle plan itself).
*
* @return array
*/
public static function get_paid_plan_product_slugs() {
return array(
'jetpack_backup_daily',
'jetpack_backup_daily_monthly',
'jetpack_backup_realtime',
'jetpack_backup_realtime_monthly',
'jetpack_backup_t1_yearly',
'jetpack_backup_t1_monthly',
'jetpack_backup_t1_bi_yearly',
'jetpack_backup_t2_yearly',
'jetpack_backup_t2_monthly',
'jetpack_backup_t0_yearly',
'jetpack_backup_t0_monthly',
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,13 @@ class Boost extends Product {
*/
public static $has_free_offering = true;

/**
* The feature slug that identifies the paid plan
*
* @var string
*/
public static $feature_identifying_paid_plan = 'cloud-critical-css';

/**
* Get the product name
*
Expand Down Expand Up @@ -341,27 +348,6 @@ public static function get_pricing_for_ui() {
);
}

/**
* Checks whether the current plan (or purchases) of the site already supports the product
*
* @return boolean
*/
public static function has_paid_plan_for_product() {
$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 ) {
// Boost is available as standalone bundle and as part of the Complete plan.
if ( strpos( $purchase->product_slug, 'jetpack_boost' ) !== false || str_starts_with( $purchase->product_slug, 'jetpack_complete' ) ) {
return true;
}
}
}
return false;
}

/**
* Get the URL where the user manages the product
*
Expand Down Expand Up @@ -392,6 +378,20 @@ public static function do_product_specific_activation( $current_result ) {
return $product_activation;
}

/**
* Get the product-slugs of the paid plans for this product.
* (Do not include bundle plans, unless it's a bundle plan itself).
*
* @return array
*/
public static function get_paid_plan_product_slugs() {
return array(
'jetpack_boost_yearly',
'jetpack_boost_monthly',
'jetpack_boost_bi_yearly',
);
}

/**
* Return product bundles list
* that supports the product.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,20 @@ public static function has_required_plan() {
return false;
}

/**
* Get the product-slugs of the paid plans for this product.
* (Do not include bundle plans, unless it's a bundle plan itself).
*
* @return array
*/
public static function get_paid_plan_product_slugs() {
return array(
'jetpack_complete',
'jetpack_complete_monthly',
'jetpack_complete_bi_yearly',
);
}

/**
* Checks whether product is a bundle.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -319,24 +319,30 @@ public static function get_wpcom_monthly_product_slug() {
}

/**
* Checks whether the current plan (or purchases) of the site already supports the product
* Get the product-slugs of the paid bundles/plans that this product/module is included in
*
* @return boolean
* @return array
*/
public static function get_paid_bundles_that_include_product() {
return array(
'jetpack_complete',
'jetpack_complete_monthly',
'jetpack_complete_bi-yearly',
);
}

/**
* Get the product-slugs of the paid plans for this product.
* (Do not include bundle plans, unless it's a bundle plan itself).
*
* @return array
*/
public static function has_paid_plan_for_product() {
$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 ) {
// Creator is available as standalone bundle and as part of the Complete plan.
if ( strpos( $purchase->product_slug, 'jetpack_creator' ) !== false || str_starts_with( $purchase->product_slug, 'jetpack_complete' ) ) {
return true;
}
}
}
return false;
public static function get_paid_plan_product_slugs() {
return array(
'jetpack_creator_yearly',
'jetpack_creator_monthly',
'jetpack_creator_bi_yearly',
);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,19 @@ public static function has_paid_plan_for_product() {
return false;
}

/**
* Get the product-slugs of the paid bundles/plans that this product/module is included in.
*
* @return array
*/
public static function get_paid_bundles_that_include_product() {
return array(
'jetpack_complete',
'jetpack_complete_monthly',
'jetpack_complete_bi_yearly',
);
}

/**
* Return product bundles list
* that supports the product.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,20 @@ public static function has_required_plan() {
return false;
}

/**
* Get the product-slugs of the paid plans for this product.
* (Do not include bundle plans, unless it's a bundle plan itself).
*
* @return array
*/
public static function get_paid_plan_product_slugs() {
return array(
'jetpack_growth_yearly',
'jetpack_growth_monthly',
'jetpack_growth_bi_yearly',
);
}

/**
* Checks whether the product is a bundle
*
Expand Down
Loading

0 comments on commit 92987ef

Please sign in to comment.