diff options
Diffstat (limited to 'plugins/jetpack/jetpack_vendor/automattic/jetpack-partner/src/class-partner-coupon.php')
-rw-r--r-- | plugins/jetpack/jetpack_vendor/automattic/jetpack-partner/src/class-partner-coupon.php | 182 |
1 files changed, 161 insertions, 21 deletions
diff --git a/plugins/jetpack/jetpack_vendor/automattic/jetpack-partner/src/class-partner-coupon.php b/plugins/jetpack/jetpack_vendor/automattic/jetpack-partner/src/class-partner-coupon.php index a1619a2b..c664e9e8 100644 --- a/plugins/jetpack/jetpack_vendor/automattic/jetpack-partner/src/class-partner-coupon.php +++ b/plugins/jetpack/jetpack_vendor/automattic/jetpack-partner/src/class-partner-coupon.php @@ -7,6 +7,7 @@ namespace Automattic\Jetpack; +use Automattic\Jetpack\Connection\Client as Connection_Client; use Automattic\Jetpack\Connection\Manager as Connection_Manager; use Jetpack_Options; @@ -20,7 +21,7 @@ if ( ! defined( 'ABSPATH' ) ) { /** * Class Jetpack_Partner_Coupon * - * @since $$next_version$$ + * @since 1.6.0 */ class Partner_Coupon { @@ -39,6 +40,20 @@ class Partner_Coupon { public static $added_option = 'partner_coupon_added'; /** + * Name of "last availability check" transient. + * + * @var string + */ + public static $last_check_transient = 'jetpack_partner_coupon_last_check'; + + /** + * Callable that executes a blog-authenticated request. + * + * @var callable + */ + protected $request_as_blog; + + /** * Jetpack_Partner_Coupon * * @var Partner_Coupon|null @@ -51,7 +66,14 @@ class Partner_Coupon { * @var array */ private static $supported_partners = array( - 'IONOS' => 'IONOS', + 'IONOS' => array( + 'name' => 'IONOS', + 'logo' => array( + 'src' => '/images/ionos-logo.jpg', + 'width' => 119, + 'height' => 32, + ), + ), ); /** @@ -65,16 +87,27 @@ class Partner_Coupon { /** * Get singleton instance of class. + * + * @return Partner_Coupon */ public static function get_instance() { - if ( is_null( self::$instance ) ) { - self::$instance = new Partner_Coupon(); + if ( self::$instance === null ) { + self::$instance = new Partner_Coupon( array( Connection_Client::class, 'wpcom_json_api_request_as_blog' ) ); } return self::$instance; } /** + * Constructor. + * + * @param callable $request_as_blog Callable that executes a blog-authenticated request. + */ + public function __construct( $request_as_blog ) { + $this->request_as_blog = $request_as_blog; + } + + /** * Register hooks to catch and purge coupon. * * @param string $plugin_slug The plugin slug to differentiate between Jetpack connections. @@ -83,8 +116,6 @@ class Partner_Coupon { public static function register_coupon_admin_hooks( $plugin_slug, $redirect_location ) { $instance = self::get_instance(); - add_action( 'admin_init', array( $instance, 'purge_coupon' ) ); - // We have to use an anonymous function, so we can pass along relevant information // and not have to hardcode values for a single plugin. // This open up the opportunity for e.g. the "all-in-one" and backup plugins @@ -93,6 +124,7 @@ class Partner_Coupon { 'admin_init', function () use ( $plugin_slug, $redirect_location, $instance ) { $instance->catch_coupon( $plugin_slug, $redirect_location ); + $instance->maybe_purge_coupon( $plugin_slug ); } ); } @@ -105,7 +137,7 @@ class Partner_Coupon { */ public function catch_coupon( $plugin_slug, $redirect_location ) { // Accept and store a partner coupon if present, and redirect to Jetpack connection screen. - $partner_coupon = isset( $_GET['jetpack-partner-coupon'] ) ? sanitize_text_field( $_GET['jetpack-partner-coupon'] ) : false; // phpcs:ignore WordPress.Security.NonceVerification.Recommended + $partner_coupon = isset( $_GET['jetpack-partner-coupon'] ) ? sanitize_text_field( wp_unslash( $_GET['jetpack-partner-coupon'] ) ) : false; // phpcs:ignore WordPress.Security.NonceVerification.Recommended if ( $partner_coupon ) { Jetpack_Options::update_options( array( @@ -127,27 +159,134 @@ class Partner_Coupon { /** * Purge partner coupon. * - * We automatically purge partner coupons after a certain amount of time to prevent - * us from unnecessarily promoting a product for months or years in the future. + * We try to remotely check if a coupon looks valid. We also automatically purge + * partner coupons after a certain amount of time to prevent unnecessary look-ups + * and/or promoting a product for months or years in the future due to unknown + * errors. + * + * @param string $plugin_slug The plugin slug to differentiate between Jetpack connections. + */ + public function maybe_purge_coupon( $plugin_slug ) { + // Only run coupon checks on Jetpack admin pages. + // The "admin-ui" package is responsible for registering the Jetpack admin + // page for all Jetpack plugins and has hardcoded the settings page to be + // "jetpack", so we shouldn't need to allow for dynamic/custom values. + // phpcs:ignore WordPress.Security.NonceVerification.Recommended + if ( ! isset( $_GET['page'] ) || 'jetpack' !== $_GET['page'] ) { + return; + } + + if ( ( new Status() )->is_offline_mode() ) { + return; + } + + $connection = new Connection_Manager( $plugin_slug ); + if ( ! $connection->is_connected() ) { + return; + } + + if ( $this->maybe_purge_coupon_by_added_date() ) { + return; + } + + // Limit checks to happen once a minute at most. + if ( get_transient( self::$last_check_transient ) ) { + return; + } + + set_transient( self::$last_check_transient, true, MINUTE_IN_SECONDS ); + + $this->maybe_purge_coupon_by_availability_check(); + } + + /** + * Purge coupon based on local added date. + * + * We automatically remove the coupon after a month to "self-heal" if + * something in the claim process has broken with the site. + * + * @return bool Return whether we should skip further purge checks. */ - public function purge_coupon() { + protected function maybe_purge_coupon_by_added_date() { $date = Jetpack_Options::get_option( self::$added_option, '' ); if ( empty( $date ) ) { - return; + return true; } $expire_date = strtotime( '+30 days', $date ); $today = time(); if ( $today >= $expire_date ) { - Jetpack_Options::delete_option( - array( - self::$coupon_option, - self::$added_option, - ) - ); + $this->delete_coupon_data(); + + return true; + } + + return false; + } + + /** + * Purge coupon based on availability check. + * + * @return bool Return whether we deleted coupon data. + */ + protected function maybe_purge_coupon_by_availability_check() { + $blog_id = Jetpack_Options::get_option( 'id', false ); + + if ( ! $blog_id ) { + return false; + } + + $coupon = self::get_coupon(); + + if ( ! $coupon ) { + return false; + } + + $response = call_user_func_array( + $this->request_as_blog, + array( + add_query_arg( + array( 'coupon_code' => $coupon['coupon_code'] ), + sprintf( + '/sites/%d/jetpack-partner/coupon/v1/site/coupon', + $blog_id + ) + ), + 2, + array( 'method' => 'GET' ), + null, + 'wpcom', + ) + ); + + $body = json_decode( wp_remote_retrieve_body( $response ), true ); + + if ( + 200 === wp_remote_retrieve_response_code( $response ) && + is_array( $body ) && + isset( $body['available'] ) && + false === $body['available'] + ) { + $this->delete_coupon_data(); + + return true; } + + return false; + } + + /** + * Delete all coupon data. + */ + protected function delete_coupon_data() { + Jetpack_Options::delete_option( + array( + self::$coupon_option, + self::$added_option, + ) + ); } /** @@ -208,8 +347,9 @@ class Partner_Coupon { } return array( - 'name' => $supported_partners[ $prefix ], + 'name' => $supported_partners[ $prefix ]['name'], 'prefix' => $prefix, + 'logo' => isset( $supported_partners[ $prefix ]['logo'] ) ? $supported_partners[ $prefix ]['logo'] : null, ); } @@ -227,7 +367,7 @@ class Partner_Coupon { /** * Allow for plugins to register supported products. * - * @since $$next_version$$ + * @since 1.6.0 * * @param array A list of product details. * @return array @@ -296,7 +436,7 @@ class Partner_Coupon { /** * Allow external code to add additional supported partners. * - * @since $$next_version$$ + * @since 1.6.0 * * @param array $supported_partners A list of supported partners. * @return array @@ -313,7 +453,7 @@ class Partner_Coupon { /** * Allow external code to add additional supported presets. * - * @since $$next_version$$ + * @since 1.6.0 * * @param array $supported_presets A list of supported presets. * @return array |