updated plugin Jetpack Protect
version 2.0.0
This commit is contained in:
@ -5,6 +5,60 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [2.2.0] - 2024-01-18
|
||||
### Added
|
||||
- Adding support for IDC when site URL is an IP address. [#34753]
|
||||
|
||||
### Changed
|
||||
- Adjust 'get_site_id()' method to return null if there's no blog ID. [#34976]
|
||||
|
||||
## [2.1.1] - 2024-01-04
|
||||
### Changed
|
||||
- Updated package dependencies. [#34815]
|
||||
|
||||
## [2.1.0] - 2023-12-03
|
||||
### Added
|
||||
- Added the welcome banner to My Jetpack. [#34384]
|
||||
- Updated XMLRPC endpoint 'jetpack.idcUrlValidation' to accept an argument specifying whether to attempt reusing existing URL secret. [#34262]
|
||||
|
||||
### Changed
|
||||
- Updated package dependencies. [#34411]
|
||||
|
||||
## [2.0.3] - 2023-11-24
|
||||
|
||||
## [2.0.2] - 2023-11-21
|
||||
### Changed
|
||||
- Replaced usage of strpos() with str_contains(). [#34137]
|
||||
|
||||
## [2.0.1] - 2023-11-21
|
||||
|
||||
## [2.0.0] - 2023-11-20
|
||||
### Added
|
||||
- Confirm blog ID and access token were saved before proceeding with connection flow. [#34136]
|
||||
|
||||
### Changed
|
||||
- Replace usage of strpos() with str_starts_with(). [#34135]
|
||||
- Updated required PHP version to >= 7.0. [#34192]
|
||||
|
||||
### Fixed
|
||||
- Ensured that partner partners are passed on during the connection process, regardless of the plugin you use to connect. [#33832]
|
||||
|
||||
## [1.60.1] - 2023-11-14
|
||||
### Changed
|
||||
- Updated package dependencies. [#34093]
|
||||
|
||||
## [1.60.0] - 2023-11-13
|
||||
### Added
|
||||
- Added a 'source' query param to the Jetpack connect URL. [#33984]
|
||||
|
||||
## [1.59.0] - 2023-11-08
|
||||
### Added
|
||||
- Added a method to check if Jetpack is ready for uninstall cleanup. [#33920]
|
||||
|
||||
## [1.58.3] - 2023-11-03
|
||||
### Fixed
|
||||
- Make sure scheme history option is an array. [#33905]
|
||||
|
||||
## [1.58.2] - 2023-10-19
|
||||
### Changed
|
||||
- Updated package dependencies. [#33687]
|
||||
@ -896,6 +950,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
- Separate the connection library into its own package.
|
||||
|
||||
[2.2.0]: https://github.com/Automattic/jetpack-connection/compare/v2.1.1...v2.2.0
|
||||
[2.1.1]: https://github.com/Automattic/jetpack-connection/compare/v2.1.0...v2.1.1
|
||||
[2.1.0]: https://github.com/Automattic/jetpack-connection/compare/v2.0.3...v2.1.0
|
||||
[2.0.3]: https://github.com/Automattic/jetpack-connection/compare/v2.0.2...v2.0.3
|
||||
[2.0.2]: https://github.com/Automattic/jetpack-connection/compare/v2.0.1...v2.0.2
|
||||
[2.0.1]: https://github.com/Automattic/jetpack-connection/compare/v2.0.0...v2.0.1
|
||||
[2.0.0]: https://github.com/Automattic/jetpack-connection/compare/v1.60.1...v2.0.0
|
||||
[1.60.1]: https://github.com/Automattic/jetpack-connection/compare/v1.60.0...v1.60.1
|
||||
[1.60.0]: https://github.com/Automattic/jetpack-connection/compare/v1.59.0...v1.60.0
|
||||
[1.59.0]: https://github.com/Automattic/jetpack-connection/compare/v1.58.3...v1.59.0
|
||||
[1.58.3]: https://github.com/Automattic/jetpack-connection/compare/v1.58.2...v1.58.3
|
||||
[1.58.2]: https://github.com/Automattic/jetpack-connection/compare/v1.58.1...v1.58.2
|
||||
[1.58.1]: https://github.com/Automattic/jetpack-connection/compare/v1.58.0...v1.58.1
|
||||
[1.58.0]: https://github.com/Automattic/jetpack-connection/compare/v1.57.5...v1.58.0
|
||||
|
@ -4,18 +4,19 @@
|
||||
"type": "jetpack-library",
|
||||
"license": "GPL-2.0-or-later",
|
||||
"require": {
|
||||
"automattic/jetpack-a8c-mc-stats": "^1.4.22",
|
||||
"automattic/jetpack-admin-ui": "^0.2.23",
|
||||
"automattic/jetpack-constants": "^1.6.23",
|
||||
"automattic/jetpack-roles": "^1.4.25",
|
||||
"automattic/jetpack-status": "^1.18.5",
|
||||
"automattic/jetpack-redirect": "^1.7.27"
|
||||
"php": ">=7.0",
|
||||
"automattic/jetpack-a8c-mc-stats": "^2.0.0",
|
||||
"automattic/jetpack-admin-ui": "^0.3.1",
|
||||
"automattic/jetpack-constants": "^2.0.0",
|
||||
"automattic/jetpack-roles": "^2.0.0",
|
||||
"automattic/jetpack-status": "^2.0.2",
|
||||
"automattic/jetpack-redirect": "^2.0.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"automattic/wordbless": "@dev",
|
||||
"yoast/phpunit-polyfills": "1.1.0",
|
||||
"brain/monkey": "2.6.1",
|
||||
"automattic/jetpack-changelogger": "^3.3.11"
|
||||
"automattic/jetpack-changelogger": "^4.0.5"
|
||||
},
|
||||
"suggest": {
|
||||
"automattic/jetpack-autoloader": "Allow for better interoperability with other plugins that use this package."
|
||||
@ -56,7 +57,7 @@
|
||||
"link-template": "https://github.com/Automattic/jetpack-connection/compare/v${old}...v${new}"
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-trunk": "1.58.x-dev"
|
||||
"dev-trunk": "2.2.x-dev"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
|
@ -1 +1 @@
|
||||
<?php return array('dependencies' => array(), 'version' => 'a96178e4d62fb695caa0');
|
||||
<?php return array('dependencies' => array(), 'version' => 'd9dbf909a3d10fb26f39');
|
||||
|
@ -1 +1 @@
|
||||
!function(){var e={775:function(e){let n;window._tkq=window._tkq||[];const t=console.error;const o={initialize:function(e,n){o.setUser(e,n),o.identifyUser()},mc:{bumpStat:function(e,n){const t=function(e,n){let t="";if("object"==typeof e)for(const n in e)t+="&x_"+encodeURIComponent(n)+"="+encodeURIComponent(e[n]);else t="&x_"+encodeURIComponent(e)+"="+encodeURIComponent(n);return t}(e,n);(new Image).src=document.location.protocol+"//pixel.wp.com/g.gif?v=wpcom-no-pv"+t+"&t="+Math.random()}},tracks:{recordEvent:function(e,n){n=n||{},0===e.indexOf("jetpack_")?window._tkq.push(["recordEvent",e,n]):t('- Event name must be prefixed by "jetpack_"')},recordPageView:function(e){o.tracks.recordEvent("jetpack_page_view",{path:e})}},setUser:function(e,t){n={ID:e,username:t}},identifyUser:function(){n&&window._tkq.push(["identifyUser",n.ID,n.username])},clearedIdentity:function(){window._tkq.push(["clearIdentity"])}};e.exports=o}},n={};var t=function t(o){var r=n[o];if(void 0!==r)return r.exports;var i=n[o]={exports:{}};return e[o](i,i.exports,t),i.exports}(775);window.analytics=t}();
|
||||
(()=>{var e={775:e=>{let n;window._tkq=window._tkq||[];const t=console.error;const o={initialize:function(e,n){o.setUser(e,n),o.identifyUser()},mc:{bumpStat:function(e,n){const t=function(e,n){let t="";if("object"==typeof e)for(const n in e)t+="&x_"+encodeURIComponent(n)+"="+encodeURIComponent(e[n]);else t="&x_"+encodeURIComponent(e)+"="+encodeURIComponent(n);return t}(e,n);(new Image).src=document.location.protocol+"//pixel.wp.com/g.gif?v=wpcom-no-pv"+t+"&t="+Math.random()}},tracks:{recordEvent:function(e,n){n=n||{},0===e.indexOf("jetpack_")?window._tkq.push(["recordEvent",e,n]):t('- Event name must be prefixed by "jetpack_"')},recordPageView:function(e){o.tracks.recordEvent("jetpack_page_view",{path:e})}},setUser:function(e,t){n={ID:e,username:t}},identifyUser:function(){n&&window._tkq.push(["identifyUser",n.ID,n.username])},clearedIdentity:function(){window._tkq.push(["clearIdentity"])}};e.exports=o}},n={};var t=function t(o){var r=n[o];if(void 0!==r)return r.exports;var i=n[o]={exports:{}};return e[o](i,i.exports,t),i.exports}(775);window.analytics=t})();
|
@ -129,6 +129,8 @@ class Jetpack_Options {
|
||||
'dismissed_backup_review_restore', // (bool) Determines if the component review request is dismissed for successful restore requests.
|
||||
'dismissed_backup_review_backups', // (bool) Determines if the component review request is dismissed for successful backup requests.
|
||||
'identity_crisis_url_secret', // (array) The IDC URL secret and its expiration date.
|
||||
'identity_crisis_ip_requester', // (array) The IDC IP address and its expiration date.
|
||||
'dismissed_welcome_banner', // (bool) Determines if the welcome banner has been dismissed or not.
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -160,7 +160,7 @@ class Jetpack_Signature {
|
||||
|
||||
$signature_details = compact( 'token', 'timestamp', 'nonce', 'body_hash', 'method', 'url' );
|
||||
|
||||
if ( 0 !== strpos( $token, "$this->token:" ) ) {
|
||||
if ( ! str_starts_with( $token, "$this->token:" ) ) {
|
||||
return new WP_Error( 'token_mismatch', 'Incorrect token', compact( 'signature_details' ) );
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ namespace Automattic\Jetpack\Connection;
|
||||
use Automattic\Jetpack\A8c_Mc_Stats;
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\Jetpack\Heartbeat;
|
||||
use Automattic\Jetpack\Partner;
|
||||
use Automattic\Jetpack\Roles;
|
||||
use Automattic\Jetpack\Status;
|
||||
use Automattic\Jetpack\Status\Host;
|
||||
@ -138,6 +139,9 @@ class Manager {
|
||||
|
||||
// Initialize token locks.
|
||||
new Tokens_Locks();
|
||||
|
||||
// Initial Partner management.
|
||||
Partner::init();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -274,7 +278,7 @@ class Manager {
|
||||
$jetpack_methods = array();
|
||||
|
||||
foreach ( $methods as $method => $callback ) {
|
||||
if ( 0 === strpos( $method, 'jetpack.' ) ) {
|
||||
if ( str_starts_with( $method, 'jetpack.' ) ) {
|
||||
$jetpack_methods[ $method ] = $callback;
|
||||
}
|
||||
}
|
||||
@ -441,7 +445,7 @@ class Manager {
|
||||
$post_data = $_POST;
|
||||
$file_hashes = array();
|
||||
foreach ( $post_data as $post_data_key => $post_data_value ) {
|
||||
if ( 0 !== strpos( $post_data_key, '_jetpack_file_hmac_' ) ) {
|
||||
if ( ! str_starts_with( $post_data_key, '_jetpack_file_hmac_' ) ) {
|
||||
continue;
|
||||
}
|
||||
$post_data_key = substr( $post_data_key, strlen( '_jetpack_file_hmac_' ) );
|
||||
@ -1188,7 +1192,7 @@ class Manager {
|
||||
$jetpack_public = false;
|
||||
}
|
||||
|
||||
\Jetpack_Options::update_options(
|
||||
Jetpack_Options::update_options(
|
||||
array(
|
||||
'id' => (int) $registration_details->jetpack_id,
|
||||
'public' => $jetpack_public,
|
||||
@ -1199,6 +1203,13 @@ class Manager {
|
||||
|
||||
$this->get_tokens()->update_blog_token( (string) $registration_details->jetpack_secret );
|
||||
|
||||
if ( ! Jetpack_Options::get_option( 'id' ) || ! $this->get_tokens()->get_access_token() ) {
|
||||
return new WP_Error(
|
||||
'connection_data_save_failed',
|
||||
'Failed to save connection data in the database'
|
||||
);
|
||||
}
|
||||
|
||||
$alternate_authorization_url = isset( $registration_details->alternate_authorization_url ) ? $registration_details->alternate_authorization_url : '';
|
||||
|
||||
add_filter(
|
||||
@ -1916,6 +1927,7 @@ class Manager {
|
||||
'site_created' => $this->get_assumed_site_creation_date(),
|
||||
'allow_site_connection' => ! $this->has_connected_owner(),
|
||||
'calypso_env' => ( new Host() )->get_calypso_env(),
|
||||
'source' => ( new Host() )->get_source_query(),
|
||||
)
|
||||
);
|
||||
|
||||
@ -1923,7 +1935,10 @@ class Manager {
|
||||
|
||||
$api_url = $this->api_url( 'authorize' );
|
||||
|
||||
return add_query_arg( $body, $api_url );
|
||||
$url = add_query_arg( $body, $api_url );
|
||||
|
||||
/** This filter is documented in plugins/jetpack/class-jetpack.php */
|
||||
return apply_filters( 'jetpack_build_authorize_url', $url );
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2544,18 +2559,36 @@ class Manager {
|
||||
/**
|
||||
* Get the WPCOM or self-hosted site ID.
|
||||
*
|
||||
* @return int|WP_Error
|
||||
* @param bool $quiet Return null instead of an error.
|
||||
*
|
||||
* @return int|WP_Error|null
|
||||
*/
|
||||
public static function get_site_id() {
|
||||
public static function get_site_id( $quiet = false ) {
|
||||
$is_wpcom = ( defined( 'IS_WPCOM' ) && IS_WPCOM );
|
||||
$site_id = $is_wpcom ? get_current_blog_id() : \Jetpack_Options::get_option( 'id' );
|
||||
if ( ! $site_id ) {
|
||||
return new \WP_Error(
|
||||
'unavailable_site_id',
|
||||
__( 'Sorry, something is wrong with your Jetpack connection.', 'jetpack-connection' ),
|
||||
403
|
||||
);
|
||||
return $quiet
|
||||
? null
|
||||
: new \WP_Error(
|
||||
'unavailable_site_id',
|
||||
__( 'Sorry, something is wrong with your Jetpack connection.', 'jetpack-connection' ),
|
||||
403
|
||||
);
|
||||
}
|
||||
return (int) $site_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if Jetpack is ready for uninstall cleanup.
|
||||
*
|
||||
* @param string $current_plugin_slug The current plugin's slug.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_ready_for_cleanup( $current_plugin_slug ) {
|
||||
$active_plugins = get_option( Plugin_Storage::ACTIVE_PLUGINS_OPTION_NAME );
|
||||
|
||||
return empty( $active_plugins ) || ! is_array( $active_plugins )
|
||||
|| ( count( $active_plugins ) === 1 && array_key_exists( $current_plugin_slug, $active_plugins ) );
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ namespace Automattic\Jetpack\Connection;
|
||||
*/
|
||||
class Package_Version {
|
||||
|
||||
const PACKAGE_VERSION = '1.58.2';
|
||||
const PACKAGE_VERSION = '2.2.0';
|
||||
|
||||
const PACKAGE_SLUG = 'connection';
|
||||
|
||||
|
@ -0,0 +1,466 @@
|
||||
<?php
|
||||
/**
|
||||
* Class for the Jetpack partner coupon logic.
|
||||
*
|
||||
* @package automattic/jetpack-connection
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack;
|
||||
|
||||
use Automattic\Jetpack\Connection\Client as Connection_Client;
|
||||
use Automattic\Jetpack\Connection\Manager as Connection_Manager;
|
||||
use Jetpack_Options;
|
||||
|
||||
/**
|
||||
* Disable direct access.
|
||||
*/
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Class Jetpack_Partner_Coupon
|
||||
*
|
||||
* @since partner-1.6.0
|
||||
* @since 2.0.0
|
||||
*/
|
||||
class Partner_Coupon {
|
||||
|
||||
/**
|
||||
* Name of the Jetpack_Option coupon option.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $coupon_option = 'partner_coupon';
|
||||
|
||||
/**
|
||||
* Name of the Jetpack_Option added option.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
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
|
||||
**/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* A list of supported partners.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $supported_partners = array(
|
||||
'IONOS' => array(
|
||||
'name' => 'IONOS',
|
||||
'logo' => array(
|
||||
'src' => '/images/ionos-logo.jpg',
|
||||
'width' => 119,
|
||||
'height' => 32,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
* A list of supported presets.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $supported_presets = array(
|
||||
'IONA' => 'jetpack_backup_daily',
|
||||
);
|
||||
|
||||
/**
|
||||
* Get singleton instance of class.
|
||||
*
|
||||
* @return Partner_Coupon
|
||||
*/
|
||||
public static function get_instance() {
|
||||
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.
|
||||
* @param string $redirect_location The location we should redirect to after catching the coupon.
|
||||
*/
|
||||
public static function register_coupon_admin_hooks( $plugin_slug, $redirect_location ) {
|
||||
$instance = self::get_instance();
|
||||
|
||||
// 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
|
||||
// to both implement partner coupon logic.
|
||||
add_action(
|
||||
'admin_init',
|
||||
function () use ( $plugin_slug, $redirect_location, $instance ) {
|
||||
$instance->catch_coupon( $plugin_slug, $redirect_location );
|
||||
$instance->maybe_purge_coupon( $plugin_slug );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Catch partner coupon and redirect to claim component.
|
||||
*
|
||||
* @param string $plugin_slug The plugin slug to differentiate between Jetpack connections.
|
||||
* @param string $redirect_location The location we should redirect to after catching the 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( wp_unslash( $_GET['jetpack-partner-coupon'] ) ) : false; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
if ( $partner_coupon ) {
|
||||
Jetpack_Options::update_options(
|
||||
array(
|
||||
self::$coupon_option => $partner_coupon,
|
||||
self::$added_option => time(),
|
||||
)
|
||||
);
|
||||
|
||||
$connection = new Connection_Manager( $plugin_slug );
|
||||
if ( $connection->is_connected() ) {
|
||||
$redirect_location = add_query_arg( array( 'showCouponRedemption' => 1 ), $redirect_location );
|
||||
wp_safe_redirect( $redirect_location );
|
||||
} else {
|
||||
wp_safe_redirect( $redirect_location );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Purge partner coupon.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
protected function maybe_purge_coupon_by_added_date() {
|
||||
$date = Jetpack_Options::get_option( self::$added_option, '' );
|
||||
|
||||
if ( empty( $date ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$expire_date = strtotime( '+30 days', $date );
|
||||
$today = time();
|
||||
|
||||
if ( $today >= $expire_date ) {
|
||||
$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,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get partner coupon data.
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
public static function get_coupon() {
|
||||
$coupon_code = Jetpack_Options::get_option( self::$coupon_option, '' );
|
||||
|
||||
if ( ! is_string( $coupon_code ) || empty( $coupon_code ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$instance = self::get_instance();
|
||||
$partner = $instance->get_coupon_partner( $coupon_code );
|
||||
|
||||
if ( ! $partner ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$preset = $instance->get_coupon_preset( $coupon_code );
|
||||
|
||||
if ( ! $preset ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$product = $instance->get_coupon_product( $preset );
|
||||
|
||||
if ( ! $product ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return array(
|
||||
'coupon_code' => $coupon_code,
|
||||
'partner' => $partner,
|
||||
'preset' => $preset,
|
||||
'product' => $product,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get coupon partner.
|
||||
*
|
||||
* @param string $coupon_code Coupon code to go through.
|
||||
* @return array|bool
|
||||
*/
|
||||
private function get_coupon_partner( $coupon_code ) {
|
||||
if ( ! is_string( $coupon_code ) || false === strpos( $coupon_code, '_' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$prefix = strtok( $coupon_code, '_' );
|
||||
$supported_partners = $this->get_supported_partners();
|
||||
|
||||
if ( ! isset( $supported_partners[ $prefix ] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return array(
|
||||
'name' => $supported_partners[ $prefix ]['name'],
|
||||
'prefix' => $prefix,
|
||||
'logo' => isset( $supported_partners[ $prefix ]['logo'] ) ? $supported_partners[ $prefix ]['logo'] : null,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get coupon product.
|
||||
*
|
||||
* @param string $coupon_preset The preset we wish to find a product for.
|
||||
* @return array|bool
|
||||
*/
|
||||
private function get_coupon_product( $coupon_preset ) {
|
||||
if ( ! is_string( $coupon_preset ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow for plugins to register supported products.
|
||||
*
|
||||
* @since 1.6.0
|
||||
*
|
||||
* @param array A list of product details.
|
||||
* @return array
|
||||
*/
|
||||
$product_details = apply_filters( 'jetpack_partner_coupon_products', array() );
|
||||
$product_slug = $this->get_supported_presets()[ $coupon_preset ];
|
||||
|
||||
foreach ( $product_details as $product ) {
|
||||
if ( ! $this->array_keys_exist( array( 'title', 'slug', 'description', 'features' ), $product ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $product_slug === $product['slug'] ) {
|
||||
return $product;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if multiple keys are present in an array.
|
||||
*
|
||||
* @param array $needles The keys we wish to check for.
|
||||
* @param array $haystack The array we want to compare keys against.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function array_keys_exist( $needles, $haystack ) {
|
||||
foreach ( $needles as $needle ) {
|
||||
if ( ! isset( $haystack[ $needle ] ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get coupon preset.
|
||||
*
|
||||
* @param string $coupon_code Coupon code to go through.
|
||||
* @return string|bool
|
||||
*/
|
||||
private function get_coupon_preset( $coupon_code ) {
|
||||
if ( ! is_string( $coupon_code ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$regex = '/^.*?_(?P<slug>.*?)_.+$/';
|
||||
$matches = array();
|
||||
|
||||
if ( ! preg_match( $regex, $coupon_code, $matches ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isset( $this->get_supported_presets()[ $matches['slug'] ] ) ? $matches['slug'] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get supported partners.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_supported_partners() {
|
||||
/**
|
||||
* Allow external code to add additional supported partners.
|
||||
*
|
||||
* @since partner-1.6.0
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param array $supported_partners A list of supported partners.
|
||||
* @return array
|
||||
*/
|
||||
return apply_filters( 'jetpack_partner_coupon_supported_partners', self::$supported_partners );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get supported presets.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_supported_presets() {
|
||||
/**
|
||||
* Allow external code to add additional supported presets.
|
||||
*
|
||||
* @since partner-1.6.0
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param array $supported_presets A list of supported presets.
|
||||
* @return array
|
||||
*/
|
||||
return apply_filters( 'jetpack_partner_coupon_supported_presets', self::$supported_presets );
|
||||
}
|
||||
}
|
@ -0,0 +1,215 @@
|
||||
<?php
|
||||
/**
|
||||
* Jetpack Partner utilities.
|
||||
*
|
||||
* @package automattic/jetpack-connection
|
||||
*/
|
||||
|
||||
namespace Automattic\Jetpack;
|
||||
|
||||
/**
|
||||
* This class introduces functionality used by Jetpack hosting partners.
|
||||
*
|
||||
* @since partner-1.0.0
|
||||
* @since 2.0.0
|
||||
*/
|
||||
class Partner {
|
||||
|
||||
/**
|
||||
* Affiliate code.
|
||||
*/
|
||||
const AFFILIATE_CODE = 'affiliate';
|
||||
|
||||
/**
|
||||
* Subsidiary id code.
|
||||
*/
|
||||
const SUBSIDIARY_CODE = 'subsidiary';
|
||||
|
||||
/**
|
||||
* Singleton instance.
|
||||
*
|
||||
* @since partner-1.0.0
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @var Partner This class instance.
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
/**
|
||||
* Partner constructor.
|
||||
*/
|
||||
private function __construct() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the class or returns the singleton.
|
||||
*
|
||||
* @since partner-1.0.0
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @return Partner | false
|
||||
*/
|
||||
public static function init() {
|
||||
if ( self::$instance === null ) {
|
||||
self::$instance = new Partner();
|
||||
add_filter( 'jetpack_build_authorize_url', array( self::$instance, 'add_subsidiary_id_as_query_arg' ) );
|
||||
add_filter( 'jetpack_build_authorize_url', array( self::$instance, 'add_affiliate_code_as_query_arg' ) );
|
||||
add_filter( 'jetpack_build_connection_url', array( self::$instance, 'add_subsidiary_id_as_query_arg' ) );
|
||||
add_filter( 'jetpack_build_connection_url', array( self::$instance, 'add_affiliate_code_as_query_arg' ) );
|
||||
|
||||
add_filter( 'jetpack_register_request_body', array( self::$instance, 'add_subsidiary_id_to_params_array' ) );
|
||||
add_filter( 'jetpack_register_request_body', array( self::$instance, 'add_affiliate_code_to_params_array' ) );
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the partner subsidiary code to the passed URL.
|
||||
*
|
||||
* @param string $url The URL.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function add_subsidiary_id_as_query_arg( $url ) {
|
||||
return $this->add_code_as_query_arg( self::SUBSIDIARY_CODE, $url );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the affiliate code to the passed URL.
|
||||
*
|
||||
* @param string $url The URL.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function add_affiliate_code_as_query_arg( $url ) {
|
||||
return $this->add_code_as_query_arg( self::AFFILIATE_CODE, $url );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the partner subsidiary code to the passed array.
|
||||
*
|
||||
* @since partner-1.5.0
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param array $params The parameters array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function add_subsidiary_id_to_params_array( $params ) {
|
||||
if ( ! is_array( $params ) ) {
|
||||
return $params;
|
||||
}
|
||||
return array_merge( $params, $this->get_code_as_array( self::SUBSIDIARY_CODE ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the affiliate code to the passed array.
|
||||
*
|
||||
* @since partner-1.5.0
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param array $params The parameters array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function add_affiliate_code_to_params_array( $params ) {
|
||||
if ( ! is_array( $params ) ) {
|
||||
return $params;
|
||||
}
|
||||
return array_merge( $params, $this->get_code_as_array( self::AFFILIATE_CODE ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the passed URL with the partner code added as a URL query arg.
|
||||
*
|
||||
* @since partner-1.0.0
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param string $type The partner code.
|
||||
* @param string $url The URL where the partner subsidiary id will be added.
|
||||
*
|
||||
* @return string The passed URL with the partner code added.
|
||||
*/
|
||||
public function add_code_as_query_arg( $type, $url ) {
|
||||
return add_query_arg( $this->get_code_as_array( $type ), $url );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the partner code in an associative array format
|
||||
*
|
||||
* @since partner-1.5.0
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param string $type The partner code.
|
||||
* @return array
|
||||
*/
|
||||
private function get_code_as_array( $type ) {
|
||||
switch ( $type ) {
|
||||
case self::AFFILIATE_CODE:
|
||||
$query_arg_name = 'aff';
|
||||
break;
|
||||
case self::SUBSIDIARY_CODE:
|
||||
$query_arg_name = 'subsidiaryId';
|
||||
break;
|
||||
default:
|
||||
return array();
|
||||
}
|
||||
|
||||
$code = $this->get_partner_code( $type );
|
||||
|
||||
if ( '' === $code ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
return array( $query_arg_name => $code );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a partner code.
|
||||
*
|
||||
* @since partner-1.0.0
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param string $type This can be either 'affiliate' or 'subsidiary'. Returns empty string when code is unknown.
|
||||
*
|
||||
* @return string The partner code.
|
||||
*/
|
||||
public function get_partner_code( $type ) {
|
||||
switch ( $type ) {
|
||||
case self::AFFILIATE_CODE:
|
||||
/**
|
||||
* Allow to filter the affiliate code.
|
||||
*
|
||||
* @since partner-1.0.0
|
||||
* @since-jetpack 6.9.0
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param string $affiliate_code The affiliate code, blank by default.
|
||||
*/
|
||||
return apply_filters( 'jetpack_affiliate_code', get_option( 'jetpack_affiliate_code', '' ) );
|
||||
case self::SUBSIDIARY_CODE:
|
||||
/**
|
||||
* Allow to filter the partner subsidiary id.
|
||||
*
|
||||
* @since partner-1.0.0
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param string $subsidiary_id The partner subsidiary id, blank by default.
|
||||
*/
|
||||
return apply_filters(
|
||||
'jetpack_partner_subsidiary_id',
|
||||
get_option( 'jetpack_partner_subsidiary_id', '' )
|
||||
);
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the singleton for testing purposes.
|
||||
*/
|
||||
public static function reset() {
|
||||
self::$instance = null;
|
||||
}
|
||||
}
|
@ -90,6 +90,7 @@ class Urls {
|
||||
$option_key = self::HTTPS_CHECK_OPTION_PREFIX . $callable;
|
||||
|
||||
$parsed_url = wp_parse_url( $new_value );
|
||||
|
||||
if ( ! $parsed_url ) {
|
||||
return $new_value;
|
||||
}
|
||||
@ -98,7 +99,12 @@ class Urls {
|
||||
} else {
|
||||
$scheme = '';
|
||||
}
|
||||
$scheme_history = get_option( $option_key, array() );
|
||||
$scheme_history = get_option( $option_key, array() );
|
||||
|
||||
if ( ! is_array( $scheme_history ) ) {
|
||||
$scheme_history = array();
|
||||
}
|
||||
|
||||
$scheme_history[] = $scheme;
|
||||
|
||||
// Limit length to self::HTTPS_CHECK_HISTORY.
|
||||
|
@ -60,6 +60,7 @@ class XMLRPC_Async_Call {
|
||||
self::$clients[ $client_blog_id ][ $user_id ] = new Jetpack_IXR_ClientMulticall( array( 'user_id' => $user_id ) );
|
||||
}
|
||||
|
||||
// https://plugins.trac.wordpress.org/ticket/2041
|
||||
if ( function_exists( 'ignore_user_abort' ) ) {
|
||||
ignore_user_abort( true );
|
||||
}
|
||||
|
@ -107,9 +107,7 @@ class Authorize_Redirect {
|
||||
remove_filter( 'jetpack_connect_request_body', array( __CLASS__, 'filter_connect_request_body' ) );
|
||||
remove_filter( 'jetpack_connect_redirect_url', array( __CLASS__, 'filter_connect_redirect_url' ) );
|
||||
|
||||
/**
|
||||
* This filter is documented in plugins/jetpack/class-jetpack.php
|
||||
*/
|
||||
/** This filter is documented in plugins/jetpack/class-jetpack.php */
|
||||
return apply_filters( 'jetpack_build_authorize_url', $url );
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user