Refactor remote specs structure and naming (#45547)
* Deprecate DataSourcePoller * Deprecate and move all rule processors and transformers * Lint * More deprecation * Remove extra line * Update deprecated class to not produce too many messages by limiting to unique messages * Changelog * Update all dependency uses, move TransformerService and TransformerInterface to Transformers package * More dependency update * Changelog * Fix wrong file reference * Lint markdown * Lint markdown * Add unsaved file * Delete unused file and more lint * More lint * Ugh ignore faulty lint rule * Rename variables for lint
This commit is contained in:
parent
7214a1ffee
commit
5485665727
|
@ -2,7 +2,7 @@
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\RuleEvaluator;
|
||||
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\RuleEvaluator;
|
||||
|
||||
register_woocommerce_admin_test_helper_rest_route(
|
||||
'/remote-spec-validator/validate',
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: patch
|
||||
Type: dev
|
||||
|
||||
Update import path
|
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: dev
|
||||
|
||||
Refactor remote specs structure and naming
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Admin\RemoteInboxNotifications as PromotionRuleEngine;
|
||||
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\RuleEvaluator;
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
|
@ -1075,7 +1076,7 @@ class WC_Admin_Addons {
|
|||
// Check for existence of promotions and evaluate out if we should show them.
|
||||
if ( ! empty( $promotions ) ) {
|
||||
foreach ( $promotions as $promo_id => $promotion ) {
|
||||
$evaluator = new PromotionRuleEngine\RuleEvaluator();
|
||||
$evaluator = new RuleEvaluator();
|
||||
$passed = $evaluator->evaluate( $promotion->rules );
|
||||
if ( ! $passed ) {
|
||||
unset( $promotions[ $promo_id ] );
|
||||
|
|
|
@ -2,55 +2,29 @@
|
|||
|
||||
namespace Automattic\WooCommerce\Admin;
|
||||
|
||||
use Automattic\WooCommerce\Admin\RemoteSpecs\DataSourcePoller as RemoteSpecsDataSourcePoller;
|
||||
|
||||
/**
|
||||
* Specs data source poller class.
|
||||
* This handles polling specs from JSON endpoints, and
|
||||
* stores the specs in to the database as an option.
|
||||
*
|
||||
* @deprecated since 8.8.0
|
||||
*/
|
||||
abstract class DataSourcePoller {
|
||||
|
||||
abstract class DataSourcePoller extends RemoteSpecsDataSourcePoller {
|
||||
/**
|
||||
* Get class instance.
|
||||
* Log a deprecation to the error log.
|
||||
*/
|
||||
abstract public static function get_instance();
|
||||
|
||||
/**
|
||||
* Name of data sources filter.
|
||||
*/
|
||||
const FILTER_NAME = 'data_source_poller_data_sources';
|
||||
|
||||
/**
|
||||
* Name of data source specs filter.
|
||||
*/
|
||||
const FILTER_NAME_SPECS = 'data_source_poller_specs';
|
||||
|
||||
/**
|
||||
* Id of DataSourcePoller.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $id = array();
|
||||
|
||||
/**
|
||||
* Default data sources array.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $data_sources = array();
|
||||
|
||||
/**
|
||||
* Default args.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $args = array();
|
||||
|
||||
/**
|
||||
* The logger instance.
|
||||
*
|
||||
* @var WC_Logger|null
|
||||
*/
|
||||
protected static $logger = null;
|
||||
private static function log_deprecation() {
|
||||
error_log( // phpcs:ignore
|
||||
sprintf(
|
||||
'%1$s is deprecated since version %2$s! Use %3$s instead.',
|
||||
self::class,
|
||||
'8.8.0',
|
||||
'Automattic\WooCommerce\Admin\RemoteSpecs\DataSourcePoller'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
|
@ -60,98 +34,41 @@ abstract class DataSourcePoller {
|
|||
* @param array $args Options for DataSourcePoller.
|
||||
*/
|
||||
public function __construct( $id, $data_sources = array(), $args = array() ) {
|
||||
$this->data_sources = $data_sources;
|
||||
$this->id = $id;
|
||||
|
||||
$arg_defaults = array(
|
||||
'spec_key' => 'id',
|
||||
'transient_name' => 'woocommerce_admin_' . $id . '_specs',
|
||||
'transient_expiry' => 7 * DAY_IN_SECONDS,
|
||||
);
|
||||
$this->args = wp_parse_args( $args, $arg_defaults );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the logger instance.
|
||||
*
|
||||
* @return WC_Logger
|
||||
*/
|
||||
protected static function get_logger() {
|
||||
if ( is_null( self::$logger ) ) {
|
||||
self::$logger = wc_get_logger();
|
||||
}
|
||||
|
||||
return self::$logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key identifier of spec, this can easily be overwritten. Defaults to id.
|
||||
*
|
||||
* @param mixed $spec a JSON parsed spec coming from the JSON feed.
|
||||
* @return string|boolean
|
||||
*/
|
||||
protected function get_spec_key( $spec ) {
|
||||
$key = $this->args['spec_key'];
|
||||
if ( isset( $spec->$key ) ) {
|
||||
return $spec->$key;
|
||||
}
|
||||
return false;
|
||||
self::log_deprecation();
|
||||
parent::__construct( $id, $data_sources, $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the data sources for specs and persists those specs.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
* @return array list of specs.
|
||||
*/
|
||||
public function get_specs_from_data_sources() {
|
||||
$locale = get_user_locale();
|
||||
$specs_group = get_transient( $this->args['transient_name'] ) ?? array();
|
||||
$specs = isset( $specs_group[ $locale ] ) ? $specs_group[ $locale ] : array();
|
||||
|
||||
if ( ! is_array( $specs ) || empty( $specs ) ) {
|
||||
$this->read_specs_from_data_sources();
|
||||
$specs_group = get_transient( $this->args['transient_name'] );
|
||||
$specs = isset( $specs_group[ $locale ] ) ? $specs_group[ $locale ] : array();
|
||||
}
|
||||
$specs = apply_filters( self::FILTER_NAME_SPECS, $specs, $this->id );
|
||||
return $specs !== false ? $specs : array();
|
||||
self::log_deprecation();
|
||||
return parent::get_specs_from_data_sources();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the data sources for specs and persists those specs.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
* @return bool Whether any specs were read.
|
||||
*/
|
||||
public function read_specs_from_data_sources() {
|
||||
$specs = array();
|
||||
$data_sources = apply_filters( self::FILTER_NAME, $this->data_sources, $this->id );
|
||||
|
||||
// Note that this merges the specs from the data sources based on the
|
||||
// id - last one wins.
|
||||
foreach ( $data_sources as $url ) {
|
||||
$specs_from_data_source = self::read_data_source( $url );
|
||||
$this->merge_specs( $specs_from_data_source, $specs, $url );
|
||||
}
|
||||
|
||||
$specs_group = get_transient( $this->args['transient_name'] );
|
||||
$specs_group = is_array( $specs_group ) ? $specs_group : array();
|
||||
$locale = get_user_locale();
|
||||
$specs_group[ $locale ] = $specs;
|
||||
// Persist the specs as a transient.
|
||||
$this->set_specs_transient(
|
||||
$specs_group,
|
||||
$this->args['transient_expiry']
|
||||
);
|
||||
return count( $specs ) !== 0;
|
||||
self::log_deprecation();
|
||||
return parent::read_specs_from_data_sources();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the specs transient.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
* @return bool success of failure of transient deletion.
|
||||
*/
|
||||
public function delete_specs_transient() {
|
||||
return delete_transient( $this->args['transient_name'] );
|
||||
self::log_deprecation();
|
||||
return parent::delete_specs_transient();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -159,112 +76,11 @@ abstract class DataSourcePoller {
|
|||
*
|
||||
* @param array $specs The specs to set in the transient.
|
||||
* @param int $expiration The expiration time for the transient.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
public function set_specs_transient( $specs, $expiration = 0 ) {
|
||||
set_transient(
|
||||
$this->args['transient_name'],
|
||||
$specs,
|
||||
$expiration,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a single data source and return the read specs
|
||||
*
|
||||
* @param string $url The URL to read the specs from.
|
||||
*
|
||||
* @return array The specs that have been read from the data source.
|
||||
*/
|
||||
protected static function read_data_source( $url ) {
|
||||
$logger_context = array( 'source' => $url );
|
||||
$logger = self::get_logger();
|
||||
$response = wp_remote_get(
|
||||
add_query_arg(
|
||||
'locale',
|
||||
get_user_locale(),
|
||||
$url
|
||||
),
|
||||
array(
|
||||
'user-agent' => 'WooCommerce/' . WC_VERSION . '; ' . home_url( '/' ),
|
||||
)
|
||||
);
|
||||
|
||||
if ( is_wp_error( $response ) || ! isset( $response['body'] ) ) {
|
||||
$logger->error(
|
||||
'Error getting data feed',
|
||||
$logger_context
|
||||
);
|
||||
// phpcs:ignore
|
||||
$logger->error( print_r( $response, true ), $logger_context );
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
$body = $response['body'];
|
||||
$specs = json_decode( $body );
|
||||
|
||||
if ( $specs === null ) {
|
||||
$logger->error(
|
||||
'Empty response in data feed',
|
||||
$logger_context
|
||||
);
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
if ( ! is_array( $specs ) ) {
|
||||
$logger->error(
|
||||
'Data feed is not an array',
|
||||
$logger_context
|
||||
);
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
return $specs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the specs.
|
||||
*
|
||||
* @param Array $specs_to_merge_in The specs to merge in to $specs.
|
||||
* @param Array $specs The list of specs being merged into.
|
||||
* @param string $url The url of the feed being merged in (for error reporting).
|
||||
*/
|
||||
protected function merge_specs( $specs_to_merge_in, &$specs, $url ) {
|
||||
foreach ( $specs_to_merge_in as $spec ) {
|
||||
if ( ! $this->validate_spec( $spec, $url ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$id = $this->get_spec_key( $spec );
|
||||
$specs[ $id ] = $spec;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the spec.
|
||||
*
|
||||
* @param object $spec The spec to validate.
|
||||
* @param string $url The url of the feed that provided the spec.
|
||||
*
|
||||
* @return bool The result of the validation.
|
||||
*/
|
||||
protected function validate_spec( $spec, $url ) {
|
||||
$logger = self::get_logger();
|
||||
$logger_context = array( 'source' => $url );
|
||||
|
||||
if ( ! $this->get_spec_key( $spec ) ) {
|
||||
$logger->error(
|
||||
'Spec is invalid because the id is missing in feed',
|
||||
$logger_context
|
||||
);
|
||||
// phpcs:ignore
|
||||
$logger->error( print_r( $spec, true ), $logger_context );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
self::log_deprecation();
|
||||
return parent::set_specs_transient( $specs, $expiration );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,12 @@ class DeprecatedClassFacade {
|
|||
*/
|
||||
protected static $deprecated_in_version = '';
|
||||
|
||||
/**
|
||||
* Static array of logged messages.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private static $logged_messages = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
|
@ -61,14 +67,18 @@ class DeprecatedClassFacade {
|
|||
* @param string $function The name of the deprecated function being called.
|
||||
*/
|
||||
private static function log_deprecation( $function ) {
|
||||
error_log( // phpcs:ignore
|
||||
sprintf(
|
||||
'%1$s is deprecated since version %2$s! Use %3$s instead.',
|
||||
static::class . '::' . $function,
|
||||
static::$deprecated_in_version,
|
||||
static::$facade_over_classname . '::' . $function
|
||||
)
|
||||
$message = sprintf(
|
||||
'%1$s is deprecated since version %2$s! Use %3$s instead.',
|
||||
static::class . '::' . $function,
|
||||
static::$deprecated_in_version,
|
||||
static::$facade_over_classname . '::' . $function
|
||||
);
|
||||
|
||||
// Only log when the message has not been logged before.
|
||||
if ( ! in_array( $message, self::$logged_messages, true ) ) {
|
||||
error_log( $message ); // phpcs:ignore
|
||||
self::$logged_messages[] = $message;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace Automattic\WooCommerce\Admin\Features\MarketingRecommendations;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DataSourcePoller;
|
||||
use Automattic\WooCommerce\Admin\RemoteSpecs\DataSourcePoller;
|
||||
|
||||
/**
|
||||
* Specs data source poller class for marketing recommendations.
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\RuleEvaluator;
|
||||
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\RuleEvaluator;
|
||||
|
||||
/**
|
||||
* Evaluates the spec and returns the evaluated suggestion.
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace Automattic\WooCommerce\Admin\Features\PaymentGatewaySuggestions;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DataSourcePoller;
|
||||
use Automattic\WooCommerce\Admin\RemoteSpecs\DataSourcePoller;
|
||||
|
||||
/**
|
||||
* Specs data source poller class for payment gateway suggestions.
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace Automattic\WooCommerce\Admin\Features\ShippingPartnerSuggestions;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DataSourcePoller;
|
||||
use Automattic\WooCommerce\Admin\RemoteSpecs\DataSourcePoller;
|
||||
|
||||
/**
|
||||
* Specs data source poller class for shipping partner suggestions.
|
||||
|
|
|
@ -6,65 +6,28 @@
|
|||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
||||
|
||||
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Rule processor that performs a comparison operation against the base
|
||||
* location - country.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class BaseLocationCountryRuleProcessor implements RuleProcessorInterface {
|
||||
class BaseLocationCountryRuleProcessor extends DeprecatedClassFacade {
|
||||
/**
|
||||
* Performs a comparison operation against the base location - country.
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @param object $rule The specific rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
* @var string
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
$base_location = wc_get_base_location();
|
||||
if (
|
||||
! is_array( $base_location ) ||
|
||||
! array_key_exists( 'country', $base_location ) ||
|
||||
! array_key_exists( 'state', $base_location )
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$onboarding_profile = get_option( 'woocommerce_onboarding_profile', array() );
|
||||
$is_address_default = 'US' === $base_location['country'] && 'CA' === $base_location['state'] && empty( get_option( 'woocommerce_store_address', '' ) );
|
||||
$is_store_country_set = isset( $onboarding_profile['is_store_country_set'] ) && $onboarding_profile['is_store_country_set'];
|
||||
|
||||
// Return false if the location is the default country and if onboarding hasn't been finished or the store address not been updated.
|
||||
if ( $is_address_default && OnboardingProfile::needs_completion() && ! $is_store_country_set ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ComparisonOperation::compare(
|
||||
$base_location['country'],
|
||||
$rule->value,
|
||||
$rule->operation
|
||||
);
|
||||
}
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\BaseLocationCountryRuleProcessor';
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
* @var string
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->operation ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -6,50 +6,28 @@
|
|||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Rule processor that performs a comparison operation against the base
|
||||
* location - state.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class BaseLocationStateRuleProcessor implements RuleProcessorInterface {
|
||||
class BaseLocationStateRuleProcessor extends DeprecatedClassFacade {
|
||||
/**
|
||||
* Performs a comparison operation against the base location - state.
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @param object $rule The specific rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
* @var string
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
$base_location = wc_get_base_location();
|
||||
if ( ! is_array( $base_location ) || ! array_key_exists( 'state', $base_location ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ComparisonOperation::compare(
|
||||
$base_location['state'],
|
||||
$rule->value,
|
||||
$rule->operation
|
||||
);
|
||||
}
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\BaseLocationStateRuleProcessor';
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
* @var string
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->operation ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -7,70 +7,25 @@ namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Compare two operands using the specified operation.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class ComparisonOperation {
|
||||
class ComparisonOperation extends DeprecatedClassFacade {
|
||||
/**
|
||||
* Compare two operands using the specified operation.
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @param object $left_operand The left hand operand.
|
||||
* @param object $right_operand The right hand operand -- 'value' from the rule definition.
|
||||
* @param string $operation The operation used to compare the operands.
|
||||
* @var string
|
||||
*/
|
||||
public static function compare( $left_operand, $right_operand, $operation ) {
|
||||
switch ( $operation ) {
|
||||
case '=':
|
||||
return $left_operand === $right_operand;
|
||||
case '<':
|
||||
return $left_operand < $right_operand;
|
||||
case '<=':
|
||||
return $left_operand <= $right_operand;
|
||||
case '>':
|
||||
return $left_operand > $right_operand;
|
||||
case '>=':
|
||||
return $left_operand >= $right_operand;
|
||||
case '!=':
|
||||
return $left_operand !== $right_operand;
|
||||
case 'contains':
|
||||
if ( is_array( $left_operand ) && is_string( $right_operand ) ) {
|
||||
return in_array( $right_operand, $left_operand, true );
|
||||
}
|
||||
if ( is_string( $right_operand ) && is_string( $left_operand ) ) {
|
||||
return strpos( $right_operand, $left_operand ) !== false;
|
||||
}
|
||||
break;
|
||||
case '!contains':
|
||||
if ( is_array( $left_operand ) && is_string( $right_operand ) ) {
|
||||
return ! in_array( $right_operand, $left_operand, true );
|
||||
}
|
||||
if ( is_string( $right_operand ) && is_string( $left_operand ) ) {
|
||||
return strpos( $right_operand, $left_operand ) === false;
|
||||
}
|
||||
break;
|
||||
case 'in':
|
||||
if ( is_array( $right_operand ) && is_string( $left_operand ) ) {
|
||||
return in_array( $left_operand, $right_operand, true );
|
||||
}
|
||||
if ( is_string( $left_operand ) && is_string( $right_operand ) ) {
|
||||
return strpos( $left_operand, $right_operand ) !== false;
|
||||
}
|
||||
break;
|
||||
case '!in':
|
||||
if ( is_array( $right_operand ) && is_string( $left_operand ) ) {
|
||||
return ! in_array( $left_operand, $right_operand, true );
|
||||
}
|
||||
if ( is_string( $left_operand ) && is_string( $right_operand ) ) {
|
||||
return strpos( $left_operand, $right_operand ) === false;
|
||||
}
|
||||
break;
|
||||
case 'range':
|
||||
if ( ! is_array( $right_operand ) || count( $right_operand ) !== 2 ) {
|
||||
return false;
|
||||
}
|
||||
return $left_operand >= $right_operand[0] && $left_operand <= $right_operand[1];
|
||||
}
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\ComparisonOperation';
|
||||
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -7,53 +7,25 @@ namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\Notes\Note;
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Evaluates the spec and returns a status.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class EvaluateAndGetStatus {
|
||||
class EvaluateAndGetStatus extends DeprecatedClassFacade {
|
||||
/**
|
||||
* Evaluates the spec and returns a status.
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @param array $spec The spec to evaluate.
|
||||
* @param string $current_status The note's current status.
|
||||
* @param object $stored_state Stored state.
|
||||
* @param object $rule_evaluator Evaluates rules into true/false.
|
||||
*
|
||||
* @return string The evaluated status.
|
||||
* @var string
|
||||
*/
|
||||
public static function evaluate( $spec, $current_status, $stored_state, $rule_evaluator ) {
|
||||
// No rules should leave the note alone.
|
||||
if ( ! isset( $spec->rules ) ) {
|
||||
return $current_status;
|
||||
}
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\EvaluateAndGetStatus';
|
||||
|
||||
$evaluated_result = $rule_evaluator->evaluate(
|
||||
$spec->rules,
|
||||
$stored_state,
|
||||
array(
|
||||
'slug' => $spec->slug,
|
||||
'source' => 'remote-inbox-notifications',
|
||||
)
|
||||
);
|
||||
|
||||
// Pending notes should be the spec status if the spec passes,
|
||||
// left alone otherwise.
|
||||
if ( Note::E_WC_ADMIN_NOTE_PENDING === $current_status ) {
|
||||
return $evaluated_result
|
||||
? $spec->status
|
||||
: Note::E_WC_ADMIN_NOTE_PENDING;
|
||||
}
|
||||
|
||||
// When allow_redisplay isn't set, just leave the note alone.
|
||||
if ( ! isset( $spec->allow_redisplay ) || ! $spec->allow_redisplay ) {
|
||||
return $current_status;
|
||||
}
|
||||
|
||||
// allow_redisplay is set, unaction the note if eval to true.
|
||||
return $evaluated_result
|
||||
? Note::E_WC_ADMIN_NOTE_UNACTIONED
|
||||
: $current_status;
|
||||
}
|
||||
/**
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -2,89 +2,26 @@
|
|||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
/**
|
||||
* Class EvaluationLogger
|
||||
*
|
||||
* @package Automattic\WooCommerce\Admin\RemoteInboxNotifications
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class EvaluationLogger {
|
||||
class EvaluationLogger extends DeprecatedClassFacade {
|
||||
/**
|
||||
* Slug of the spec.
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $slug;
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\EvaluationLogger';
|
||||
|
||||
/**
|
||||
* Results of rules in the given spec.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @var array
|
||||
* @var string
|
||||
*/
|
||||
private $results = array();
|
||||
|
||||
/**
|
||||
* Logger class to use.
|
||||
*
|
||||
* @var WC_Logger_Interface|null
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* Logger source.
|
||||
*
|
||||
* @var string logger source.
|
||||
*/
|
||||
private $source = '';
|
||||
|
||||
/**
|
||||
* EvaluationLogger constructor.
|
||||
*
|
||||
* @param string $slug Slug of a spec that is being evaluated.
|
||||
* @param null $source Logger source.
|
||||
* @param \WC_Logger_Interface $logger Logger class to use.
|
||||
*/
|
||||
public function __construct( $slug, $source = null, \WC_Logger_Interface $logger = null ) {
|
||||
$this->slug = $slug;
|
||||
if ( null === $logger ) {
|
||||
$logger = wc_get_logger();
|
||||
}
|
||||
|
||||
if ( $source ) {
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add evaluation result of a rule.
|
||||
*
|
||||
* @param string $rule_type name of the rule being tested.
|
||||
* @param boolean $result result of a given rule.
|
||||
*/
|
||||
public function add_result( $rule_type, $result ) {
|
||||
array_push(
|
||||
$this->results,
|
||||
array(
|
||||
'rule' => $rule_type,
|
||||
'result' => $result ? 'passed' : 'failed',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the results.
|
||||
*/
|
||||
public function log() {
|
||||
if ( false === defined( 'WC_ADMIN_DEBUG_RULE_EVALUATOR' ) || true !== constant( 'WC_ADMIN_DEBUG_RULE_EVALUATOR' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $this->results as $result ) {
|
||||
$this->logger->debug(
|
||||
"[{$this->slug}] {$result['rule']}: {$result['result']}",
|
||||
array( 'source' => $this->source )
|
||||
);
|
||||
}
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -7,30 +7,25 @@ namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Rule processor that fails.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class FailRuleProcessor implements RuleProcessorInterface {
|
||||
class FailRuleProcessor extends DeprecatedClassFacade {
|
||||
/**
|
||||
* Fails the rule.
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @param object $rule The specific rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool Always false.
|
||||
* @var string
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
return false;
|
||||
}
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\FailRuleProcessor';
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
* @var string
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -7,63 +7,25 @@ namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Class encapsulating getting the processor for a given rule type.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class GetRuleProcessor {
|
||||
class GetRuleProcessor extends DeprecatedClassFacade {
|
||||
/**
|
||||
* Get the processor for the specified rule type.
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @param string $rule_type The rule type.
|
||||
*
|
||||
* @return RuleProcessorInterface The matching processor for the specified rule type, or a FailRuleProcessor if no matching processor is found.
|
||||
* @var string
|
||||
*/
|
||||
public static function get_processor( $rule_type ) {
|
||||
switch ( $rule_type ) {
|
||||
case 'plugins_activated':
|
||||
return new PluginsActivatedRuleProcessor();
|
||||
case 'publish_after_time':
|
||||
return new PublishAfterTimeRuleProcessor();
|
||||
case 'publish_before_time':
|
||||
return new PublishBeforeTimeRuleProcessor();
|
||||
case 'not':
|
||||
return new NotRuleProcessor();
|
||||
case 'or':
|
||||
return new OrRuleProcessor();
|
||||
case 'fail':
|
||||
return new FailRuleProcessor();
|
||||
case 'pass':
|
||||
return new PassRuleProcessor();
|
||||
case 'plugin_version':
|
||||
return new PluginVersionRuleProcessor();
|
||||
case 'stored_state':
|
||||
return new StoredStateRuleProcessor();
|
||||
case 'order_count':
|
||||
return new OrderCountRuleProcessor();
|
||||
case 'wcadmin_active_for':
|
||||
return new WCAdminActiveForRuleProcessor();
|
||||
case 'product_count':
|
||||
return new ProductCountRuleProcessor();
|
||||
case 'onboarding_profile':
|
||||
return new OnboardingProfileRuleProcessor();
|
||||
case 'is_ecommerce':
|
||||
return new IsEcommerceRuleProcessor();
|
||||
case 'is_woo_express':
|
||||
return new IsWooExpressRuleProcessor();
|
||||
case 'base_location_country':
|
||||
return new BaseLocationCountryRuleProcessor();
|
||||
case 'base_location_state':
|
||||
return new BaseLocationStateRuleProcessor();
|
||||
case 'note_status':
|
||||
return new NoteStatusRuleProcessor();
|
||||
case 'option':
|
||||
return new OptionRuleProcessor();
|
||||
case 'wca_updated':
|
||||
return new WooCommerceAdminUpdatedRuleProcessor();
|
||||
case 'total_payments_value':
|
||||
return new TotalPaymentsVolumeProcessor();
|
||||
}
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\GetRuleProcessor';
|
||||
|
||||
return new FailRuleProcessor();
|
||||
}
|
||||
/**
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -10,40 +10,26 @@ namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Rule processor that passes (or fails) when the site is on the eCommerce
|
||||
* plan.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class IsEcommerceRuleProcessor implements RuleProcessorInterface {
|
||||
class IsEcommerceRuleProcessor extends DeprecatedClassFacade {
|
||||
/**
|
||||
* Passes (or fails) based on whether the site is on the eCommerce plan or
|
||||
* not.
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @param object $rule The rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
* @var string
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
if ( ! function_exists( 'wc_calypso_bridge_is_ecommerce_plan' ) ) {
|
||||
return false === $rule->value;
|
||||
}
|
||||
|
||||
return (bool) wc_calypso_bridge_is_ecommerce_plan() === $rule->value;
|
||||
}
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\IsEcommerceRuleProcessor';
|
||||
|
||||
/**
|
||||
* Validate the rule.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
* @var string
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -9,61 +9,26 @@ namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Rule processor that passes (or fails) when the site is on a Woo Express plan.
|
||||
* You may optionally pass a plan name to target a specific Woo Express plan.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class IsWooExpressRuleProcessor implements RuleProcessorInterface {
|
||||
class IsWooExpressRuleProcessor extends DeprecatedClassFacade {
|
||||
/**
|
||||
* Passes (or fails) based on whether the site is a Woo Express plan.
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @param object $rule The rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
* @var string
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
if ( ! function_exists( 'wc_calypso_bridge_is_woo_express_plan' ) ) {
|
||||
return false === $rule->value;
|
||||
}
|
||||
|
||||
// If the plan is undefined, only check if it's a Woo Express plan.
|
||||
if ( ! isset( $rule->plan ) ) {
|
||||
return wc_calypso_bridge_is_woo_express_plan() === $rule->value;
|
||||
}
|
||||
|
||||
// If a plan name is defined, only evaluate the plan if we're on the Woo Express plan.
|
||||
if ( wc_calypso_bridge_is_woo_express_plan() ) {
|
||||
$fn = 'wc_calypso_bridge_is_woo_express_' . (string) $rule->plan . '_plan';
|
||||
if ( function_exists( $fn ) ) {
|
||||
return $fn() === $rule->value;
|
||||
}
|
||||
|
||||
// If an invalid plan name is given, only evaluate the rule if we're targeting all plans other than the specified (invalid) one.
|
||||
return false === $rule->value;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\IsWooExpressRuleProcessor';
|
||||
|
||||
/**
|
||||
* Validate the rule.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
* @var string
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( isset( $rule->plan ) ) {
|
||||
if ( ! function_exists( 'wc_calypso_bridge_is_woo_express_plan' ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -7,58 +7,25 @@ namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Rule processor that negates the rules in the rule's operand.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class NotRuleProcessor implements RuleProcessorInterface {
|
||||
class NotRuleProcessor extends DeprecatedClassFacade {
|
||||
/**
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\NotRuleProcessor';
|
||||
|
||||
/**
|
||||
* The rule evaluator to use.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @var RuleEvaluator
|
||||
* @var string
|
||||
*/
|
||||
protected $rule_evaluator;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param RuleEvaluator $rule_evaluator The rule evaluator to use.
|
||||
*/
|
||||
public function __construct( $rule_evaluator = null ) {
|
||||
$this->rule_evaluator = null === $rule_evaluator
|
||||
? new RuleEvaluator()
|
||||
: $rule_evaluator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the rules in the operand and negates the result.
|
||||
*
|
||||
* @param object $rule The specific rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
$evaluated_operand = $this->rule_evaluator->evaluate(
|
||||
$rule->operand,
|
||||
$stored_state
|
||||
);
|
||||
|
||||
return ! $evaluated_operand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->operand ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -9,53 +9,25 @@ namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\Notes\Notes;
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Rule processor that compares against the status of another note.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class NoteStatusRuleProcessor implements RuleProcessorInterface {
|
||||
class NoteStatusRuleProcessor extends DeprecatedClassFacade {
|
||||
/**
|
||||
* Compare against the status of another note.
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @param object $rule The rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
* @var string
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
$status = Notes::get_note_status( $rule->note_name );
|
||||
if ( ! $status ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ComparisonOperation::compare(
|
||||
$status,
|
||||
$rule->status,
|
||||
$rule->operation
|
||||
);
|
||||
}
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\NoteStatusRuleProcessor';
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
* @var string
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->note_name ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->status ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->operation ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -8,58 +8,26 @@ namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Rule processor that performs a comparison operation against a value in the
|
||||
* onboarding profile.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class OnboardingProfileRuleProcessor implements RuleProcessorInterface {
|
||||
class OnboardingProfileRuleProcessor extends DeprecatedClassFacade {
|
||||
/**
|
||||
* Performs a comparison operation against a value in the onboarding
|
||||
* profile.
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @param object $rule The rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
* @var string
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
$onboarding_profile = get_option( 'woocommerce_onboarding_profile' );
|
||||
|
||||
if ( empty( $onboarding_profile ) || ! is_array( $onboarding_profile ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $onboarding_profile[ $rule->index ] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ComparisonOperation::compare(
|
||||
$onboarding_profile[ $rule->index ],
|
||||
$rule->value,
|
||||
$rule->operation
|
||||
);
|
||||
}
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\OnboardingProfileRuleProcessor';
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
* @var string
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->index ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->operation ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -7,97 +7,25 @@ namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Rule processor that performs a comparison operation against an option value.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class OptionRuleProcessor implements RuleProcessorInterface {
|
||||
class OptionRuleProcessor extends DeprecatedClassFacade {
|
||||
/**
|
||||
* Performs a comparison operation against the option value.
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @param object $rule The specific rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
* @var string
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
$is_contains = $rule->operation && strpos( $rule->operation, 'contains' ) !== false;
|
||||
$default_value = $is_contains ? array() : false;
|
||||
$is_default_set = property_exists( $rule, 'default' );
|
||||
$default = $is_default_set ? $rule->default : $default_value;
|
||||
$option_value = $this->get_option_value( $rule, $default, $is_contains );
|
||||
|
||||
if ( isset( $rule->transformers ) && is_array( $rule->transformers ) ) {
|
||||
$option_value = TransformerService::apply( $option_value, $rule->transformers, $is_default_set, $default );
|
||||
}
|
||||
|
||||
return ComparisonOperation::compare(
|
||||
$option_value,
|
||||
$rule->value,
|
||||
$rule->operation
|
||||
);
|
||||
}
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\OptionRuleProcessor';
|
||||
|
||||
/**
|
||||
* Retrieves the option value and handles logging if necessary.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @param object $rule The specific rule being processed.
|
||||
* @param mixed $default The default value.
|
||||
* @param bool $is_contains Indicates whether the operation is "contains".
|
||||
*
|
||||
* @return mixed The option value.
|
||||
* @var string
|
||||
*/
|
||||
private function get_option_value( $rule, $default, $is_contains ) {
|
||||
$option_value = get_option( $rule->option_name, $default );
|
||||
$is_contains_valid = $is_contains && ( is_array( $option_value ) || ( is_string( $option_value ) && is_string( $rule->value ) ) );
|
||||
|
||||
if ( $is_contains && ! $is_contains_valid ) {
|
||||
$logger = wc_get_logger();
|
||||
$logger->warning(
|
||||
sprintf(
|
||||
'ComparisonOperation "%s" option value "%s" is not an array, defaulting to empty array.',
|
||||
$rule->operation,
|
||||
$rule->option_name
|
||||
),
|
||||
array(
|
||||
'option_value' => $option_value,
|
||||
'rule' => $rule,
|
||||
)
|
||||
);
|
||||
$option_value = array();
|
||||
}
|
||||
|
||||
return $option_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->option_name ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->operation ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( isset( $rule->transformers ) && is_array( $rule->transformers ) ) {
|
||||
foreach ( $rule->transformers as $transform_args ) {
|
||||
$transformer = TransformerService::create_transformer( $transform_args->use );
|
||||
if ( ! $transformer->validate( $transform_args->arguments ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -8,66 +8,26 @@ namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Rule processor that performs an OR operation on the rule's left and right
|
||||
* operands.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class OrRuleProcessor implements RuleProcessorInterface {
|
||||
class OrRuleProcessor extends DeprecatedClassFacade {
|
||||
/**
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\OrRuleProcessor';
|
||||
|
||||
/**
|
||||
* Rule evaluator to use.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @var RuleEvaluator
|
||||
* @var string
|
||||
*/
|
||||
private $rule_evaluator;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param RuleEvaluator $rule_evaluator The rule evaluator to use.
|
||||
*/
|
||||
public function __construct( $rule_evaluator = null ) {
|
||||
$this->rule_evaluator = null === $rule_evaluator
|
||||
? new RuleEvaluator()
|
||||
: $rule_evaluator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs an OR operation on the rule's left and right operands.
|
||||
*
|
||||
* @param object $rule The specific rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
foreach ( $rule->operands as $operand ) {
|
||||
$evaluated_operand = $this->rule_evaluator->evaluate(
|
||||
$operand,
|
||||
$stored_state
|
||||
);
|
||||
|
||||
if ( $evaluated_operand ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->operands ) || ! is_array( $rule->operands ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -7,63 +7,25 @@ namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Rule processor for publishing based on the number of orders.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class OrderCountRuleProcessor implements RuleProcessorInterface {
|
||||
class OrderCountRuleProcessor extends DeprecatedClassFacade {
|
||||
/**
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\OrderCountRuleProcessor';
|
||||
|
||||
/**
|
||||
* The orders provider.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @var OrdersProvider
|
||||
* @var string
|
||||
*/
|
||||
protected $orders_provider;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param object $orders_provider The orders provider.
|
||||
*/
|
||||
public function __construct( $orders_provider = null ) {
|
||||
$this->orders_provider = null === $orders_provider
|
||||
? new OrdersProvider()
|
||||
: $orders_provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the rule.
|
||||
*
|
||||
* @param object $rule The rule to process.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool Whether the rule passes or not.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
$count = $this->orders_provider->get_order_count();
|
||||
|
||||
return ComparisonOperation::compare(
|
||||
$count,
|
||||
$rule->value,
|
||||
$rule->operation
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->operation ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -7,30 +7,25 @@ namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Provider for order-related queries and operations.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class OrdersProvider {
|
||||
class OrdersProvider extends DeprecatedClassFacade {
|
||||
/**
|
||||
* Allowed order statuses for calculating milestones.
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @var array
|
||||
* @var string
|
||||
*/
|
||||
protected $allowed_statuses = array(
|
||||
'pending',
|
||||
'processing',
|
||||
'completed',
|
||||
);
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\OrdersProvider';
|
||||
|
||||
/**
|
||||
* Returns the number of orders.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @return integer The number of orders.
|
||||
* @var string
|
||||
*/
|
||||
public function get_order_count() {
|
||||
$status_counts = array_map( 'wc_orders_count', $this->allowed_statuses );
|
||||
$orders_count = array_sum( $status_counts );
|
||||
|
||||
return $orders_count;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -8,30 +8,25 @@ namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Rule processor that passes.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class PassRuleProcessor implements RuleProcessorInterface {
|
||||
class PassRuleProcessor extends DeprecatedClassFacade {
|
||||
/**
|
||||
* Passes the rule.
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @param object $rule The specific rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool Always true.
|
||||
* @var string
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
return true;
|
||||
}
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\PassRuleProcessor';
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
* @var string
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -8,79 +8,26 @@ namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\PluginsProvider\PluginsProvider;
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Rule processor for sending when the provided plugin is activated and
|
||||
* matches the specified version.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class PluginVersionRuleProcessor implements RuleProcessorInterface {
|
||||
class PluginVersionRuleProcessor extends DeprecatedClassFacade {
|
||||
/**
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\PluginVersionRuleProcessor';
|
||||
|
||||
/**
|
||||
* Plugins provider instance.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @var PluginsProviderInterface
|
||||
* @var string
|
||||
*/
|
||||
private $plugins_provider;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param PluginsProviderInterface $plugins_provider The plugins provider.
|
||||
*/
|
||||
public function __construct( $plugins_provider = null ) {
|
||||
$this->plugins_provider = null === $plugins_provider
|
||||
? new PluginsProvider()
|
||||
: $plugins_provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the rule.
|
||||
*
|
||||
* @param object $rule The specific rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool Whether the rule passes or not.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
$active_plugin_slugs = $this->plugins_provider->get_active_plugin_slugs();
|
||||
|
||||
if ( ! in_array( $rule->plugin, $active_plugin_slugs, true ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$plugin_data = $this->plugins_provider->get_plugin_data( $rule->plugin );
|
||||
|
||||
if ( ! is_array( $plugin_data ) || ! array_key_exists( 'Version', $plugin_data ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$plugin_version = $plugin_data['Version'];
|
||||
|
||||
return version_compare( $plugin_version, $rule->version, $rule->operator );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->plugin ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->version ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->operator ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -7,75 +7,25 @@ namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\PluginsProvider\PluginsProvider;
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Rule processor for sending when the provided plugins are activated.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class PluginsActivatedRuleProcessor implements RuleProcessorInterface {
|
||||
class PluginsActivatedRuleProcessor extends DeprecatedClassFacade {
|
||||
/**
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\PluginsActivatedRuleProcessor';
|
||||
|
||||
/**
|
||||
* The plugins provider.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @var PluginsProviderInterface
|
||||
* @var string
|
||||
*/
|
||||
protected $plugins_provider;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param PluginsProviderInterface $plugins_provider The plugins provider.
|
||||
*/
|
||||
public function __construct( $plugins_provider = null ) {
|
||||
$this->plugins_provider = null === $plugins_provider
|
||||
? new PluginsProvider()
|
||||
: $plugins_provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the rule.
|
||||
*
|
||||
* @param object $rule The specific rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool Whether the rule passes or not.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
if ( ! is_countable( $rule->plugins ) || 0 === count( $rule->plugins ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$active_plugin_slugs = $this->plugins_provider->get_active_plugin_slugs();
|
||||
|
||||
foreach ( $rule->plugins as $plugin_slug ) {
|
||||
if ( ! is_string( $plugin_slug ) ) {
|
||||
$logger = wc_get_logger();
|
||||
$logger->warning(
|
||||
__( 'Invalid plugin slug provided in the plugins activated rule.', 'woocommerce' )
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! in_array( $plugin_slug, $active_plugin_slugs, true ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->plugins ) || ! is_array( $rule->plugins ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -8,71 +8,26 @@ namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Rule processor that performs a comparison operation against the number of
|
||||
* products.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class ProductCountRuleProcessor implements RuleProcessorInterface {
|
||||
class ProductCountRuleProcessor extends DeprecatedClassFacade {
|
||||
/**
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\ProductCountRuleProcessor';
|
||||
|
||||
/**
|
||||
* The product query.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @var WC_Product_Query
|
||||
* @var string
|
||||
*/
|
||||
protected $product_query;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param object $product_query The product query.
|
||||
*/
|
||||
public function __construct( $product_query = null ) {
|
||||
$this->product_query = null === $product_query
|
||||
? new \WC_Product_Query(
|
||||
array(
|
||||
'limit' => 1,
|
||||
'paginate' => true,
|
||||
'return' => 'ids',
|
||||
'status' => array( 'publish' ),
|
||||
)
|
||||
)
|
||||
: $product_query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a comparison operation against the number of products.
|
||||
*
|
||||
* @param object $rule The specific rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
$products = $this->product_query->get_products();
|
||||
|
||||
return ComparisonOperation::compare(
|
||||
$products->total,
|
||||
$rule->value,
|
||||
$rule->operation
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->operation ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -7,61 +7,25 @@ namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DateTimeProvider\CurrentDateTimeProvider;
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Rule processor for sending after a specified date/time.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class PublishAfterTimeRuleProcessor implements RuleProcessorInterface {
|
||||
class PublishAfterTimeRuleProcessor extends DeprecatedClassFacade {
|
||||
/**
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\PublishAfterTimeRuleProcessor';
|
||||
|
||||
/**
|
||||
* The DateTime provider.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @var DateTimeProviderInterface
|
||||
* @var string
|
||||
*/
|
||||
protected $date_time_provider;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param DateTimeProviderInterface $date_time_provider The DateTime provider.
|
||||
*/
|
||||
public function __construct( $date_time_provider = null ) {
|
||||
$this->date_time_provider = null === $date_time_provider
|
||||
? new CurrentDateTimeProvider()
|
||||
: $date_time_provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the rule.
|
||||
*
|
||||
* @param object $rule The specific rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool Whether the rule passes or not.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
return $this->date_time_provider->get_now() >= new \DateTime( $rule->publish_after );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->publish_after ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
new \DateTime( $rule->publish_after );
|
||||
} catch ( \Throwable $e ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -7,61 +7,25 @@ namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DateTimeProvider\CurrentDateTimeProvider;
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Rule processor for sending before a specified date/time.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class PublishBeforeTimeRuleProcessor implements RuleProcessorInterface {
|
||||
class PublishBeforeTimeRuleProcessor extends DeprecatedClassFacade {
|
||||
/**
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\PublishBeforeTimeRuleProcessor';
|
||||
|
||||
/**
|
||||
* The DateTime provider.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @var DateTimeProviderInterface
|
||||
* @var string
|
||||
*/
|
||||
protected $date_time_provider;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param DateTimeProviderInterface $date_time_provider The DateTime provider.
|
||||
*/
|
||||
public function __construct( $date_time_provider = null ) {
|
||||
$this->date_time_provider = null === $date_time_provider
|
||||
? new CurrentDateTimeProvider()
|
||||
: $date_time_provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the rule.
|
||||
*
|
||||
* @param object $rule The specific rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool Whether the rule passes or not.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
return $this->date_time_provider->get_now() <= new \DateTime( $rule->publish_before );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->publish_before ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
new \DateTime( $rule->publish_before );
|
||||
} catch ( \Throwable $e ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -136,480 +136,4 @@ The `status` is what the status of the created note will be set to after interac
|
|||
|
||||
## Rule
|
||||
|
||||
Rules in an array are executed as an AND operation. If there are no rules in the array the result is false and the specified notification is not shown.
|
||||
|
||||
### Operations
|
||||
|
||||
Some rule types support an `operation` value, which is used to compare two
|
||||
values. The following operations are implemented:
|
||||
|
||||
- `=`
|
||||
- `<`
|
||||
- `<=`
|
||||
- `>`
|
||||
- `>=`
|
||||
- `!=`
|
||||
- `contains`
|
||||
- `!contains`
|
||||
- `in` (Added in WooCommerce 8.2.0)
|
||||
- `!in` (Added in WooCommerce 8.2.0)
|
||||
- `range` (Added in WooCommerce 8.8.0)
|
||||
|
||||
#### contains and !contains
|
||||
|
||||
`contains` and `!contains` allow checking if the provided value is present (or
|
||||
not present) in the haystack value. An example of this is using the
|
||||
`onboarding_profile` rule to match on a value in the `product_types` array -
|
||||
this rule matches if `physical` was selected as a product type in the
|
||||
onboarding profile:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "onboarding_profile",
|
||||
"index": "product_types",
|
||||
"operation": "contains",
|
||||
"value": "physical"
|
||||
}
|
||||
```
|
||||
|
||||
#### in and !in
|
||||
|
||||
`in` and `!in` allow checking if a value is found (or not found) in a provided array. For example, using the `in` comparison operator to check if the base country location value is found in a given array, as below. This rule matches if the `base_location_country` is `US`, `NZ`, or `ZA`. **NOTE:** These comparisons were added in **WooCommerce 8.2.0**. If the spec is read by an older version of WooCommerce, the rule will evaluate to `false`.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "base_location_country",
|
||||
"value": [
|
||||
"US",
|
||||
"NZ",
|
||||
"ZA"
|
||||
],
|
||||
"operation": "in"
|
||||
}
|
||||
```
|
||||
|
||||
#### range
|
||||
|
||||
`range` operator performs an inclusive check to determine if a number falls within a certain range.
|
||||
This means that both the 'from' and 'to' values of the specified range are included in the check.
|
||||
|
||||
The following rule returns true when `woocommerce_remote_variant_assignment` value is between 1 and 10.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "option",
|
||||
"value": [ 1, 10 ],
|
||||
"default": 0,
|
||||
"operation": "range",
|
||||
"option_name": "woocommerce_remote_variant_assignment",
|
||||
}
|
||||
```
|
||||
|
||||
### Plugins activated
|
||||
|
||||
This passes if all of the listed plugins are installed and activated.
|
||||
|
||||
`plugins` is required.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "plugins_activated",
|
||||
"plugins": [
|
||||
"plugin-slug-1',
|
||||
"plugin-slug-2"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Publish after time
|
||||
|
||||
This passes if the system time is after the specified date/time.
|
||||
|
||||
Note that using both `publish_after_time` and `publish_before_time` allows timeboxing a note which could be useful for promoting a sale.
|
||||
|
||||
`publish_after` is required.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "publish_after_time",
|
||||
"publish_after": "2020-04-22 00:00:00"
|
||||
}
|
||||
```
|
||||
|
||||
### Publish before time
|
||||
|
||||
This passes if the system time is before the specified date/time.
|
||||
|
||||
Note that using both `publish_after_time` and `publish_before_time` allows timeboxing a note which could be useful for promoting a sale.
|
||||
|
||||
`publish_before` is required.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "publish_before_time",
|
||||
"publish_before": "2020-04-22 00:00:00"
|
||||
}
|
||||
```
|
||||
|
||||
### Not
|
||||
|
||||
This negates the rules in the provided set of rules. Note that the rules in `operand` get ANDed together into a single boolean.
|
||||
|
||||
`operand` is required.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "not",
|
||||
"operand": [
|
||||
<Rule>,
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Or
|
||||
|
||||
This performs an OR operation on the operands, passing if any of the operands evaluates to true. Note that if the operands are an array of `Rule`s (as in the first example), each operand is treated as an AND operation.
|
||||
|
||||
`operands` is required.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "or",
|
||||
"operands": [
|
||||
[
|
||||
<Rule>,
|
||||
...
|
||||
],
|
||||
[
|
||||
<Rule>,
|
||||
...
|
||||
]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Alternatively:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "or",
|
||||
"operands": [
|
||||
<Rule>,
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Fail
|
||||
|
||||
This just returns a false value. This is useful if you want to keep a specification around, but don't want it displayed.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "fail"
|
||||
}
|
||||
```
|
||||
|
||||
### Plugin version
|
||||
|
||||
This compares the installed version of the plugin to the required version, using the comparison operator. If the plugin isn’t activated this returns false.
|
||||
|
||||
`plugin`, `version`, and `operator` are required.
|
||||
|
||||
This example passes if Jetpack 8.4.1 is installed and activated.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "plugin_version",
|
||||
"plugin": "jetpack",
|
||||
"version": "8.4.1",
|
||||
"operator": "="
|
||||
}
|
||||
```
|
||||
|
||||
### Stored state
|
||||
|
||||
This allows access to a stored state containing calculated values that otherwise would be impossible to reproduce using other rules. It performs the comparison operation against the stored state value.
|
||||
|
||||
This example passes if the `there_were_no_products` index is equal to `true`.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "stored_state",
|
||||
"index": "there_were_no_products",
|
||||
"operation": "=",
|
||||
"value": true
|
||||
}
|
||||
```
|
||||
|
||||
There are only a limited amount of indices available to this rule, and new indices will need a new version of the WC Admin plugin to be installed.
|
||||
|
||||
The currently available indices are:
|
||||
|
||||
```json
|
||||
there_were_no_products
|
||||
there_are_now_products
|
||||
new_product_count
|
||||
```
|
||||
|
||||
`index`, `operation`, and `value` are required.
|
||||
|
||||
### Product count
|
||||
|
||||
This passes if the number of products currently in the system match the comparison operation.
|
||||
|
||||
This example passes if there are more than 10 products currently in the system.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "product_count",
|
||||
"operation": ">",
|
||||
"value": 10
|
||||
}
|
||||
```
|
||||
|
||||
`operation` and `value` are required.
|
||||
|
||||
### Order count
|
||||
|
||||
This passes if the number of orders currently in the system match the comparison operation.
|
||||
|
||||
This example passes if there are more than 10 orders currently in the system.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "order_count",
|
||||
"operation": ">",
|
||||
"value": 10
|
||||
}
|
||||
```
|
||||
|
||||
`operation` and `value` are required.
|
||||
|
||||
### WooCommerce Admin active for
|
||||
|
||||
This passes if the time WooCommerce Admin has been active for (in days) matches the comparison operation.
|
||||
|
||||
This is used as a proxy indicator of the age of the shop.
|
||||
|
||||
This example passes if it has been active for more than 8 days.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "wcadmin_active_for",
|
||||
"operation": ">",
|
||||
"days": 8
|
||||
}
|
||||
```
|
||||
|
||||
`operation` and `days` are required.
|
||||
|
||||
### Onboarding profile
|
||||
|
||||
This allows access to the onboarding profile that was built up in the onboarding wizard. The below example passes when the current revenue selected was "none".
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "onboarding_profile",
|
||||
"index": "revenue",
|
||||
"operation": "=",
|
||||
"value": "none"
|
||||
}
|
||||
```
|
||||
|
||||
`index`, `operation`, and `value` are all required.
|
||||
|
||||
### Is eCommerce
|
||||
|
||||
This passes when the store is on a WordPress.com site with the eCommerce plan.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "is_ecommerce",
|
||||
"value": true
|
||||
}
|
||||
```
|
||||
|
||||
`value` is required.
|
||||
|
||||
### Is Woo Express
|
||||
|
||||
This passes when the store is on a WordPress.com site with a Woo Express plan active.
|
||||
You can optionally pass the `plan` name to target a specific Woo Express plan, e.g. `performance`.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "is_woo_express",
|
||||
"plan": "trial|essential|performance",
|
||||
"value": true
|
||||
}
|
||||
```
|
||||
|
||||
`value` is required.
|
||||
`plan` is optional, e.g. `trial`, `essential`, `performance`.
|
||||
|
||||
### Base location - country
|
||||
|
||||
This passes when the store is located in the specified country.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "base_location_country",
|
||||
"value": "US",
|
||||
"operation": "="
|
||||
}
|
||||
```
|
||||
|
||||
`value` and `operation` are both required.
|
||||
|
||||
### Base location - state
|
||||
|
||||
This passes when the store is located in the specified state.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "base_location_state",
|
||||
"value": "TX",
|
||||
"operation": "="
|
||||
}
|
||||
```
|
||||
|
||||
`value` and `operation` are both required.
|
||||
|
||||
### Note status
|
||||
|
||||
This passes when the status of the specified note matches the specified status.
|
||||
The below example passes when the `wc-admin-mobile-app` note has not been
|
||||
actioned.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "note_status",
|
||||
"note_name": "wc-admin-mobile-app",
|
||||
"status": "actioned",
|
||||
"operation": "!="
|
||||
}
|
||||
```
|
||||
|
||||
### Total Payments Value
|
||||
|
||||
This passes when the total value of all payments for a given timeframe
|
||||
compared to the provided value pass the operation test.
|
||||
|
||||
`timeframe` can be one of `last_week`, `last_month`, `last_quarter`, `last_6_months`, `last_year`
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "total_payments_value",
|
||||
"timeframe": "last_month",
|
||||
"value": 2300,
|
||||
"operation": ">"
|
||||
}
|
||||
```
|
||||
|
||||
`timeframe`, `value`, and `operation` are all required.
|
||||
|
||||
### Option
|
||||
|
||||
This passes when the option value matches the value using the operation.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "option",
|
||||
"option_name": "woocommerce_currency",
|
||||
"value": "USD",
|
||||
"default": "USD",
|
||||
"operation": "="
|
||||
}
|
||||
```
|
||||
|
||||
`option_name`, `value`, and `operation` are all required. `default` is not required and allows a default value to be used if the option does not exist.
|
||||
|
||||
#### Option Transformer
|
||||
|
||||
This transforms the given option value into a different value by a series of transformers.
|
||||
|
||||
Example option value:
|
||||
|
||||
```php
|
||||
Array
|
||||
(
|
||||
[setup_client] =>
|
||||
[industry] => Array
|
||||
(
|
||||
[0] => Array
|
||||
(
|
||||
[slug] => food-drink
|
||||
)
|
||||
|
||||
[1] => Array
|
||||
(
|
||||
[slug] => fashion-apparel-accessories
|
||||
)
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
If you want to ensure that the industry array contains `fashion-apparel-accessories`, you can use the following Option definition with transformers.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "option",
|
||||
"transformers": [
|
||||
{
|
||||
"use": "dot_notation",
|
||||
"arguments": {
|
||||
"path": "industry"
|
||||
}
|
||||
},
|
||||
{
|
||||
"use": "array_column",
|
||||
"arguments": {
|
||||
"key": "slug"
|
||||
}
|
||||
},
|
||||
{
|
||||
"use": "array_search",
|
||||
"arguments": {
|
||||
"value": "fashion-apparel-accessories"
|
||||
}
|
||||
}
|
||||
],
|
||||
"option_name": "woocommerce_onboarding_profile",
|
||||
"value": "fashion-apparel-accessories",
|
||||
"default": "USD",
|
||||
"operation": "="
|
||||
}
|
||||
```
|
||||
|
||||
You can find a list of transformers and examples in the transformer [README](./Transformers/README.md).
|
||||
|
||||
### WCA updated
|
||||
|
||||
This passes when WooCommerce Admin has just been updated. The specs will be run
|
||||
on update. Note that this doesn't provide a way to check the version number as
|
||||
the `plugin_version` rule can be used to check for a specific version of the
|
||||
WooCommerce Admin plugin.
|
||||
|
||||
```json
|
||||
{
|
||||
type: "wca_updated"
|
||||
}
|
||||
```
|
||||
|
||||
No other values are needed.
|
||||
|
||||
## Debugging Specification
|
||||
|
||||
You can see the evaluation of each specification by turning on an optional evaluation logger.
|
||||
|
||||
1. Define `WC_ADMIN_DEBUG_RULE_EVALUATOR` constant in `wp-config.php`. `define('WC_ADMIN_DEBUG_RULE_EVALUATOR', true);`
|
||||
2. Run `wc_admin_daily`
|
||||
3. cd to `wp-content/uploads/wc-logs/` and check a log file in `remote-inbox-notifications-:date-hash.log` format.
|
||||
|
||||
You can tail the log file with a slug name to see the evaluation of a rule that you are testing.
|
||||
|
||||
Example:
|
||||
|
||||
`tail -f remote-inbox-notifications-2021-06-15-128.log | grep 'wcpay-promo-2021-6-incentive-2'`
|
||||
You can find the readme for RuleProcessors and Transformers in [this README](../RemoteSpecs/RuleProcessors/README.md)
|
||||
|
|
|
@ -7,12 +7,15 @@ namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\RemoteSpecs\DataSourcePoller;
|
||||
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\GetRuleProcessor;
|
||||
|
||||
/**
|
||||
* Specs data source poller class.
|
||||
* This handles polling specs from JSON endpoints, and
|
||||
* stores the specs in to the database as an option.
|
||||
*/
|
||||
class DataSourcePoller extends \Automattic\WooCommerce\Admin\DataSourcePoller {
|
||||
class RemoteInboxNotificationsDataSourcePoller extends DataSourcePoller {
|
||||
const ID = 'remote_inbox_notifications';
|
||||
const DATA_SOURCES = array(
|
||||
'https://woocommerce.com/wp-json/wccom/inbox-notifications/2.0/notifications.json',
|
|
@ -11,6 +11,7 @@ use Automattic\WooCommerce\Admin\PluginsProvider\PluginsProvider;
|
|||
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
|
||||
use Automattic\WooCommerce\Admin\Notes\Note;
|
||||
use Automattic\WooCommerce\Admin\RemoteSpecs\RemoteSpecsEngine;
|
||||
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\StoredStateSetupForProducts;
|
||||
|
||||
/**
|
||||
* Remote Inbox Notifications engine.
|
||||
|
@ -111,7 +112,7 @@ class RemoteInboxNotificationsEngine extends RemoteSpecsEngine {
|
|||
* Go through the specs and run them.
|
||||
*/
|
||||
public static function run() {
|
||||
$specs = DataSourcePoller::get_instance()->get_specs_from_data_sources();
|
||||
$specs = RemoteInboxNotificationsDataSourcePoller::get_instance()->get_specs_from_data_sources();
|
||||
|
||||
if ( false === $specs || ! is_countable( $specs ) || count( $specs ) === 0 ) {
|
||||
return;
|
||||
|
@ -204,7 +205,7 @@ class RemoteInboxNotificationsEngine extends RemoteSpecsEngine {
|
|||
if ( ! $note_from_db instanceof Note || get_user_locale() === $note_from_db->get_locale() ) {
|
||||
return $note_from_db;
|
||||
}
|
||||
$specs = DataSourcePoller::get_instance()->get_specs_from_data_sources();
|
||||
$specs = RemoteInboxNotificationsDataSourcePoller::get_instance()->get_specs_from_data_sources();
|
||||
foreach ( $specs as $spec ) {
|
||||
if ( $spec->slug !== $note_from_db->get_name() ) {
|
||||
continue;
|
||||
|
|
|
@ -8,85 +8,26 @@ namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Evaluate the given rules as an AND operation - return false early if a
|
||||
* rule evaluates to false.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class RuleEvaluator {
|
||||
class RuleEvaluator extends DeprecatedClassFacade {
|
||||
/**
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\RuleEvaluator';
|
||||
|
||||
/**
|
||||
* GetRuleProcessor to use.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @var GetRuleProcessor
|
||||
* @var string
|
||||
*/
|
||||
private $get_rule_processor;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param GetRuleProcessor $get_rule_processor The GetRuleProcessor to use.
|
||||
*/
|
||||
public function __construct( $get_rule_processor = null ) {
|
||||
$this->get_rule_processor = null === $get_rule_processor
|
||||
? new GetRuleProcessor()
|
||||
: $get_rule_processor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the given rules as an AND operation - return false early if a
|
||||
* rule evaluates to false.
|
||||
*
|
||||
* @param array|object $rules The rule or rules being processed.
|
||||
* @param object|null $stored_state Stored state.
|
||||
* @param array $logger_args Arguments for the event logger. `slug` is required.
|
||||
*
|
||||
* @throws \InvalidArgumentException Thrown when $logger_args is missing slug.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
*/
|
||||
public function evaluate( $rules, $stored_state = null, $logger_args = array() ) {
|
||||
|
||||
if ( is_bool( $rules ) ) {
|
||||
return $rules;
|
||||
}
|
||||
|
||||
if ( ! is_array( $rules ) ) {
|
||||
$rules = array( $rules );
|
||||
}
|
||||
|
||||
if ( 0 === count( $rules ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$evaluation_logger = null;
|
||||
|
||||
if ( count( $logger_args ) ) {
|
||||
if ( ! array_key_exists( 'slug', $logger_args ) ) {
|
||||
throw new \InvalidArgumentException( 'Missing required field: slug in $logger_args.' );
|
||||
}
|
||||
|
||||
array_key_exists( 'source', $logger_args ) ? $source = $logger_args['source'] : $source = null;
|
||||
|
||||
$evaluation_logger = new EvaluationLogger( $logger_args['slug'], $source );
|
||||
}
|
||||
|
||||
foreach ( $rules as $rule ) {
|
||||
if ( ! is_object( $rule ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$processor = $this->get_rule_processor->get_processor( $rule->type );
|
||||
$processor_result = $processor->process( $rule, $stored_state );
|
||||
$evaluation_logger && $evaluation_logger->add_result( $rule->type, $processor_result );
|
||||
|
||||
if ( ! $processor_result ) {
|
||||
$evaluation_logger && $evaluation_logger->log();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$evaluation_logger && $evaluation_logger->log();
|
||||
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ defined( 'ABSPATH' ) || exit;
|
|||
|
||||
use Automattic\WooCommerce\Admin\Notes\Note;
|
||||
use Automattic\WooCommerce\Admin\Notes\Notes;
|
||||
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\EvaluateAndGetStatus;
|
||||
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\RuleEvaluator;
|
||||
|
||||
/**
|
||||
* Runs a single spec.
|
||||
|
|
|
@ -8,51 +8,26 @@ namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Rule processor that performs a comparison operation against a value in the
|
||||
* stored state object.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class StoredStateRuleProcessor implements RuleProcessorInterface {
|
||||
class StoredStateRuleProcessor extends DeprecatedClassFacade {
|
||||
/**
|
||||
* Performs a comparison operation against a value in the stored state object.
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @param object $rule The rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
* @var string
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
if ( ! isset( $stored_state->{$rule->index} ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ComparisonOperation::compare(
|
||||
$stored_state->{$rule->index},
|
||||
$rule->value,
|
||||
$rule->operation
|
||||
);
|
||||
}
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\StoredStateRuleProcessor';
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
* @var string
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->index ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->operation ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -7,125 +7,25 @@ namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\PluginsProvider\PluginsProvider;
|
||||
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\SpecRunner;
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Handles stored state setup for products.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class StoredStateSetupForProducts {
|
||||
const ASYNC_RUN_REMOTE_NOTIFICATIONS_ACTION_NAME =
|
||||
'woocommerce_admin/stored_state_setup_for_products/async/run_remote_notifications';
|
||||
|
||||
class StoredStateSetupForProducts extends DeprecatedClassFacade {
|
||||
/**
|
||||
* Initialize the class via the admin_init hook.
|
||||
*/
|
||||
public static function admin_init() {
|
||||
add_action( 'product_page_product_importer', array( __CLASS__, 'run_on_product_importer' ) );
|
||||
add_action( 'transition_post_status', array( __CLASS__, 'run_on_transition_post_status' ), 10, 3 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the class via the init hook.
|
||||
*/
|
||||
public static function init() {
|
||||
add_action( self::ASYNC_RUN_REMOTE_NOTIFICATIONS_ACTION_NAME, array( __CLASS__, 'run_remote_notifications' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the remote notifications engine. This is triggered by
|
||||
* action-scheduler after a product is added. It also cleans up from
|
||||
* setting the product count increment.
|
||||
*/
|
||||
public static function run_remote_notifications() {
|
||||
RemoteInboxNotificationsEngine::run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set initial stored state values.
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @param object $stored_state The stored state.
|
||||
* @var string
|
||||
*/
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\StoredStateSetupForProducts';
|
||||
|
||||
/**
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @return object The stored state.
|
||||
* @var string
|
||||
*/
|
||||
public static function init_stored_state( $stored_state ) {
|
||||
$stored_state->there_were_no_products = ! self::are_there_products();
|
||||
$stored_state->there_are_now_products = ! $stored_state->there_were_no_products;
|
||||
|
||||
return $stored_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Are there products query.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private static function are_there_products() {
|
||||
$query = new \WC_Product_Query(
|
||||
array(
|
||||
'limit' => 1,
|
||||
'paginate' => true,
|
||||
'return' => 'ids',
|
||||
'status' => array( 'publish' ),
|
||||
)
|
||||
);
|
||||
$products = $query->get_products();
|
||||
$count = $products->total;
|
||||
|
||||
return $count > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs on product importer steps.
|
||||
*/
|
||||
public static function run_on_product_importer() {
|
||||
// We're only interested in when the importer completes.
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
if ( ! isset( $_REQUEST['step'] ) ) {
|
||||
return;
|
||||
}
|
||||
if ( 'done' !== $_REQUEST['step'] ) {
|
||||
return;
|
||||
}
|
||||
// phpcs:enable
|
||||
|
||||
self::update_stored_state_and_possibly_run_remote_notifications();
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs when a post status transitions, but we're only interested if it is
|
||||
* a product being published.
|
||||
*
|
||||
* @param string $new_status The new status.
|
||||
* @param string $old_status The old status.
|
||||
* @param Post $post The post.
|
||||
*/
|
||||
public static function run_on_transition_post_status( $new_status, $old_status, $post ) {
|
||||
if (
|
||||
'product' !== $post->post_type ||
|
||||
'publish' !== $new_status
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::update_stored_state_and_possibly_run_remote_notifications();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues an async action (using action-scheduler) to run remote
|
||||
* notifications.
|
||||
*/
|
||||
private static function update_stored_state_and_possibly_run_remote_notifications() {
|
||||
$stored_state = RemoteInboxNotificationsEngine::get_stored_state();
|
||||
// If the stored_state is the same, we don't need to run remote notifications to avoid unnecessary action scheduling.
|
||||
if ( true === $stored_state->there_are_now_products ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$stored_state->there_are_now_products = true;
|
||||
RemoteInboxNotificationsEngine::update_stored_state( $stored_state );
|
||||
|
||||
// Run self::run_remote_notifications asynchronously.
|
||||
as_enqueue_async_action( self::ASYNC_RUN_REMOTE_NOTIFICATIONS_ACTION_NAME );
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -7,87 +7,25 @@ namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\API\Reports\Revenue\Query as RevenueQuery;
|
||||
use Automattic\WooCommerce\Admin\API\Reports\TimeInterval;
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Rule processor that passes when a store's payments volume exceeds a provided amount.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class TotalPaymentsVolumeProcessor implements RuleProcessorInterface {
|
||||
class TotalPaymentsVolumeProcessor extends DeprecatedClassFacade {
|
||||
/**
|
||||
* Compare against the store's total payments volume.
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @param object $rule The rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
* @var string
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
$dates = TimeInterval::get_timeframe_dates( $rule->timeframe );
|
||||
$reports_revenue = $this->get_reports_query(
|
||||
array(
|
||||
'before' => $dates['end'],
|
||||
'after' => $dates['start'],
|
||||
'interval' => 'year',
|
||||
'fields' => array( 'total_sales' ),
|
||||
)
|
||||
);
|
||||
$report_data = $reports_revenue->get_data();
|
||||
|
||||
if ( ! $report_data || ! isset( $report_data->totals->total_sales ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$value = $report_data->totals->total_sales;
|
||||
|
||||
return ComparisonOperation::compare(
|
||||
$value,
|
||||
$rule->value,
|
||||
$rule->operation
|
||||
);
|
||||
}
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\TotalPaymentsVolumeProcessor';
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
* @var string
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
$allowed_timeframes = array(
|
||||
'last_week',
|
||||
'last_month',
|
||||
'last_quarter',
|
||||
'last_6_months',
|
||||
'last_year',
|
||||
);
|
||||
|
||||
if ( ! isset( $rule->timeframe ) || ! in_array( $rule->timeframe, $allowed_timeframes, true ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->value ) || ! is_numeric( $rule->value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->operation ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the report query.
|
||||
*
|
||||
* @param array $args The query args.
|
||||
*
|
||||
* @return RevenueQuery The report query.
|
||||
*/
|
||||
protected function get_reports_query( $args ) {
|
||||
return new RevenueQuery(
|
||||
$args
|
||||
);
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -17,11 +17,11 @@ interface TransformerInterface {
|
|||
*
|
||||
* @param mixed $value a value to transform.
|
||||
* @param stdClass|null $arguments arguments.
|
||||
* @param string|null $default default value.
|
||||
* @param string|null $default_value default value.
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function transform( $value, stdClass $arguments = null, $default = null);
|
||||
public function transform( $value, stdClass $arguments = null, $default_value = null );
|
||||
|
||||
/**
|
||||
* Validate Transformer arguments.
|
||||
|
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use stdClass;
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* A simple service class for the Transformer classes.
|
||||
|
@ -11,73 +10,21 @@ use stdClass;
|
|||
* Class TransformerService
|
||||
*
|
||||
* @package Automattic\WooCommerce\Admin\RemoteInboxNotifications
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class TransformerService {
|
||||
class TransformerService extends DeprecatedClassFacade {
|
||||
/**
|
||||
* Create a transformer object by name.
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @param string $name name of the transformer.
|
||||
*
|
||||
* @return TransformerInterface|null
|
||||
* @var string
|
||||
*/
|
||||
public static function create_transformer( $name ) {
|
||||
$camel_cased = str_replace( ' ', '', ucwords( str_replace( '_', ' ', $name ) ) );
|
||||
|
||||
$classname = __NAMESPACE__ . '\\Transformers\\' . $camel_cased;
|
||||
if ( ! class_exists( $classname ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new $classname();
|
||||
}
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\TransformerService';
|
||||
|
||||
/**
|
||||
* Apply transformers to the given value.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @param mixed $target_value a value to transform.
|
||||
* @param array $transformer_configs transform configuration.
|
||||
* @param bool $is_default_set flag on is default value set.
|
||||
* @param string $default default value.
|
||||
*
|
||||
* @throws InvalidArgumentException Throws when one of the requried arguments is missing.
|
||||
* @return mixed|null
|
||||
* @var string
|
||||
*/
|
||||
public static function apply( $target_value, array $transformer_configs, $is_default_set, $default ) {
|
||||
foreach ( $transformer_configs as $transformer_config ) {
|
||||
if ( ! isset( $transformer_config->use ) ) {
|
||||
throw new InvalidArgumentException( 'Missing required config value: use' );
|
||||
}
|
||||
|
||||
if ( ! isset( $transformer_config->arguments ) ) {
|
||||
$transformer_config->arguments = null;
|
||||
}
|
||||
|
||||
$transformer = self::create_transformer( $transformer_config->use );
|
||||
if ( null === $transformer ) {
|
||||
throw new InvalidArgumentException( "Unable to find a transformer by name: {$transformer_config->use}" );
|
||||
}
|
||||
|
||||
$target_value = $transformer->transform( $target_value, $transformer_config->arguments, $is_default_set ? $default : null );
|
||||
|
||||
// Break early when there's no more value to traverse.
|
||||
if ( null === $target_value ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $is_default_set ) {
|
||||
// Nulls always return the default value.
|
||||
if ( null === $target_value ) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
// When type of the default value is different from the target value, return the default value
|
||||
// to ensure type safety.
|
||||
if ( gettype( $default ) !== gettype( $target_value ) ) {
|
||||
return $default;
|
||||
}
|
||||
}
|
||||
|
||||
return $target_value;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -2,55 +2,27 @@
|
|||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications\Transformers;
|
||||
|
||||
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\TransformerInterface;
|
||||
use InvalidArgumentException;
|
||||
use stdClass;
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Search array value by one of its key.
|
||||
*
|
||||
* @package Automattic\WooCommerce\Admin\RemoteInboxNotifications\Transformers
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class ArrayColumn implements TransformerInterface {
|
||||
class ArrayColumn extends DeprecatedClassFacade {
|
||||
/**
|
||||
* Search array value by one of its key.
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @param mixed $value a value to transform.
|
||||
* @param stdClass|null $arguments required arguments 'key'.
|
||||
* @param string|null $default default value.
|
||||
*
|
||||
* @throws InvalidArgumentException Throws when the required argument 'key' is missing.
|
||||
*
|
||||
* @return mixed
|
||||
* @var string
|
||||
*/
|
||||
public function transform( $value, stdClass $arguments = null, $default = array() ) {
|
||||
if ( ! is_array( $value ) ) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
return array_column( $value, $arguments->key );
|
||||
}
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\ArrayColumn';
|
||||
|
||||
/**
|
||||
* Validate Transformer arguments.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @param stdClass|null $arguments arguments to validate.
|
||||
*
|
||||
* @return mixed
|
||||
* @var string
|
||||
*/
|
||||
public function validate( stdClass $arguments = null ) {
|
||||
if ( ! isset( $arguments->key ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
null !== $arguments->key &&
|
||||
! is_string( $arguments->key ) &&
|
||||
! is_int( $arguments->key )
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -2,48 +2,27 @@
|
|||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications\Transformers;
|
||||
|
||||
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\TransformerInterface;
|
||||
use stdClass;
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Flatten nested array.
|
||||
*
|
||||
* @package Automattic\WooCommerce\Admin\RemoteInboxNotifications\Transformers
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class ArrayFlatten implements TransformerInterface {
|
||||
class ArrayFlatten extends DeprecatedClassFacade {
|
||||
/**
|
||||
* Search a given value in the array.
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @param mixed $value a value to transform.
|
||||
* @param stdClass|null $arguments arguments.
|
||||
* @param string|null $default default value.
|
||||
*
|
||||
* @return mixed|null
|
||||
* @var string
|
||||
*/
|
||||
public function transform( $value, stdClass $arguments = null, $default = array() ) {
|
||||
if ( ! is_array( $value ) ) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
$return = array();
|
||||
array_walk_recursive(
|
||||
$value,
|
||||
function( $item ) use ( &$return ) {
|
||||
$return[] = $item;
|
||||
}
|
||||
);
|
||||
|
||||
return $return;
|
||||
}
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\ArrayColumn';
|
||||
|
||||
/**
|
||||
* Validate Transformer arguments.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @param stdClass|null $arguments arguments to validate.
|
||||
*
|
||||
* @return mixed
|
||||
* @var string
|
||||
*/
|
||||
public function validate( stdClass $arguments = null ) {
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -2,40 +2,27 @@
|
|||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications\Transformers;
|
||||
|
||||
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\TransformerInterface;
|
||||
use stdClass;
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Search array value by one of its key.
|
||||
*
|
||||
* @package Automattic\WooCommerce\Admin\RemoteInboxNotifications\Transformers
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class ArrayKeys implements TransformerInterface {
|
||||
class ArrayKeys extends DeprecatedClassFacade {
|
||||
/**
|
||||
* Search array value by one of its key.
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @param mixed $value a value to transform.
|
||||
* @param stdClass|null $arguments arguments.
|
||||
* @param string|null $default default value.
|
||||
*
|
||||
* @return mixed
|
||||
* @var string
|
||||
*/
|
||||
public function transform( $value, stdClass $arguments = null, $default = array() ) {
|
||||
if ( ! is_array( $value ) ) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
return array_keys( $value );
|
||||
}
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\ArrayColumn';
|
||||
|
||||
/**
|
||||
* Validate Transformer arguments.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @param stdClass|null $arguments arguments to validate.
|
||||
*
|
||||
* @return mixed
|
||||
* @var string
|
||||
*/
|
||||
public function validate( stdClass $arguments = null ) {
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -2,52 +2,27 @@
|
|||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications\Transformers;
|
||||
|
||||
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\TransformerInterface;
|
||||
use InvalidArgumentException;
|
||||
use stdClass;
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Searches a given a given value in the array.
|
||||
*
|
||||
* @package Automattic\WooCommerce\Admin\RemoteInboxNotifications\Transformers
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class ArraySearch implements TransformerInterface {
|
||||
class ArraySearch extends DeprecatedClassFacade {
|
||||
/**
|
||||
* Search a given value in the array.
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @param mixed $value a value to transform.
|
||||
* @param stdClass|null $arguments required argument 'value'.
|
||||
* @param string|null $default default value.
|
||||
*
|
||||
* @throws InvalidArgumentException Throws when the required 'value' is missing.
|
||||
*
|
||||
* @return mixed|null
|
||||
* @var string
|
||||
*/
|
||||
public function transform( $value, stdClass $arguments = null, $default = null ) {
|
||||
if ( ! is_array( $value ) ) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
$key = array_search( $arguments->value, $value, true );
|
||||
if ( false !== $key ) {
|
||||
return $value[ $key ];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\ArrayColumn';
|
||||
|
||||
/**
|
||||
* Validate Transformer arguments.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @param stdClass|null $arguments arguments to validate.
|
||||
*
|
||||
* @return mixed
|
||||
* @var string
|
||||
*/
|
||||
public function validate( stdClass $arguments = null ) {
|
||||
if ( ! isset( $arguments->value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -2,40 +2,27 @@
|
|||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications\Transformers;
|
||||
|
||||
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\TransformerInterface;
|
||||
use stdClass;
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Search array value by one of its key.
|
||||
*
|
||||
* @package Automattic\WooCommerce\Admin\RemoteInboxNotifications\Transformers
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class ArrayValues implements TransformerInterface {
|
||||
class ArrayValues extends DeprecatedClassFacade {
|
||||
/**
|
||||
* Search array value by one of its key.
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @param mixed $value a value to transform.
|
||||
* @param stdClass|null $arguments arguments.
|
||||
* @param string|null $default default value.
|
||||
*
|
||||
* @return mixed
|
||||
* @var string
|
||||
*/
|
||||
public function transform( $value, stdClass $arguments = null, $default = array() ) {
|
||||
if ( ! is_array( $value ) ) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
return array_values( $value );
|
||||
}
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\ArrayColumn';
|
||||
|
||||
/**
|
||||
* Validate Transformer arguments.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @param stdClass|null $arguments arguments to validate.
|
||||
*
|
||||
* @return mixed
|
||||
* @var string
|
||||
*/
|
||||
public function validate( stdClass $arguments = null ) {
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -2,40 +2,27 @@
|
|||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications\Transformers;
|
||||
|
||||
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\TransformerInterface;
|
||||
use stdClass;
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Count elements in Array or Countable object.
|
||||
*
|
||||
* @package Automattic\WooCommerce\Admin\RemoteInboxNotifications\Transformers
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class Count implements TransformerInterface {
|
||||
class Count extends DeprecatedClassFacade {
|
||||
/**
|
||||
* Count elements in Array or Countable object.
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @param array|Countable $value an array to count.
|
||||
* @param stdClass|null $arguments arguments.
|
||||
* @param string|null $default default value.
|
||||
*
|
||||
* @return number
|
||||
* @var string
|
||||
*/
|
||||
public function transform( $value, stdClass $arguments = null, $default = null ) {
|
||||
if ( ! is_array( $value ) && ! $value instanceof \Countable ) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
return count( $value );
|
||||
}
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\ArrayColumn';
|
||||
|
||||
/**
|
||||
* Validate Transformer arguments.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @param stdClass|null $arguments arguments to validate.
|
||||
*
|
||||
* @return mixed
|
||||
* @var string
|
||||
*/
|
||||
public function validate( stdClass $arguments = null ) {
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -2,78 +2,27 @@
|
|||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications\Transformers;
|
||||
|
||||
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\TransformerInterface;
|
||||
use InvalidArgumentException;
|
||||
use stdClass;
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Find an array value by dot notation.
|
||||
*
|
||||
* @package Automattic\WooCommerce\Admin\RemoteInboxNotifications\Transformers
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class DotNotation implements TransformerInterface {
|
||||
class DotNotation extends DeprecatedClassFacade {
|
||||
/**
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\ArrayColumn';
|
||||
|
||||
/**
|
||||
* Find given path from the given value.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @param mixed $value a value to transform.
|
||||
* @param stdClass|null $arguments required argument 'path'.
|
||||
* @param string|null $default default value.
|
||||
*
|
||||
* @throws InvalidArgumentException Throws when the required 'path' is missing.
|
||||
*
|
||||
* @return mixed
|
||||
* @var string
|
||||
*/
|
||||
public function transform( $value, stdclass $arguments = null, $default = null ) {
|
||||
if ( is_object( $value ) ) {
|
||||
// if the value is an object, convert it to an array.
|
||||
$value = json_decode( wp_json_encode( $value ), true );
|
||||
}
|
||||
|
||||
return $this->get( $value, $arguments->path, $default );
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the given $path in $array by dot notation.
|
||||
*
|
||||
* @param array $array an array to search in.
|
||||
* @param string $path a path in the given array.
|
||||
* @param null $default default value to return if $path was not found.
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function get( $array, $path, $default = null ) {
|
||||
if ( ! is_array( $array ) ) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
if ( isset( $array[ $path ] ) ) {
|
||||
return $array[ $path ];
|
||||
}
|
||||
|
||||
foreach ( explode( '.', $path ) as $segment ) {
|
||||
if ( ! is_array( $array ) || ! array_key_exists( $segment, $array ) ) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
$array = $array[ $segment ];
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Transformer arguments.
|
||||
*
|
||||
* @param stdClass|null $arguments arguments to validate.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function validate( stdClass $arguments = null ) {
|
||||
if ( ! isset( $arguments->path ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -2,54 +2,27 @@
|
|||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications\Transformers;
|
||||
|
||||
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\TransformerInterface;
|
||||
use stdClass;
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Prepare site URL for comparison.
|
||||
*
|
||||
* @package Automattic\WooCommerce\Admin\RemoteInboxNotifications\Transformers
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class PrepareUrl implements TransformerInterface {
|
||||
class PrepareUrl extends DeprecatedClassFacade {
|
||||
/**
|
||||
* Prepares the site URL by removing the protocol and trailing slash.
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @param string $value a value to transform.
|
||||
* @param stdClass|null $arguments arguments.
|
||||
* @param string|null $default default value.
|
||||
*
|
||||
* @return mixed|null
|
||||
* @var string
|
||||
*/
|
||||
public function transform( $value, stdClass $arguments = null, $default = null ) {
|
||||
if ( ! is_string( $value ) ) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
$url_parts = wp_parse_url( rtrim( $value, '/' ) );
|
||||
|
||||
if ( ! $url_parts ) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
if ( ! isset( $url_parts['host'] ) ) {
|
||||
return $default;
|
||||
}
|
||||
|
||||
if ( isset( $url_parts['path'] ) ) {
|
||||
return $url_parts['host'] . $url_parts['path'];
|
||||
}
|
||||
|
||||
return $url_parts['host'];
|
||||
}
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\ArrayColumn';
|
||||
|
||||
/**
|
||||
* Validate Transformer arguments.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @param stdClass|null $arguments arguments to validate.
|
||||
*
|
||||
* @return mixed
|
||||
* @var string
|
||||
*/
|
||||
public function validate( stdClass $arguments = null ) {
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -5,20 +5,27 @@
|
|||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
||||
|
||||
use Automattic\WooCommerce\Admin\WCAdminHelper;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* WCAdminActiveForProvider class
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class WCAdminActiveForProvider {
|
||||
class WCAdminActiveForProvider extends DeprecatedClassFacade {
|
||||
/**
|
||||
* Get the number of seconds that the store has been active.
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @return number Number of seconds.
|
||||
* @var string
|
||||
*/
|
||||
public function get_wcadmin_active_for_in_seconds() {
|
||||
return WCAdminHelper::get_wcadmin_active_for_in_seconds();
|
||||
}
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\WCAdminActiveForProvider';
|
||||
|
||||
/**
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -8,72 +8,26 @@ namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Rule processor for publishing if wc-admin has been active for at least the
|
||||
* given number of seconds.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class WCAdminActiveForRuleProcessor implements RuleProcessorInterface {
|
||||
class WCAdminActiveForRuleProcessor extends DeprecatedClassFacade {
|
||||
/**
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\WCAdminActiveForRuleProcessor';
|
||||
|
||||
/**
|
||||
* Provides the amount of time wcadmin has been active for.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @var WCAdminActiveForProvider
|
||||
* @var string
|
||||
*/
|
||||
protected $wcadmin_active_for_provider;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param object $wcadmin_active_for_provider Provides the amount of time wcadmin has been active for.
|
||||
*/
|
||||
public function __construct( $wcadmin_active_for_provider = null ) {
|
||||
$this->wcadmin_active_for_provider = null === $wcadmin_active_for_provider
|
||||
? new WCAdminActiveForProvider()
|
||||
: $wcadmin_active_for_provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a comparison operation against the amount of time wc-admin has
|
||||
* been active for in days.
|
||||
*
|
||||
* @param object $rule The rule being processed.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
$active_for_seconds = $this->wcadmin_active_for_provider->get_wcadmin_active_for_in_seconds();
|
||||
|
||||
if ( ! $active_for_seconds || ! is_numeric( $active_for_seconds ) || $active_for_seconds < 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$rule_seconds = $rule->days * DAY_IN_SECONDS;
|
||||
|
||||
return ComparisonOperation::compare(
|
||||
$active_for_seconds,
|
||||
$rule_seconds,
|
||||
$rule->operation
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
// Ensure that 'days' property is set and is a valid numeric value.
|
||||
if ( ! isset( $rule->days ) || ! is_numeric( $rule->days ) || $rule->days < 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->operation ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -7,30 +7,25 @@ namespace Automattic\WooCommerce\Admin\RemoteInboxNotifications;
|
|||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DeprecatedClassFacade;
|
||||
|
||||
/**
|
||||
* Rule processor for sending when WooCommerce Admin has been updated.
|
||||
*
|
||||
* @deprecated 8.8.0
|
||||
*/
|
||||
class WooCommerceAdminUpdatedRuleProcessor implements RuleProcessorInterface {
|
||||
class WooCommerceAdminUpdatedRuleProcessor extends DeprecatedClassFacade {
|
||||
/**
|
||||
* Process the rule.
|
||||
* The name of the non-deprecated class that this facade covers.
|
||||
*
|
||||
* @param object $rule The specific rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool Whether the rule passes or not.
|
||||
* @var string
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
return get_option( RemoteInboxNotificationsEngine::WCA_UPDATED_OPTION_NAME, false );
|
||||
}
|
||||
protected static $facade_over_classname = 'Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\WooCommerceAdminUpdatedRuleProcessor';
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
* The version that this class was deprecated in.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
* @var string
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
return true;
|
||||
}
|
||||
protected static $deprecated_in_version = '8.8.0';
|
||||
}
|
||||
|
|
|
@ -0,0 +1,288 @@
|
|||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs;
|
||||
|
||||
/**
|
||||
* Specs data source poller class.
|
||||
* This handles polling specs from JSON endpoints, and
|
||||
* stores the specs in to the database as an option.
|
||||
*/
|
||||
abstract class DataSourcePoller {
|
||||
|
||||
/**
|
||||
* Get class instance.
|
||||
*/
|
||||
abstract public static function get_instance();
|
||||
|
||||
/**
|
||||
* Name of data sources filter.
|
||||
*/
|
||||
const FILTER_NAME = 'data_source_poller_data_sources';
|
||||
|
||||
/**
|
||||
* Name of data source specs filter.
|
||||
*/
|
||||
const FILTER_NAME_SPECS = 'data_source_poller_specs';
|
||||
|
||||
/**
|
||||
* Id of DataSourcePoller.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $id = array();
|
||||
|
||||
/**
|
||||
* Default data sources array.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $data_sources = array();
|
||||
|
||||
/**
|
||||
* Default args.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $args = array();
|
||||
|
||||
/**
|
||||
* The logger instance.
|
||||
*
|
||||
* @var WC_Logger|null
|
||||
*/
|
||||
protected static $logger = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $id id of DataSourcePoller.
|
||||
* @param array $data_sources urls for data sources.
|
||||
* @param array $args Options for DataSourcePoller.
|
||||
*/
|
||||
public function __construct( $id, $data_sources = array(), $args = array() ) {
|
||||
$this->data_sources = $data_sources;
|
||||
$this->id = $id;
|
||||
|
||||
$arg_defaults = array(
|
||||
'spec_key' => 'id',
|
||||
'transient_name' => 'woocommerce_admin_' . $id . '_specs',
|
||||
'transient_expiry' => 7 * DAY_IN_SECONDS,
|
||||
);
|
||||
$this->args = wp_parse_args( $args, $arg_defaults );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the logger instance.
|
||||
*
|
||||
* @return WC_Logger
|
||||
*/
|
||||
protected static function get_logger() {
|
||||
if ( is_null( self::$logger ) ) {
|
||||
self::$logger = wc_get_logger();
|
||||
}
|
||||
|
||||
return self::$logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the key identifier of spec, this can easily be overwritten. Defaults to id.
|
||||
*
|
||||
* @param mixed $spec a JSON parsed spec coming from the JSON feed.
|
||||
* @return string|boolean
|
||||
*/
|
||||
protected function get_spec_key( $spec ) {
|
||||
$key = $this->args['spec_key'];
|
||||
if ( isset( $spec->$key ) ) {
|
||||
return $spec->$key;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the data sources for specs and persists those specs.
|
||||
*
|
||||
* @return array list of specs.
|
||||
*/
|
||||
public function get_specs_from_data_sources() {
|
||||
$locale = get_user_locale();
|
||||
$specs_group = get_transient( $this->args['transient_name'] ) ?? array();
|
||||
$specs = isset( $specs_group[ $locale ] ) ? $specs_group[ $locale ] : array();
|
||||
|
||||
if ( ! is_array( $specs ) || empty( $specs ) ) {
|
||||
$this->read_specs_from_data_sources();
|
||||
$specs_group = get_transient( $this->args['transient_name'] );
|
||||
$specs = isset( $specs_group[ $locale ] ) ? $specs_group[ $locale ] : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter specs.
|
||||
*
|
||||
* @param array $specs List of specs.
|
||||
* @param string $this->id Spec identifier.
|
||||
*
|
||||
* @since 8.8.0
|
||||
*/
|
||||
$specs = apply_filters( self::FILTER_NAME_SPECS, $specs, $this->id );
|
||||
return false !== $specs ? $specs : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the data sources for specs and persists those specs.
|
||||
*
|
||||
* @return bool Whether any specs were read.
|
||||
*/
|
||||
public function read_specs_from_data_sources() {
|
||||
$specs = array();
|
||||
|
||||
/**
|
||||
* Filter data sources.
|
||||
*
|
||||
* @param array $this->data_sources List of data sources.
|
||||
* @param string $this->id Spec identifier.
|
||||
*
|
||||
* @since 8.8.0
|
||||
*/
|
||||
$data_sources = apply_filters( self::FILTER_NAME, $this->data_sources, $this->id );
|
||||
|
||||
// Note that this merges the specs from the data sources based on the
|
||||
// id - last one wins.
|
||||
foreach ( $data_sources as $url ) {
|
||||
$specs_from_data_source = self::read_data_source( $url );
|
||||
$this->merge_specs( $specs_from_data_source, $specs, $url );
|
||||
}
|
||||
|
||||
$specs_group = get_transient( $this->args['transient_name'] );
|
||||
$specs_group = is_array( $specs_group ) ? $specs_group : array();
|
||||
$locale = get_user_locale();
|
||||
$specs_group[ $locale ] = $specs;
|
||||
// Persist the specs as a transient.
|
||||
$this->set_specs_transient(
|
||||
$specs_group,
|
||||
$this->args['transient_expiry']
|
||||
);
|
||||
return count( $specs ) !== 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the specs transient.
|
||||
*
|
||||
* @return bool success of failure of transient deletion.
|
||||
*/
|
||||
public function delete_specs_transient() {
|
||||
return delete_transient( $this->args['transient_name'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the specs transient.
|
||||
*
|
||||
* @param array $specs The specs to set in the transient.
|
||||
* @param int $expiration The expiration time for the transient.
|
||||
*/
|
||||
public function set_specs_transient( $specs, $expiration = 0 ) {
|
||||
set_transient(
|
||||
$this->args['transient_name'],
|
||||
$specs,
|
||||
$expiration,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a single data source and return the read specs
|
||||
*
|
||||
* @param string $url The URL to read the specs from.
|
||||
*
|
||||
* @return array The specs that have been read from the data source.
|
||||
*/
|
||||
protected static function read_data_source( $url ) {
|
||||
$logger_context = array( 'source' => $url );
|
||||
$logger = self::get_logger();
|
||||
$response = wp_remote_get(
|
||||
add_query_arg(
|
||||
'locale',
|
||||
get_user_locale(),
|
||||
$url
|
||||
),
|
||||
array(
|
||||
'user-agent' => 'WooCommerce/' . WC_VERSION . '; ' . home_url( '/' ),
|
||||
)
|
||||
);
|
||||
|
||||
if ( is_wp_error( $response ) || ! isset( $response['body'] ) ) {
|
||||
$logger->error(
|
||||
'Error getting data feed',
|
||||
$logger_context
|
||||
);
|
||||
// phpcs:ignore
|
||||
$logger->error( print_r( $response, true ), $logger_context );
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
$body = $response['body'];
|
||||
$specs = json_decode( $body );
|
||||
|
||||
if ( null === $specs ) {
|
||||
$logger->error(
|
||||
'Empty response in data feed',
|
||||
$logger_context
|
||||
);
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
if ( ! is_array( $specs ) ) {
|
||||
$logger->error(
|
||||
'Data feed is not an array',
|
||||
$logger_context
|
||||
);
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
return $specs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge the specs.
|
||||
*
|
||||
* @param Array $specs_to_merge_in The specs to merge in to $specs.
|
||||
* @param Array $specs The list of specs being merged into.
|
||||
* @param string $url The url of the feed being merged in (for error reporting).
|
||||
*/
|
||||
protected function merge_specs( $specs_to_merge_in, &$specs, $url ) {
|
||||
foreach ( $specs_to_merge_in as $spec ) {
|
||||
if ( ! $this->validate_spec( $spec, $url ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$id = $this->get_spec_key( $spec );
|
||||
$specs[ $id ] = $spec;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the spec.
|
||||
*
|
||||
* @param object $spec The spec to validate.
|
||||
* @param string $url The url of the feed that provided the spec.
|
||||
*
|
||||
* @return bool The result of the validation.
|
||||
*/
|
||||
protected function validate_spec( $spec, $url ) {
|
||||
$logger = self::get_logger();
|
||||
$logger_context = array( 'source' => $url );
|
||||
|
||||
if ( ! $this->get_spec_key( $spec ) ) {
|
||||
$logger->error(
|
||||
'Spec is invalid because the id is missing in feed',
|
||||
$logger_context
|
||||
);
|
||||
// phpcs:ignore
|
||||
$logger->error( print_r( $spec, true ), $logger_context );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
/**
|
||||
* Rule processor that performs a comparison operation against the base
|
||||
* location - country.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Rule processor that performs a comparison operation against the base
|
||||
* location - country.
|
||||
*/
|
||||
class BaseLocationCountryRuleProcessor implements RuleProcessorInterface {
|
||||
/**
|
||||
* Performs a comparison operation against the base location - country.
|
||||
*
|
||||
* @param object $rule The specific rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
$base_location = wc_get_base_location();
|
||||
if (
|
||||
! is_array( $base_location ) ||
|
||||
! array_key_exists( 'country', $base_location ) ||
|
||||
! array_key_exists( 'state', $base_location )
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$onboarding_profile = get_option( 'woocommerce_onboarding_profile', array() );
|
||||
$is_address_default = 'US' === $base_location['country'] && 'CA' === $base_location['state'] && empty( get_option( 'woocommerce_store_address', '' ) );
|
||||
$is_store_country_set = isset( $onboarding_profile['is_store_country_set'] ) && $onboarding_profile['is_store_country_set'];
|
||||
|
||||
// Return false if the location is the default country and if onboarding hasn't been finished or the store address not been updated.
|
||||
if ( $is_address_default && OnboardingProfile::needs_completion() && ! $is_store_country_set ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ComparisonOperation::compare(
|
||||
$base_location['country'],
|
||||
$rule->value,
|
||||
$rule->operation
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->operation ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
/**
|
||||
* Rule processor that performs a comparison operation against the base
|
||||
* location - state.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Rule processor that performs a comparison operation against the base
|
||||
* location - state.
|
||||
*/
|
||||
class BaseLocationStateRuleProcessor implements RuleProcessorInterface {
|
||||
/**
|
||||
* Performs a comparison operation against the base location - state.
|
||||
*
|
||||
* @param object $rule The specific rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
$base_location = wc_get_base_location();
|
||||
if ( ! is_array( $base_location ) || ! array_key_exists( 'state', $base_location ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ComparisonOperation::compare(
|
||||
$base_location['state'],
|
||||
$rule->value,
|
||||
$rule->operation
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->operation ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
/**
|
||||
* Compare two operands using the specified operation.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Compare two operands using the specified operation.
|
||||
*/
|
||||
class ComparisonOperation {
|
||||
/**
|
||||
* Compare two operands using the specified operation.
|
||||
*
|
||||
* @param object $left_operand The left hand operand.
|
||||
* @param object $right_operand The right hand operand -- 'value' from the rule definition.
|
||||
* @param string $operation The operation used to compare the operands.
|
||||
*/
|
||||
public static function compare( $left_operand, $right_operand, $operation ) {
|
||||
switch ( $operation ) {
|
||||
case '=':
|
||||
return $left_operand === $right_operand;
|
||||
case '<':
|
||||
return $left_operand < $right_operand;
|
||||
case '<=':
|
||||
return $left_operand <= $right_operand;
|
||||
case '>':
|
||||
return $left_operand > $right_operand;
|
||||
case '>=':
|
||||
return $left_operand >= $right_operand;
|
||||
case '!=':
|
||||
return $left_operand !== $right_operand;
|
||||
case 'contains':
|
||||
if ( is_array( $left_operand ) && is_string( $right_operand ) ) {
|
||||
return in_array( $right_operand, $left_operand, true );
|
||||
}
|
||||
if ( is_string( $right_operand ) && is_string( $left_operand ) ) {
|
||||
return strpos( $right_operand, $left_operand ) !== false;
|
||||
}
|
||||
break;
|
||||
case '!contains':
|
||||
if ( is_array( $left_operand ) && is_string( $right_operand ) ) {
|
||||
return ! in_array( $right_operand, $left_operand, true );
|
||||
}
|
||||
if ( is_string( $right_operand ) && is_string( $left_operand ) ) {
|
||||
return strpos( $right_operand, $left_operand ) === false;
|
||||
}
|
||||
break;
|
||||
case 'in':
|
||||
if ( is_array( $right_operand ) && is_string( $left_operand ) ) {
|
||||
return in_array( $left_operand, $right_operand, true );
|
||||
}
|
||||
if ( is_string( $left_operand ) && is_string( $right_operand ) ) {
|
||||
return strpos( $left_operand, $right_operand ) !== false;
|
||||
}
|
||||
break;
|
||||
case '!in':
|
||||
if ( is_array( $right_operand ) && is_string( $left_operand ) ) {
|
||||
return ! in_array( $left_operand, $right_operand, true );
|
||||
}
|
||||
if ( is_string( $left_operand ) && is_string( $right_operand ) ) {
|
||||
return strpos( $left_operand, $right_operand ) === false;
|
||||
}
|
||||
break;
|
||||
case 'range':
|
||||
if ( ! is_array( $right_operand ) || count( $right_operand ) !== 2 ) {
|
||||
return false;
|
||||
}
|
||||
return $left_operand >= $right_operand[0] && $left_operand <= $right_operand[1];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
/**
|
||||
* Evaluates the spec and returns a status.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\Notes\Note;
|
||||
|
||||
/**
|
||||
* Evaluates the spec and returns a status.
|
||||
*/
|
||||
class EvaluateAndGetStatus {
|
||||
/**
|
||||
* Evaluates the spec and returns a status.
|
||||
*
|
||||
* @param array $spec The spec to evaluate.
|
||||
* @param string $current_status The note's current status.
|
||||
* @param object $stored_state Stored state.
|
||||
* @param object $rule_evaluator Evaluates rules into true/false.
|
||||
*
|
||||
* @return string The evaluated status.
|
||||
*/
|
||||
public static function evaluate( $spec, $current_status, $stored_state, $rule_evaluator ) {
|
||||
// No rules should leave the note alone.
|
||||
if ( ! isset( $spec->rules ) ) {
|
||||
return $current_status;
|
||||
}
|
||||
|
||||
$evaluated_result = $rule_evaluator->evaluate(
|
||||
$spec->rules,
|
||||
$stored_state,
|
||||
array(
|
||||
'slug' => $spec->slug,
|
||||
'source' => 'remote-inbox-notifications',
|
||||
)
|
||||
);
|
||||
|
||||
// Pending notes should be the spec status if the spec passes,
|
||||
// left alone otherwise.
|
||||
if ( Note::E_WC_ADMIN_NOTE_PENDING === $current_status ) {
|
||||
return $evaluated_result
|
||||
? $spec->status
|
||||
: Note::E_WC_ADMIN_NOTE_PENDING;
|
||||
}
|
||||
|
||||
// When allow_redisplay isn't set, just leave the note alone.
|
||||
if ( ! isset( $spec->allow_redisplay ) || ! $spec->allow_redisplay ) {
|
||||
return $current_status;
|
||||
}
|
||||
|
||||
// allow_redisplay is set, unaction the note if eval to true.
|
||||
return $evaluated_result
|
||||
? Note::E_WC_ADMIN_NOTE_UNACTIONED
|
||||
: $current_status;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
/**
|
||||
* Class EvaluationLogger
|
||||
*
|
||||
* @package Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors
|
||||
*/
|
||||
class EvaluationLogger {
|
||||
/**
|
||||
* Slug of the spec.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $slug;
|
||||
|
||||
/**
|
||||
* Results of rules in the given spec.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $results = array();
|
||||
|
||||
/**
|
||||
* Logger class to use.
|
||||
*
|
||||
* @var WC_Logger_Interface|null
|
||||
*/
|
||||
private $logger;
|
||||
|
||||
/**
|
||||
* Logger source.
|
||||
*
|
||||
* @var string logger source.
|
||||
*/
|
||||
private $source = '';
|
||||
|
||||
/**
|
||||
* EvaluationLogger constructor.
|
||||
*
|
||||
* @param string $slug Slug of a spec that is being evaluated.
|
||||
* @param null $source Logger source.
|
||||
* @param \WC_Logger_Interface $logger Logger class to use.
|
||||
*/
|
||||
public function __construct( $slug, $source = null, \WC_Logger_Interface $logger = null ) {
|
||||
$this->slug = $slug;
|
||||
if ( null === $logger ) {
|
||||
$logger = wc_get_logger();
|
||||
}
|
||||
|
||||
if ( $source ) {
|
||||
$this->source = $source;
|
||||
}
|
||||
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add evaluation result of a rule.
|
||||
*
|
||||
* @param string $rule_type name of the rule being tested.
|
||||
* @param boolean $result result of a given rule.
|
||||
*/
|
||||
public function add_result( $rule_type, $result ) {
|
||||
array_push(
|
||||
$this->results,
|
||||
array(
|
||||
'rule' => $rule_type,
|
||||
'result' => $result ? 'passed' : 'failed',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log the results.
|
||||
*/
|
||||
public function log() {
|
||||
if ( false === defined( 'WC_ADMIN_DEBUG_RULE_EVALUATOR' ) || true !== constant( 'WC_ADMIN_DEBUG_RULE_EVALUATOR' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $this->results as $result ) {
|
||||
$this->logger->debug(
|
||||
"[{$this->slug}] {$result['rule']}: {$result['result']}",
|
||||
array( 'source' => $this->source )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
/**
|
||||
* Rule processor that fails.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Rule processor that fails.
|
||||
*/
|
||||
class FailRuleProcessor implements RuleProcessorInterface {
|
||||
/**
|
||||
* Fails the rule.
|
||||
*
|
||||
* @param object $rule The specific rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool Always false.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
/**
|
||||
* Gets the processor for the specified rule type.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Class encapsulating getting the processor for a given rule type.
|
||||
*/
|
||||
class GetRuleProcessor {
|
||||
/**
|
||||
* Get the processor for the specified rule type.
|
||||
*
|
||||
* @param string $rule_type The rule type.
|
||||
*
|
||||
* @return RuleProcessorInterface The matching processor for the specified rule type, or a FailRuleProcessor if no matching processor is found.
|
||||
*/
|
||||
public static function get_processor( $rule_type ) {
|
||||
switch ( $rule_type ) {
|
||||
case 'plugins_activated':
|
||||
return new PluginsActivatedRuleProcessor();
|
||||
case 'publish_after_time':
|
||||
return new PublishAfterTimeRuleProcessor();
|
||||
case 'publish_before_time':
|
||||
return new PublishBeforeTimeRuleProcessor();
|
||||
case 'not':
|
||||
return new NotRuleProcessor();
|
||||
case 'or':
|
||||
return new OrRuleProcessor();
|
||||
case 'fail':
|
||||
return new FailRuleProcessor();
|
||||
case 'pass':
|
||||
return new PassRuleProcessor();
|
||||
case 'plugin_version':
|
||||
return new PluginVersionRuleProcessor();
|
||||
case 'stored_state':
|
||||
return new StoredStateRuleProcessor();
|
||||
case 'order_count':
|
||||
return new OrderCountRuleProcessor();
|
||||
case 'wcadmin_active_for':
|
||||
return new WCAdminActiveForRuleProcessor();
|
||||
case 'product_count':
|
||||
return new ProductCountRuleProcessor();
|
||||
case 'onboarding_profile':
|
||||
return new OnboardingProfileRuleProcessor();
|
||||
case 'is_ecommerce':
|
||||
return new IsEcommerceRuleProcessor();
|
||||
case 'is_woo_express':
|
||||
return new IsWooExpressRuleProcessor();
|
||||
case 'base_location_country':
|
||||
return new BaseLocationCountryRuleProcessor();
|
||||
case 'base_location_state':
|
||||
return new BaseLocationStateRuleProcessor();
|
||||
case 'note_status':
|
||||
return new NoteStatusRuleProcessor();
|
||||
case 'option':
|
||||
return new OptionRuleProcessor();
|
||||
case 'wca_updated':
|
||||
return new WooCommerceAdminUpdatedRuleProcessor();
|
||||
case 'total_payments_value':
|
||||
return new TotalPaymentsVolumeProcessor();
|
||||
}
|
||||
|
||||
return new FailRuleProcessor();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
/**
|
||||
* Rule processor that passes (or fails) when the site is on the eCommerce
|
||||
* plan.
|
||||
*
|
||||
* @package WooCommerce\Admin\Classes
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Rule processor that passes (or fails) when the site is on the eCommerce
|
||||
* plan.
|
||||
*/
|
||||
class IsEcommerceRuleProcessor implements RuleProcessorInterface {
|
||||
/**
|
||||
* Passes (or fails) based on whether the site is on the eCommerce plan or
|
||||
* not.
|
||||
*
|
||||
* @param object $rule The rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
if ( ! function_exists( 'wc_calypso_bridge_is_ecommerce_plan' ) ) {
|
||||
return false === $rule->value;
|
||||
}
|
||||
|
||||
return (bool) wc_calypso_bridge_is_ecommerce_plan() === $rule->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
/**
|
||||
* Rule processor that passes (or fails) when the site is on a Woo Express plan.
|
||||
*
|
||||
* @package WooCommerce\Admin\Classes
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Rule processor that passes (or fails) when the site is on a Woo Express plan.
|
||||
* You may optionally pass a plan name to target a specific Woo Express plan.
|
||||
*/
|
||||
class IsWooExpressRuleProcessor implements RuleProcessorInterface {
|
||||
/**
|
||||
* Passes (or fails) based on whether the site is a Woo Express plan.
|
||||
*
|
||||
* @param object $rule The rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
if ( ! function_exists( 'wc_calypso_bridge_is_woo_express_plan' ) ) {
|
||||
return false === $rule->value;
|
||||
}
|
||||
|
||||
// If the plan is undefined, only check if it's a Woo Express plan.
|
||||
if ( ! isset( $rule->plan ) ) {
|
||||
return wc_calypso_bridge_is_woo_express_plan() === $rule->value;
|
||||
}
|
||||
|
||||
// If a plan name is defined, only evaluate the plan if we're on the Woo Express plan.
|
||||
if ( wc_calypso_bridge_is_woo_express_plan() ) {
|
||||
$fn = 'wc_calypso_bridge_is_woo_express_' . (string) $rule->plan . '_plan';
|
||||
if ( function_exists( $fn ) ) {
|
||||
return $fn() === $rule->value;
|
||||
}
|
||||
|
||||
// If an invalid plan name is given, only evaluate the rule if we're targeting all plans other than the specified (invalid) one.
|
||||
return false === $rule->value;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( isset( $rule->plan ) ) {
|
||||
if ( ! function_exists( 'wc_calypso_bridge_is_woo_express_plan' ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
/**
|
||||
* Rule processor that negates the rules in the rule's operand.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Rule processor that negates the rules in the rule's operand.
|
||||
*/
|
||||
class NotRuleProcessor implements RuleProcessorInterface {
|
||||
|
||||
/**
|
||||
* The rule evaluator to use.
|
||||
*
|
||||
* @var RuleEvaluator
|
||||
*/
|
||||
protected $rule_evaluator;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param RuleEvaluator $rule_evaluator The rule evaluator to use.
|
||||
*/
|
||||
public function __construct( $rule_evaluator = null ) {
|
||||
$this->rule_evaluator = null === $rule_evaluator
|
||||
? new RuleEvaluator()
|
||||
: $rule_evaluator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluates the rules in the operand and negates the result.
|
||||
*
|
||||
* @param object $rule The specific rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
$evaluated_operand = $this->rule_evaluator->evaluate(
|
||||
$rule->operand,
|
||||
$stored_state
|
||||
);
|
||||
|
||||
return ! $evaluated_operand;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->operand ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
<?php
|
||||
/**
|
||||
* Rule processor that compares against the status of another note. For
|
||||
* example, this could be used to conditionally create a note only if another
|
||||
* note has not been actioned.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\Notes\Notes;
|
||||
|
||||
/**
|
||||
* Rule processor that compares against the status of another note.
|
||||
*/
|
||||
class NoteStatusRuleProcessor implements RuleProcessorInterface {
|
||||
/**
|
||||
* Compare against the status of another note.
|
||||
*
|
||||
* @param object $rule The rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
$status = Notes::get_note_status( $rule->note_name );
|
||||
if ( ! $status ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ComparisonOperation::compare(
|
||||
$status,
|
||||
$rule->status,
|
||||
$rule->operation
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->note_name ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->status ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->operation ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
/**
|
||||
* Rule processor that performs a comparison operation against a value in the
|
||||
* onboarding profile.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Rule processor that performs a comparison operation against a value in the
|
||||
* onboarding profile.
|
||||
*/
|
||||
class OnboardingProfileRuleProcessor implements RuleProcessorInterface {
|
||||
/**
|
||||
* Performs a comparison operation against a value in the onboarding
|
||||
* profile.
|
||||
*
|
||||
* @param object $rule The rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
$onboarding_profile = get_option( 'woocommerce_onboarding_profile' );
|
||||
|
||||
if ( empty( $onboarding_profile ) || ! is_array( $onboarding_profile ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $onboarding_profile[ $rule->index ] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ComparisonOperation::compare(
|
||||
$onboarding_profile[ $rule->index ],
|
||||
$rule->value,
|
||||
$rule->operation
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->index ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->operation ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
/**
|
||||
* Rule processor that performs a comparison operation against an option value.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\TransformerService;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Rule processor that performs a comparison operation against an option value.
|
||||
*/
|
||||
class OptionRuleProcessor implements RuleProcessorInterface {
|
||||
/**
|
||||
* Performs a comparison operation against the option value.
|
||||
*
|
||||
* @param object $rule The specific rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
$is_contains = $rule->operation && strpos( $rule->operation, 'contains' ) !== false;
|
||||
$value_when_default_not_provided = $is_contains ? array() : false;
|
||||
$is_default_set = property_exists( $rule, 'default' );
|
||||
$default_value = $is_default_set ? $rule->default : $value_when_default_not_provided;
|
||||
$option_value = $this->get_option_value( $rule, $default_value, $is_contains );
|
||||
|
||||
if ( isset( $rule->transformers ) && is_array( $rule->transformers ) ) {
|
||||
$option_value = TransformerService::apply( $option_value, $rule->transformers, $is_default_set, $default_value );
|
||||
}
|
||||
|
||||
return ComparisonOperation::compare(
|
||||
$option_value,
|
||||
$rule->value,
|
||||
$rule->operation
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the option value and handles logging if necessary.
|
||||
*
|
||||
* @param object $rule The specific rule being processed.
|
||||
* @param mixed $default_value The default value.
|
||||
* @param bool $is_contains Indicates whether the operation is "contains".
|
||||
*
|
||||
* @return mixed The option value.
|
||||
*/
|
||||
private function get_option_value( $rule, $default_value, $is_contains ) {
|
||||
$option_value = get_option( $rule->option_name, $default_value );
|
||||
$is_contains_valid = $is_contains && ( is_array( $option_value ) || ( is_string( $option_value ) && is_string( $rule->value ) ) );
|
||||
|
||||
if ( $is_contains && ! $is_contains_valid ) {
|
||||
$logger = wc_get_logger();
|
||||
$logger->warning(
|
||||
sprintf(
|
||||
'ComparisonOperation "%s" option value "%s" is not an array, defaulting to empty array.',
|
||||
$rule->operation,
|
||||
$rule->option_name
|
||||
),
|
||||
array(
|
||||
'option_value' => $option_value,
|
||||
'rule' => $rule,
|
||||
)
|
||||
);
|
||||
$option_value = array();
|
||||
}
|
||||
|
||||
return $option_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->option_name ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->operation ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( isset( $rule->transformers ) && is_array( $rule->transformers ) ) {
|
||||
foreach ( $rule->transformers as $transform_args ) {
|
||||
$transformer = TransformerService::create_transformer( $transform_args->use );
|
||||
if ( ! $transformer->validate( $transform_args->arguments ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
/**
|
||||
* Rule processor that performs an OR operation on the rule's left and right
|
||||
* operands.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Rule processor that performs an OR operation on the rule's left and right
|
||||
* operands.
|
||||
*/
|
||||
class OrRuleProcessor implements RuleProcessorInterface {
|
||||
|
||||
/**
|
||||
* Rule evaluator to use.
|
||||
*
|
||||
* @var RuleEvaluator
|
||||
*/
|
||||
private $rule_evaluator;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param RuleEvaluator $rule_evaluator The rule evaluator to use.
|
||||
*/
|
||||
public function __construct( $rule_evaluator = null ) {
|
||||
$this->rule_evaluator = null === $rule_evaluator
|
||||
? new RuleEvaluator()
|
||||
: $rule_evaluator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs an OR operation on the rule's left and right operands.
|
||||
*
|
||||
* @param object $rule The specific rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
foreach ( $rule->operands as $operand ) {
|
||||
$evaluated_operand = $this->rule_evaluator->evaluate(
|
||||
$operand,
|
||||
$stored_state
|
||||
);
|
||||
|
||||
if ( $evaluated_operand ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->operands ) || ! is_array( $rule->operands ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
/**
|
||||
* Rule processor for publishing based on the number of orders.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Rule processor for publishing based on the number of orders.
|
||||
*/
|
||||
class OrderCountRuleProcessor implements RuleProcessorInterface {
|
||||
|
||||
/**
|
||||
* The orders provider.
|
||||
*
|
||||
* @var OrdersProvider
|
||||
*/
|
||||
protected $orders_provider;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param object $orders_provider The orders provider.
|
||||
*/
|
||||
public function __construct( $orders_provider = null ) {
|
||||
$this->orders_provider = null === $orders_provider
|
||||
? new OrdersProvider()
|
||||
: $orders_provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the rule.
|
||||
*
|
||||
* @param object $rule The rule to process.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool Whether the rule passes or not.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
$count = $this->orders_provider->get_order_count();
|
||||
|
||||
return ComparisonOperation::compare(
|
||||
$count,
|
||||
$rule->value,
|
||||
$rule->operation
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->operation ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
/**
|
||||
* Provider for order-related queries and operations.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Provider for order-related queries and operations.
|
||||
*/
|
||||
class OrdersProvider {
|
||||
/**
|
||||
* Allowed order statuses for calculating milestones.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $allowed_statuses = array(
|
||||
'pending',
|
||||
'processing',
|
||||
'completed',
|
||||
);
|
||||
|
||||
/**
|
||||
* Returns the number of orders.
|
||||
*
|
||||
* @return integer The number of orders.
|
||||
*/
|
||||
public function get_order_count() {
|
||||
$status_counts = array_map( 'wc_orders_count', $this->allowed_statuses );
|
||||
$orders_count = array_sum( $status_counts );
|
||||
|
||||
return $orders_count;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
/**
|
||||
* Rule processor that passes. This is required because an empty set of rules
|
||||
* (or predicate) evaluates to false.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Rule processor that passes.
|
||||
*/
|
||||
class PassRuleProcessor implements RuleProcessorInterface {
|
||||
/**
|
||||
* Passes the rule.
|
||||
*
|
||||
* @param object $rule The specific rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool Always true.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
/**
|
||||
* Rule processor for sending when the provided plugin is activated and
|
||||
* matches the specified version.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\PluginsProvider\PluginsProvider;
|
||||
|
||||
/**
|
||||
* Rule processor for sending when the provided plugin is activated and
|
||||
* matches the specified version.
|
||||
*/
|
||||
class PluginVersionRuleProcessor implements RuleProcessorInterface {
|
||||
|
||||
/**
|
||||
* Plugins provider instance.
|
||||
*
|
||||
* @var PluginsProviderInterface
|
||||
*/
|
||||
private $plugins_provider;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param PluginsProviderInterface $plugins_provider The plugins provider.
|
||||
*/
|
||||
public function __construct( $plugins_provider = null ) {
|
||||
$this->plugins_provider = null === $plugins_provider
|
||||
? new PluginsProvider()
|
||||
: $plugins_provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the rule.
|
||||
*
|
||||
* @param object $rule The specific rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool Whether the rule passes or not.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
$active_plugin_slugs = $this->plugins_provider->get_active_plugin_slugs();
|
||||
|
||||
if ( ! in_array( $rule->plugin, $active_plugin_slugs, true ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$plugin_data = $this->plugins_provider->get_plugin_data( $rule->plugin );
|
||||
|
||||
if ( ! is_array( $plugin_data ) || ! array_key_exists( 'Version', $plugin_data ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$plugin_version = $plugin_data['Version'];
|
||||
|
||||
return version_compare( $plugin_version, $rule->version, $rule->operator );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->plugin ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->version ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->operator ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
/**
|
||||
* Rule processor for sending when the provided plugins are activated.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\PluginsProvider\PluginsProvider;
|
||||
|
||||
/**
|
||||
* Rule processor for sending when the provided plugins are activated.
|
||||
*/
|
||||
class PluginsActivatedRuleProcessor implements RuleProcessorInterface {
|
||||
|
||||
/**
|
||||
* The plugins provider.
|
||||
*
|
||||
* @var PluginsProviderInterface
|
||||
*/
|
||||
protected $plugins_provider;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param PluginsProviderInterface $plugins_provider The plugins provider.
|
||||
*/
|
||||
public function __construct( $plugins_provider = null ) {
|
||||
$this->plugins_provider = null === $plugins_provider
|
||||
? new PluginsProvider()
|
||||
: $plugins_provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the rule.
|
||||
*
|
||||
* @param object $rule The specific rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool Whether the rule passes or not.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
if ( ! is_countable( $rule->plugins ) || 0 === count( $rule->plugins ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$active_plugin_slugs = $this->plugins_provider->get_active_plugin_slugs();
|
||||
|
||||
foreach ( $rule->plugins as $plugin_slug ) {
|
||||
if ( ! is_string( $plugin_slug ) ) {
|
||||
$logger = wc_get_logger();
|
||||
$logger->warning(
|
||||
__( 'Invalid plugin slug provided in the plugins activated rule.', 'woocommerce' )
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! in_array( $plugin_slug, $active_plugin_slugs, true ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->plugins ) || ! is_array( $rule->plugins ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
/**
|
||||
* Rule processor that performs a comparison operation against the number of
|
||||
* products.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Rule processor that performs a comparison operation against the number of
|
||||
* products.
|
||||
*/
|
||||
class ProductCountRuleProcessor implements RuleProcessorInterface {
|
||||
|
||||
/**
|
||||
* The product query.
|
||||
*
|
||||
* @var WC_Product_Query
|
||||
*/
|
||||
protected $product_query;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param object $product_query The product query.
|
||||
*/
|
||||
public function __construct( $product_query = null ) {
|
||||
$this->product_query = null === $product_query
|
||||
? new \WC_Product_Query(
|
||||
array(
|
||||
'limit' => 1,
|
||||
'paginate' => true,
|
||||
'return' => 'ids',
|
||||
'status' => array( 'publish' ),
|
||||
)
|
||||
)
|
||||
: $product_query;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a comparison operation against the number of products.
|
||||
*
|
||||
* @param object $rule The specific rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
$products = $this->product_query->get_products();
|
||||
|
||||
return ComparisonOperation::compare(
|
||||
$products->total,
|
||||
$rule->value,
|
||||
$rule->operation
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->operation ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
/**
|
||||
* Rule processor for sending after a specified date/time.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DateTimeProvider\CurrentDateTimeProvider;
|
||||
|
||||
/**
|
||||
* Rule processor for sending after a specified date/time.
|
||||
*/
|
||||
class PublishAfterTimeRuleProcessor implements RuleProcessorInterface {
|
||||
|
||||
/**
|
||||
* The DateTime provider.
|
||||
*
|
||||
* @var DateTimeProviderInterface
|
||||
*/
|
||||
protected $date_time_provider;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param DateTimeProviderInterface $date_time_provider The DateTime provider.
|
||||
*/
|
||||
public function __construct( $date_time_provider = null ) {
|
||||
$this->date_time_provider = null === $date_time_provider
|
||||
? new CurrentDateTimeProvider()
|
||||
: $date_time_provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the rule.
|
||||
*
|
||||
* @param object $rule The specific rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool Whether the rule passes or not.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
return $this->date_time_provider->get_now() >= new \DateTime( $rule->publish_after );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->publish_after ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
new \DateTime( $rule->publish_after );
|
||||
} catch ( \Throwable $e ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
/**
|
||||
* Rule processor for sending before a specified date/time.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DateTimeProvider\CurrentDateTimeProvider;
|
||||
|
||||
/**
|
||||
* Rule processor for sending before a specified date/time.
|
||||
*/
|
||||
class PublishBeforeTimeRuleProcessor implements RuleProcessorInterface {
|
||||
|
||||
/**
|
||||
* The DateTime provider.
|
||||
*
|
||||
* @var DateTimeProviderInterface
|
||||
*/
|
||||
protected $date_time_provider;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param DateTimeProviderInterface $date_time_provider The DateTime provider.
|
||||
*/
|
||||
public function __construct( $date_time_provider = null ) {
|
||||
$this->date_time_provider = null === $date_time_provider
|
||||
? new CurrentDateTimeProvider()
|
||||
: $date_time_provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the rule.
|
||||
*
|
||||
* @param object $rule The specific rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool Whether the rule passes or not.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
return $this->date_time_provider->get_now() <= new \DateTime( $rule->publish_before );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->publish_before ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
new \DateTime( $rule->publish_before );
|
||||
} catch ( \Throwable $e ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,479 @@
|
|||
# Rule
|
||||
|
||||
Rules in an array are executed as an AND operation. If there are no rules in the array the result is false and the specified notification is not shown.
|
||||
|
||||
## Operations
|
||||
|
||||
Some rule types support an `operation` value, which is used to compare two
|
||||
values. The following operations are implemented:
|
||||
|
||||
- `=`
|
||||
- `<`
|
||||
- `<=`
|
||||
- `>`
|
||||
- `>=`
|
||||
- `!=`
|
||||
- `contains`
|
||||
- `!contains`
|
||||
- `in` (Added in WooCommerce 8.2.0)
|
||||
- `!in` (Added in WooCommerce 8.2.0)
|
||||
- `range` (Added in WooCommerce 8.8.0)
|
||||
|
||||
### contains and !contains
|
||||
|
||||
`contains` and `!contains` allow checking if the provided value is present (or
|
||||
not present) in the haystack value. An example of this is using the
|
||||
`onboarding_profile` rule to match on a value in the `product_types` array -
|
||||
this rule matches if `physical` was selected as a product type in the
|
||||
onboarding profile:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "onboarding_profile",
|
||||
"index": "product_types",
|
||||
"operation": "contains",
|
||||
"value": "physical"
|
||||
}
|
||||
```
|
||||
|
||||
### in and !in
|
||||
|
||||
`in` and `!in` allow checking if a value is found (or not found) in a provided array. For example, using the `in` comparison operator to check if the base country location value is found in a given array, as below. This rule matches if the `base_location_country` is `US`, `NZ`, or `ZA`. **NOTE:** These comparisons were added in **WooCommerce 8.2.0**. If the spec is read by an older version of WooCommerce, the rule will evaluate to `false`.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "base_location_country",
|
||||
"value": [
|
||||
"US",
|
||||
"NZ",
|
||||
"ZA"
|
||||
],
|
||||
"operation": "in"
|
||||
}
|
||||
```
|
||||
|
||||
### range
|
||||
|
||||
`range` operator performs an inclusive check to determine if a number falls within a certain range.
|
||||
This means that both the 'from' and 'to' values of the specified range are included in the check.
|
||||
|
||||
The following rule returns true when `woocommerce_remote_variant_assignment` value is between 1 and 10.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "option",
|
||||
"value": [ 1, 10 ],
|
||||
"default": 0,
|
||||
"operation": "range",
|
||||
"option_name": "woocommerce_remote_variant_assignment",
|
||||
}
|
||||
```
|
||||
|
||||
## Plugins activated
|
||||
|
||||
This passes if all of the listed plugins are installed and activated.
|
||||
|
||||
`plugins` is required.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "plugins_activated",
|
||||
"plugins": [
|
||||
"plugin-slug-1',
|
||||
"plugin-slug-2"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Publish after time
|
||||
|
||||
This passes if the system time is after the specified date/time.
|
||||
|
||||
Note that using both `publish_after_time` and `publish_before_time` allows timeboxing a note which could be useful for promoting a sale.
|
||||
|
||||
`publish_after` is required.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "publish_after_time",
|
||||
"publish_after": "2020-04-22 00:00:00"
|
||||
}
|
||||
```
|
||||
|
||||
## Publish before time
|
||||
|
||||
This passes if the system time is before the specified date/time.
|
||||
|
||||
Note that using both `publish_after_time` and `publish_before_time` allows timeboxing a note which could be useful for promoting a sale.
|
||||
|
||||
`publish_before` is required.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "publish_before_time",
|
||||
"publish_before": "2020-04-22 00:00:00"
|
||||
}
|
||||
```
|
||||
|
||||
## Not
|
||||
|
||||
This negates the rules in the provided set of rules. Note that the rules in `operand` get ANDed together into a single boolean.
|
||||
|
||||
`operand` is required.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "not",
|
||||
"operand": [
|
||||
<Rule>,
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Or
|
||||
|
||||
This performs an OR operation on the operands, passing if any of the operands evaluates to true. Note that if the operands are an array of `Rule`s (as in the first example), each operand is treated as an AND operation.
|
||||
|
||||
`operands` is required.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "or",
|
||||
"operands": [
|
||||
[
|
||||
<Rule>,
|
||||
...
|
||||
],
|
||||
[
|
||||
<Rule>,
|
||||
...
|
||||
]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Alternatively:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "or",
|
||||
"operands": [
|
||||
<Rule>,
|
||||
...
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Fail
|
||||
|
||||
This just returns a false value. This is useful if you want to keep a specification around, but don't want it displayed.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "fail"
|
||||
}
|
||||
```
|
||||
|
||||
## Plugin version
|
||||
|
||||
This compares the installed version of the plugin to the required version, using the comparison operator. If the plugin isn’t activated this returns false.
|
||||
|
||||
`plugin`, `version`, and `operator` are required.
|
||||
|
||||
This example passes if Jetpack 8.4.1 is installed and activated.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "plugin_version",
|
||||
"plugin": "jetpack",
|
||||
"version": "8.4.1",
|
||||
"operator": "="
|
||||
}
|
||||
```
|
||||
|
||||
## Stored state
|
||||
|
||||
This allows access to a stored state containing calculated values that otherwise would be impossible to reproduce using other rules. It performs the comparison operation against the stored state value.
|
||||
|
||||
This example passes if the `there_were_no_products` index is equal to `true`.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "stored_state",
|
||||
"index": "there_were_no_products",
|
||||
"operation": "=",
|
||||
"value": true
|
||||
}
|
||||
```
|
||||
|
||||
There are only a limited amount of indices available to this rule, and new indices will need a new version of the WC Admin plugin to be installed.
|
||||
|
||||
The currently available indices are:
|
||||
|
||||
```json
|
||||
there_were_no_products
|
||||
there_are_now_products
|
||||
new_product_count
|
||||
```
|
||||
|
||||
`index`, `operation`, and `value` are required.
|
||||
|
||||
## Product count
|
||||
|
||||
This passes if the number of products currently in the system match the comparison operation.
|
||||
|
||||
This example passes if there are more than 10 products currently in the system.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "product_count",
|
||||
"operation": ">",
|
||||
"value": 10
|
||||
}
|
||||
```
|
||||
|
||||
`operation` and `value` are required.
|
||||
|
||||
## Order count
|
||||
|
||||
This passes if the number of orders currently in the system match the comparison operation.
|
||||
|
||||
This example passes if there are more than 10 orders currently in the system.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "order_count",
|
||||
"operation": ">",
|
||||
"value": 10
|
||||
}
|
||||
```
|
||||
|
||||
`operation` and `value` are required.
|
||||
|
||||
## WooCommerce Admin active for
|
||||
|
||||
This passes if the time WooCommerce Admin has been active for (in days) matches the comparison operation.
|
||||
|
||||
This is used as a proxy indicator of the age of the shop.
|
||||
|
||||
This example passes if it has been active for more than 8 days.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "wcadmin_active_for",
|
||||
"operation": ">",
|
||||
"days": 8
|
||||
}
|
||||
```
|
||||
|
||||
`operation` and `days` are required.
|
||||
|
||||
## Onboarding profile
|
||||
|
||||
This allows access to the onboarding profile that was built up in the onboarding wizard. The below example passes when the current revenue selected was "none".
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "onboarding_profile",
|
||||
"index": "revenue",
|
||||
"operation": "=",
|
||||
"value": "none"
|
||||
}
|
||||
```
|
||||
|
||||
`index`, `operation`, and `value` are all required.
|
||||
|
||||
## Is eCommerce
|
||||
|
||||
This passes when the store is on a WordPress.com site with the eCommerce plan.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "is_ecommerce",
|
||||
"value": true
|
||||
}
|
||||
```
|
||||
|
||||
`value` is required.
|
||||
|
||||
## Is Woo Express
|
||||
|
||||
This passes when the store is on a WordPress.com site with a Woo Express plan active.
|
||||
You can optionally pass the `plan` name to target a specific Woo Express plan, e.g. `performance`.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "is_woo_express",
|
||||
"plan": "trial|essential|performance",
|
||||
"value": true
|
||||
}
|
||||
```
|
||||
|
||||
`value` is required.
|
||||
`plan` is optional, e.g. `trial`, `essential`, `performance`.
|
||||
|
||||
## Base location - country
|
||||
|
||||
This passes when the store is located in the specified country.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "base_location_country",
|
||||
"value": "US",
|
||||
"operation": "="
|
||||
}
|
||||
```
|
||||
|
||||
`value` and `operation` are both required.
|
||||
|
||||
## Base location - state
|
||||
|
||||
This passes when the store is located in the specified state.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "base_location_state",
|
||||
"value": "TX",
|
||||
"operation": "="
|
||||
}
|
||||
```
|
||||
|
||||
`value` and `operation` are both required.
|
||||
|
||||
## Note status
|
||||
|
||||
This passes when the status of the specified note matches the specified status.
|
||||
The below example passes when the `wc-admin-mobile-app` note has not been
|
||||
actioned.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "note_status",
|
||||
"note_name": "wc-admin-mobile-app",
|
||||
"status": "actioned",
|
||||
"operation": "!="
|
||||
}
|
||||
```
|
||||
|
||||
## Total Payments Value
|
||||
|
||||
This passes when the total value of all payments for a given timeframe
|
||||
compared to the provided value pass the operation test.
|
||||
|
||||
`timeframe` can be one of `last_week`, `last_month`, `last_quarter`, `last_6_months`, `last_year`
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "total_payments_value",
|
||||
"timeframe": "last_month",
|
||||
"value": 2300,
|
||||
"operation": ">"
|
||||
}
|
||||
```
|
||||
|
||||
`timeframe`, `value`, and `operation` are all required.
|
||||
|
||||
## Option
|
||||
|
||||
This passes when the option value matches the value using the operation.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "option",
|
||||
"option_name": "woocommerce_currency",
|
||||
"value": "USD",
|
||||
"default": "USD",
|
||||
"operation": "="
|
||||
}
|
||||
```
|
||||
|
||||
`option_name`, `value`, and `operation` are all required. `default` is not required and allows a default value to be used if the option does not exist.
|
||||
|
||||
### Option Transformer
|
||||
|
||||
This transforms the given option value into a different value by a series of transformers.
|
||||
|
||||
Example option value:
|
||||
|
||||
```php
|
||||
Array
|
||||
(
|
||||
[setup_client] =>
|
||||
[industry] => Array
|
||||
(
|
||||
[0] => Array
|
||||
(
|
||||
[slug] => food-drink
|
||||
)
|
||||
|
||||
[1] => Array
|
||||
(
|
||||
[slug] => fashion-apparel-accessories
|
||||
)
|
||||
)
|
||||
)
|
||||
```
|
||||
|
||||
If you want to ensure that the industry array contains `fashion-apparel-accessories`, you can use the following Option definition with transformers.
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "option",
|
||||
"transformers": [
|
||||
{
|
||||
"use": "dot_notation",
|
||||
"arguments": {
|
||||
"path": "industry"
|
||||
}
|
||||
},
|
||||
{
|
||||
"use": "array_column",
|
||||
"arguments": {
|
||||
"key": "slug"
|
||||
}
|
||||
},
|
||||
{
|
||||
"use": "array_search",
|
||||
"arguments": {
|
||||
"value": "fashion-apparel-accessories"
|
||||
}
|
||||
}
|
||||
],
|
||||
"option_name": "woocommerce_onboarding_profile",
|
||||
"value": "fashion-apparel-accessories",
|
||||
"default": "USD",
|
||||
"operation": "="
|
||||
}
|
||||
```
|
||||
|
||||
You can find a list of transformers and examples in the transformer [README](./Transformers/README.md).
|
||||
|
||||
## WCA updated
|
||||
|
||||
This passes when WooCommerce Admin has just been updated. The specs will be run
|
||||
on update. Note that this doesn't provide a way to check the version number as
|
||||
the `plugin_version` rule can be used to check for a specific version of the
|
||||
WooCommerce Admin plugin.
|
||||
|
||||
```json
|
||||
{
|
||||
type: "wca_updated"
|
||||
}
|
||||
```
|
||||
|
||||
No other values are needed.
|
||||
|
||||
## Debugging Specification
|
||||
|
||||
You can see the evaluation of each specification by turning on an optional evaluation logger.
|
||||
|
||||
1. Define `WC_ADMIN_DEBUG_RULE_EVALUATOR` constant in `wp-config.php`. `define('WC_ADMIN_DEBUG_RULE_EVALUATOR', true);`
|
||||
2. Run `wc_admin_daily`
|
||||
3. cd to `wp-content/uploads/wc-logs/` and check a log file in `remote-inbox-notifications-:date-hash.log` format.
|
||||
|
||||
You can tail the log file with a slug name to see the evaluation of a rule that you are testing.
|
||||
|
||||
Example:
|
||||
|
||||
`tail -f remote-inbox-notifications-2021-06-15-128.log | grep 'wcpay-promo-2021-6-incentive-2'`
|
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
/**
|
||||
* Evaluate the given rules as an AND operation - return false early if a
|
||||
* rule evaluates to false.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Evaluate the given rules as an AND operation - return false early if a
|
||||
* rule evaluates to false.
|
||||
*/
|
||||
class RuleEvaluator {
|
||||
|
||||
/**
|
||||
* GetRuleProcessor to use.
|
||||
*
|
||||
* @var GetRuleProcessor
|
||||
*/
|
||||
private $get_rule_processor;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param GetRuleProcessor $get_rule_processor The GetRuleProcessor to use.
|
||||
*/
|
||||
public function __construct( $get_rule_processor = null ) {
|
||||
$this->get_rule_processor = null === $get_rule_processor
|
||||
? new GetRuleProcessor()
|
||||
: $get_rule_processor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the given rules as an AND operation - return false early if a
|
||||
* rule evaluates to false.
|
||||
*
|
||||
* @param array|object $rules The rule or rules being processed.
|
||||
* @param object|null $stored_state Stored state.
|
||||
* @param array $logger_args Arguments for the event logger. `slug` is required.
|
||||
*
|
||||
* @throws \InvalidArgumentException Thrown when $logger_args is missing slug.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
*/
|
||||
public function evaluate( $rules, $stored_state = null, $logger_args = array() ) {
|
||||
|
||||
if ( is_bool( $rules ) ) {
|
||||
return $rules;
|
||||
}
|
||||
|
||||
if ( ! is_array( $rules ) ) {
|
||||
$rules = array( $rules );
|
||||
}
|
||||
|
||||
if ( 0 === count( $rules ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$evaluation_logger = null;
|
||||
|
||||
if ( count( $logger_args ) ) {
|
||||
if ( ! array_key_exists( 'slug', $logger_args ) ) {
|
||||
throw new \InvalidArgumentException( 'Missing required field: slug in $logger_args.' );
|
||||
}
|
||||
|
||||
array_key_exists( 'source', $logger_args ) ? $source = $logger_args['source'] : $source = null;
|
||||
|
||||
$evaluation_logger = new EvaluationLogger( $logger_args['slug'], $source );
|
||||
}
|
||||
|
||||
foreach ( $rules as $rule ) {
|
||||
if ( ! is_object( $rule ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$processor = $this->get_rule_processor->get_processor( $rule->type );
|
||||
$processor_result = $processor->process( $rule, $stored_state );
|
||||
$evaluation_logger && $evaluation_logger->add_result( $rule->type, $processor_result );
|
||||
|
||||
if ( ! $processor_result ) {
|
||||
$evaluation_logger && $evaluation_logger->log();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$evaluation_logger && $evaluation_logger->log();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
/**
|
||||
* Interface for a rule processor.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Rule processor interface
|
||||
*/
|
||||
interface RuleProcessorInterface {
|
||||
/**
|
||||
* Processes a rule, returning the boolean result of the processing.
|
||||
*
|
||||
* @param object $rule The rule to process.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool The result of the processing.
|
||||
*/
|
||||
public function process( $rule, $stored_state );
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule );
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
/**
|
||||
* Rule processor that performs a comparison operation against a value in the
|
||||
* stored state object.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Rule processor that performs a comparison operation against a value in the
|
||||
* stored state object.
|
||||
*/
|
||||
class StoredStateRuleProcessor implements RuleProcessorInterface {
|
||||
/**
|
||||
* Performs a comparison operation against a value in the stored state object.
|
||||
*
|
||||
* @param object $rule The rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
if ( ! isset( $stored_state->{$rule->index} ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ComparisonOperation::compare(
|
||||
$stored_state->{$rule->index},
|
||||
$rule->value,
|
||||
$rule->operation
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
if ( ! isset( $rule->index ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->operation ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
<?php
|
||||
/**
|
||||
* Handles stored state setup for products.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\RemoteInboxNotificationsEngine;
|
||||
|
||||
/**
|
||||
* Handles stored state setup for products.
|
||||
*/
|
||||
class StoredStateSetupForProducts {
|
||||
const ASYNC_RUN_REMOTE_NOTIFICATIONS_ACTION_NAME =
|
||||
'woocommerce_admin/stored_state_setup_for_products/async/run_remote_notifications';
|
||||
|
||||
/**
|
||||
* Initialize the class via the admin_init hook.
|
||||
*/
|
||||
public static function admin_init() {
|
||||
add_action( 'product_page_product_importer', array( __CLASS__, 'run_on_product_importer' ) );
|
||||
add_action( 'transition_post_status', array( __CLASS__, 'run_on_transition_post_status' ), 10, 3 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the class via the init hook.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final public static function init() {
|
||||
add_action( self::ASYNC_RUN_REMOTE_NOTIFICATIONS_ACTION_NAME, array( __CLASS__, 'run_remote_notifications' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the remote notifications engine. This is triggered by
|
||||
* action-scheduler after a product is added. It also cleans up from
|
||||
* setting the product count increment.
|
||||
*/
|
||||
public static function run_remote_notifications() {
|
||||
RemoteInboxNotificationsEngine::run();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set initial stored state values.
|
||||
*
|
||||
* @param object $stored_state The stored state.
|
||||
*
|
||||
* @return object The stored state.
|
||||
*/
|
||||
public static function init_stored_state( $stored_state ) {
|
||||
$stored_state->there_were_no_products = ! self::are_there_products();
|
||||
$stored_state->there_are_now_products = ! $stored_state->there_were_no_products;
|
||||
|
||||
return $stored_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Are there products query.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private static function are_there_products() {
|
||||
$query = new \WC_Product_Query(
|
||||
array(
|
||||
'limit' => 1,
|
||||
'paginate' => true,
|
||||
'return' => 'ids',
|
||||
'status' => array( 'publish' ),
|
||||
)
|
||||
);
|
||||
$products = $query->get_products();
|
||||
$count = $products->total;
|
||||
|
||||
return $count > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs on product importer steps.
|
||||
*/
|
||||
public static function run_on_product_importer() {
|
||||
// We're only interested in when the importer completes.
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
if ( ! isset( $_REQUEST['step'] ) ) {
|
||||
return;
|
||||
}
|
||||
if ( 'done' !== $_REQUEST['step'] ) {
|
||||
return;
|
||||
}
|
||||
// phpcs:enable
|
||||
|
||||
self::update_stored_state_and_possibly_run_remote_notifications();
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs when a post status transitions, but we're only interested if it is
|
||||
* a product being published.
|
||||
*
|
||||
* @param string $new_status The new status.
|
||||
* @param string $old_status The old status.
|
||||
* @param Post $post The post.
|
||||
*/
|
||||
public static function run_on_transition_post_status( $new_status, $old_status, $post ) {
|
||||
if (
|
||||
'product' !== $post->post_type ||
|
||||
'publish' !== $new_status
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::update_stored_state_and_possibly_run_remote_notifications();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues an async action (using action-scheduler) to run remote
|
||||
* notifications.
|
||||
*/
|
||||
private static function update_stored_state_and_possibly_run_remote_notifications() {
|
||||
$stored_state = RemoteInboxNotificationsEngine::get_stored_state();
|
||||
// If the stored_state is the same, we don't need to run remote notifications to avoid unnecessary action scheduling.
|
||||
if ( true === $stored_state->there_are_now_products ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$stored_state->there_are_now_products = true;
|
||||
RemoteInboxNotificationsEngine::update_stored_state( $stored_state );
|
||||
|
||||
// Run self::run_remote_notifications asynchronously.
|
||||
as_enqueue_async_action( self::ASYNC_RUN_REMOTE_NOTIFICATIONS_ACTION_NAME );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
<?php
|
||||
/**
|
||||
* Rule processor that passes when a store's payments volume exceeds a provided amount.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\API\Reports\Revenue\Query as RevenueQuery;
|
||||
use Automattic\WooCommerce\Admin\API\Reports\TimeInterval;
|
||||
|
||||
/**
|
||||
* Rule processor that passes when a store's payments volume exceeds a provided amount.
|
||||
*/
|
||||
class TotalPaymentsVolumeProcessor implements RuleProcessorInterface {
|
||||
/**
|
||||
* Compare against the store's total payments volume.
|
||||
*
|
||||
* @param object $rule The rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
$dates = TimeInterval::get_timeframe_dates( $rule->timeframe );
|
||||
$reports_revenue = $this->get_reports_query(
|
||||
array(
|
||||
'before' => $dates['end'],
|
||||
'after' => $dates['start'],
|
||||
'interval' => 'year',
|
||||
'fields' => array( 'total_sales' ),
|
||||
)
|
||||
);
|
||||
$report_data = $reports_revenue->get_data();
|
||||
|
||||
if ( ! $report_data || ! isset( $report_data->totals->total_sales ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$value = $report_data->totals->total_sales;
|
||||
|
||||
return ComparisonOperation::compare(
|
||||
$value,
|
||||
$rule->value,
|
||||
$rule->operation
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
$allowed_timeframes = array(
|
||||
'last_week',
|
||||
'last_month',
|
||||
'last_quarter',
|
||||
'last_6_months',
|
||||
'last_year',
|
||||
);
|
||||
|
||||
if ( ! isset( $rule->timeframe ) || ! in_array( $rule->timeframe, $allowed_timeframes, true ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->value ) || ! is_numeric( $rule->value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->operation ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the report query.
|
||||
*
|
||||
* @param array $args The query args.
|
||||
*
|
||||
* @return RevenueQuery The report query.
|
||||
*/
|
||||
protected function get_reports_query( $args ) {
|
||||
return new RevenueQuery(
|
||||
$args
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers;
|
||||
|
||||
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\TransformerInterface;
|
||||
use InvalidArgumentException;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Search array value by one of its key.
|
||||
*
|
||||
* @package Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers
|
||||
*/
|
||||
class ArrayColumn implements TransformerInterface {
|
||||
/**
|
||||
* Search array value by one of its key.
|
||||
*
|
||||
* @param mixed $value a value to transform.
|
||||
* @param stdClass|null $arguments required arguments 'key'.
|
||||
* @param string|null $default_value default value.
|
||||
*
|
||||
* @throws InvalidArgumentException Throws when the required argument 'key' is missing.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function transform( $value, stdClass $arguments = null, $default_value = array() ) {
|
||||
if ( ! is_array( $value ) ) {
|
||||
return $default_value;
|
||||
}
|
||||
|
||||
return array_column( $value, $arguments->key );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Transformer arguments.
|
||||
*
|
||||
* @param stdClass|null $arguments arguments to validate.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function validate( stdClass $arguments = null ) {
|
||||
if ( ! isset( $arguments->key ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
null !== $arguments->key &&
|
||||
! is_string( $arguments->key ) &&
|
||||
! is_int( $arguments->key )
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers;
|
||||
|
||||
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\TransformerInterface;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Flatten nested array.
|
||||
*
|
||||
* @package Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers
|
||||
*/
|
||||
class ArrayFlatten implements TransformerInterface {
|
||||
/**
|
||||
* Search a given value in the array.
|
||||
*
|
||||
* @param mixed $value a value to transform.
|
||||
* @param stdClass|null $arguments arguments.
|
||||
* @param string|null $default_value default value.
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function transform( $value, stdClass $arguments = null, $default_value = array() ) {
|
||||
if ( ! is_array( $value ) ) {
|
||||
return $default_value;
|
||||
}
|
||||
|
||||
$return = array();
|
||||
array_walk_recursive(
|
||||
$value,
|
||||
function ( $item ) use ( &$return ) {
|
||||
$return[] = $item;
|
||||
}
|
||||
);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Transformer arguments.
|
||||
*
|
||||
* @param stdClass|null $arguments arguments to validate.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function validate( stdClass $arguments = null ) {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers;
|
||||
|
||||
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\TransformerInterface;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Search array value by one of its key.
|
||||
*
|
||||
* @package Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers
|
||||
*/
|
||||
class ArrayKeys implements TransformerInterface {
|
||||
/**
|
||||
* Search array value by one of its key.
|
||||
*
|
||||
* @param mixed $value a value to transform.
|
||||
* @param stdClass|null $arguments arguments.
|
||||
* @param string|null $default_value default value.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function transform( $value, stdClass $arguments = null, $default_value = array() ) {
|
||||
if ( ! is_array( $value ) ) {
|
||||
return $default_value;
|
||||
}
|
||||
|
||||
return array_keys( $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Transformer arguments.
|
||||
*
|
||||
* @param stdClass|null $arguments arguments to validate.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function validate( stdClass $arguments = null ) {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers;
|
||||
|
||||
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\TransformerInterface;
|
||||
use InvalidArgumentException;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Searches a given a given value in the array.
|
||||
*
|
||||
* @package Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers
|
||||
*/
|
||||
class ArraySearch implements TransformerInterface {
|
||||
/**
|
||||
* Search a given value in the array.
|
||||
*
|
||||
* @param mixed $value a value to transform.
|
||||
* @param stdClass|null $arguments required argument 'value'.
|
||||
* @param string|null $default_value default value.
|
||||
*
|
||||
* @throws InvalidArgumentException Throws when the required 'value' is missing.
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function transform( $value, stdClass $arguments = null, $default_value = null ) {
|
||||
if ( ! is_array( $value ) ) {
|
||||
return $default_value;
|
||||
}
|
||||
|
||||
$key = array_search( $arguments->value, $value, true );
|
||||
if ( false !== $key ) {
|
||||
return $value[ $key ];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Transformer arguments.
|
||||
*
|
||||
* @param stdClass|null $arguments arguments to validate.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function validate( stdClass $arguments = null ) {
|
||||
if ( ! isset( $arguments->value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers;
|
||||
|
||||
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\TransformerInterface;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Search array value by one of its key.
|
||||
*
|
||||
* @package Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers
|
||||
*/
|
||||
class ArrayValues implements TransformerInterface {
|
||||
/**
|
||||
* Search array value by one of its key.
|
||||
*
|
||||
* @param mixed $value a value to transform.
|
||||
* @param stdClass|null $arguments arguments.
|
||||
* @param string|null $default_value default value.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function transform( $value, stdClass $arguments = null, $default_value = array() ) {
|
||||
if ( ! is_array( $value ) ) {
|
||||
return $default_value;
|
||||
}
|
||||
|
||||
return array_values( $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Transformer arguments.
|
||||
*
|
||||
* @param stdClass|null $arguments arguments to validate.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function validate( stdClass $arguments = null ) {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers;
|
||||
|
||||
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\TransformerInterface;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Count elements in Array or Countable object.
|
||||
*
|
||||
* @package Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers
|
||||
*/
|
||||
class Count implements TransformerInterface {
|
||||
/**
|
||||
* Count elements in Array or Countable object.
|
||||
*
|
||||
* @param array|Countable $value an array to count.
|
||||
* @param stdClass|null $arguments arguments.
|
||||
* @param string|null $default_value default value.
|
||||
*
|
||||
* @return number
|
||||
*/
|
||||
public function transform( $value, stdClass $arguments = null, $default_value = null ) {
|
||||
if ( ! is_array( $value ) && ! $value instanceof \Countable ) {
|
||||
return $default_value;
|
||||
}
|
||||
|
||||
return count( $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Transformer arguments.
|
||||
*
|
||||
* @param stdClass|null $arguments arguments to validate.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function validate( stdClass $arguments = null ) {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers;
|
||||
|
||||
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\TransformerInterface;
|
||||
use InvalidArgumentException;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Find an array value by dot notation.
|
||||
*
|
||||
* @package Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers
|
||||
*/
|
||||
class DotNotation implements TransformerInterface {
|
||||
|
||||
/**
|
||||
* Find given path from the given value.
|
||||
*
|
||||
* @param mixed $value a value to transform.
|
||||
* @param stdClass|null $arguments required argument 'path'.
|
||||
* @param string|null $default_value default value.
|
||||
*
|
||||
* @throws InvalidArgumentException Throws when the required 'path' is missing.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function transform( $value, stdclass $arguments = null, $default_value = null ) {
|
||||
if ( is_object( $value ) ) {
|
||||
// if the value is an object, convert it to an array.
|
||||
$value = json_decode( wp_json_encode( $value ), true );
|
||||
}
|
||||
|
||||
return $this->get( $value, $arguments->path, $default_value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the given $path in $array_to_search by dot notation.
|
||||
*
|
||||
* @param array $array_to_search an array to search in.
|
||||
* @param string $path a path in the given array.
|
||||
* @param null $default_value default value to return if $path was not found.
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function get( $array_to_search, $path, $default_value = null ) {
|
||||
if ( ! is_array( $array_to_search ) ) {
|
||||
return $default_value;
|
||||
}
|
||||
|
||||
if ( isset( $array_to_search[ $path ] ) ) {
|
||||
return $array_to_search[ $path ];
|
||||
}
|
||||
|
||||
foreach ( explode( '.', $path ) as $segment ) {
|
||||
if ( ! is_array( $array_to_search ) || ! array_key_exists( $segment, $array_to_search ) ) {
|
||||
return $default_value;
|
||||
}
|
||||
|
||||
$array_to_search = $array_to_search[ $segment ];
|
||||
}
|
||||
|
||||
return $array_to_search;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Transformer arguments.
|
||||
*
|
||||
* @param stdClass|null $arguments arguments to validate.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function validate( stdClass $arguments = null ) {
|
||||
if ( ! isset( $arguments->path ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers;
|
||||
|
||||
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\TransformerInterface;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Prepare site URL for comparison.
|
||||
*
|
||||
* @package Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers
|
||||
*/
|
||||
class PrepareUrl implements TransformerInterface {
|
||||
/**
|
||||
* Prepares the site URL by removing the protocol and trailing slash.
|
||||
*
|
||||
* @param string $value a value to transform.
|
||||
* @param stdClass|null $arguments arguments.
|
||||
* @param string|null $default_value default value.
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function transform( $value, stdClass $arguments = null, $default_value = null ) {
|
||||
if ( ! is_string( $value ) ) {
|
||||
return $default_value;
|
||||
}
|
||||
|
||||
$url_parts = wp_parse_url( rtrim( $value, '/' ) );
|
||||
|
||||
if ( ! $url_parts ) {
|
||||
return $default_value;
|
||||
}
|
||||
|
||||
if ( ! isset( $url_parts['host'] ) ) {
|
||||
return $default_value;
|
||||
}
|
||||
|
||||
if ( isset( $url_parts['path'] ) ) {
|
||||
return $url_parts['host'] . $url_parts['path'];
|
||||
}
|
||||
|
||||
return $url_parts['host'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Transformer arguments.
|
||||
*
|
||||
* @param stdClass|null $arguments arguments to validate.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function validate( stdClass $arguments = null ) {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,404 @@
|
|||
<!-- markdownlint-disable MD024 -->
|
||||
|
||||
# Option Transformer
|
||||
|
||||
An option transformer is a class that transforms the given option value into a different value for the comparison operation.
|
||||
|
||||
Transformers run in the order in which they are defined, and each transformer passes down the value it transformed to the next transformer for consumption.
|
||||
|
||||
**Definition example**: transformers are always used with `option` rule.
|
||||
|
||||
```js
|
||||
{
|
||||
"slug": "test-note",
|
||||
...
|
||||
],
|
||||
"rules": [
|
||||
{
|
||||
"type": "option",
|
||||
"transformers": [
|
||||
{
|
||||
"use": "dot_notation",
|
||||
"arguments": {
|
||||
"path": "industry"
|
||||
}
|
||||
},
|
||||
{
|
||||
"use": "array_column",
|
||||
"arguments": {
|
||||
"key": "slug"
|
||||
}
|
||||
}
|
||||
],
|
||||
"option_name": "woocommerce_onboarding_profile",
|
||||
"operation": "!=",
|
||||
"value": "fashion-apparel-accessories",
|
||||
"default": []
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## array_column
|
||||
|
||||
PHP's built-in `array_column` to select values from a single column. For more information about how array_column works, please see PHP's [official documentation](https://www.php.net/manual/en/function.array-column.php).
|
||||
|
||||
### Arguments
|
||||
|
||||
| name | description |
|
||||
| ---- | -------------- |
|
||||
| key | array key name |
|
||||
|
||||
### Definition
|
||||
|
||||
```php
|
||||
"transformers": [
|
||||
{
|
||||
"use": "array_column",
|
||||
"arguments": {
|
||||
"key": "industry"
|
||||
}
|
||||
}
|
||||
],
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
Given the following data
|
||||
|
||||
```php
|
||||
array(
|
||||
array("industry" => "media" ),
|
||||
array("industry" => "software" )
|
||||
);
|
||||
```
|
||||
|
||||
Use `array_column` to extract `array("media", "software")` then choose the first element with `dot_notation`.
|
||||
|
||||
```php
|
||||
"transformers": [
|
||||
{
|
||||
"use": "array_column",
|
||||
"arguments": {
|
||||
"key": "industry"
|
||||
}
|
||||
},
|
||||
{
|
||||
"use": "dot_notation",
|
||||
"arguments": {
|
||||
"key": "0"
|
||||
}
|
||||
}
|
||||
],
|
||||
```
|
||||
|
||||
**Output**: "media"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## array_flatten
|
||||
|
||||
Flattens a nested array.
|
||||
|
||||
### Arguments: N/A
|
||||
|
||||
### Definition
|
||||
|
||||
```php
|
||||
"transformers": [
|
||||
{
|
||||
"use": "array_flatten"
|
||||
}
|
||||
],
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
Given the following data
|
||||
|
||||
```php
|
||||
array(
|
||||
array(
|
||||
'member1',
|
||||
),
|
||||
array(
|
||||
'member2',
|
||||
),
|
||||
array(
|
||||
'member3',
|
||||
),
|
||||
);
|
||||
```
|
||||
|
||||
Use `array_flatten` to extract `array("member1", "member2", "member3")` then use `array_search` to make sure it has `member2`
|
||||
|
||||
|
||||
```php
|
||||
"transformers": [
|
||||
{
|
||||
"use": "array_flatten",
|
||||
},
|
||||
{
|
||||
"use": "array_search",
|
||||
"arguments": {
|
||||
"key": "member2"
|
||||
}
|
||||
}
|
||||
],
|
||||
```
|
||||
|
||||
**Output**: true
|
||||
|
||||
## array_keys
|
||||
|
||||
PHP's built-in `array_keys` to return keys from an array. For more information about how `array_keys` works, please see PHP’s [official documentation](https://www.php.net/manual/en/function.array-column.php).
|
||||
|
||||
### Arguments: N/A
|
||||
|
||||
### Definition
|
||||
|
||||
```php
|
||||
"transformers": [
|
||||
{
|
||||
"use": "array_keys"
|
||||
}
|
||||
],
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
Given the following data
|
||||
|
||||
```php
|
||||
array(
|
||||
"name" => "tester",
|
||||
"address" => "test",
|
||||
"supports_version_2" => true
|
||||
)
|
||||
```
|
||||
|
||||
Use `array_keys` to extract `array("name", "address", "supports_version_2")` and then use `array_search` to make sure it has `supports_version_2`
|
||||
|
||||
```php
|
||||
"transformers": [
|
||||
{
|
||||
"use": "array_keys",
|
||||
},
|
||||
{
|
||||
"use": "array_search",
|
||||
"arguments": {
|
||||
"key": "member2"
|
||||
}
|
||||
}
|
||||
],
|
||||
```
|
||||
|
||||
**Output**: true
|
||||
|
||||
## array_search
|
||||
|
||||
PHP's built-in `array_search` to search a value in an array. For more information about how `array_search` works, please see PHP’s [official documentation](https://www.php.net/manual/en/function.array-search.php).
|
||||
|
||||
### Arguments
|
||||
|
||||
|name|description|
|
||||
|----|---------|
|
||||
| value | a value to search in the given array |
|
||||
|
||||
### Definition
|
||||
|
||||
```php
|
||||
"transformers": [
|
||||
{
|
||||
"use": "array_search",
|
||||
"arguments": {
|
||||
"value": "test"
|
||||
}
|
||||
}
|
||||
],
|
||||
```
|
||||
|
||||
### Examples
|
||||
|
||||
See examples from [array_flatten](#array_flatten) and [array_keys](#array_keys)
|
||||
|
||||
## array_values
|
||||
|
||||
PHP's built-in array_values to return values from an array. For more information about how `array_values` works, please see PHP’s [official documentation](https://www.php.net/manual/en/function.array-values).
|
||||
|
||||
|
||||
### Arguments: N/A
|
||||
|
||||
### Definition
|
||||
|
||||
```php
|
||||
"transformers": [
|
||||
{
|
||||
"use": "array_values"
|
||||
}
|
||||
],
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
Given the following data
|
||||
|
||||
```php
|
||||
array (
|
||||
"size" => "x-large"
|
||||
)
|
||||
```
|
||||
|
||||
Use `array_values` to extract `array("x-large")`
|
||||
|
||||
```php
|
||||
"transformers": [
|
||||
{
|
||||
"use": "array_values",
|
||||
}
|
||||
],
|
||||
```
|
||||
|
||||
**Output:** "x-large"
|
||||
|
||||
|
||||
## dot_notation
|
||||
|
||||
Uses dot notation to select a value in an array. Dot notation lets you access an array as if it is an object.
|
||||
|
||||
### Arguments: N/A
|
||||
|
||||
### Definition
|
||||
|
||||
|
||||
```php
|
||||
"transformers": [
|
||||
{
|
||||
"use": "dot_notation",
|
||||
"arguments": {
|
||||
"path": "name"
|
||||
}
|
||||
}
|
||||
],
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
|
||||
Given the following data
|
||||
|
||||
```php
|
||||
array(
|
||||
'name' => 'john',
|
||||
'members' => ['member1', 'member2']
|
||||
);
|
||||
```
|
||||
|
||||
Select `name` field.
|
||||
|
||||
```php
|
||||
"transformers": [
|
||||
{
|
||||
"use": "dot_notation",
|
||||
"arguments": {
|
||||
"path": "name"
|
||||
}
|
||||
}
|
||||
],
|
||||
```
|
||||
|
||||
**Output:** "john"
|
||||
|
||||
Select `member2`. You can access array items with an index.
|
||||
|
||||
```php
|
||||
"transformers": [
|
||||
{
|
||||
"use": "dot_notation",
|
||||
"arguments": {
|
||||
"path": "members.1"
|
||||
}
|
||||
}
|
||||
],
|
||||
```
|
||||
|
||||
**Output:**: "member2"
|
||||
|
||||
## count
|
||||
|
||||
PHP's built-in count to return the number of values from a countable, such as an array.
|
||||
|
||||
### Arguments: N/A
|
||||
|
||||
### Definition
|
||||
|
||||
```php
|
||||
"transformers": [
|
||||
{
|
||||
"use": "count"
|
||||
}
|
||||
],
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
Given the following list of usernames
|
||||
|
||||
```php
|
||||
array(
|
||||
"username1",
|
||||
"username2",
|
||||
"username3"
|
||||
)
|
||||
```
|
||||
|
||||
Let's count # of users with `count`
|
||||
|
||||
```php
|
||||
"transformers": [
|
||||
{
|
||||
"use": "count",
|
||||
}
|
||||
],
|
||||
```
|
||||
|
||||
**Output:** 3
|
||||
|
||||
## prepare_url
|
||||
|
||||
This prepares the site URL by removing the protocol and the last slash.
|
||||
|
||||
### Arguments: N/A
|
||||
|
||||
### Definition
|
||||
|
||||
```php
|
||||
"transformers": [
|
||||
{
|
||||
"use": "prepare_url"
|
||||
}
|
||||
],
|
||||
```
|
||||
|
||||
### Example
|
||||
|
||||
Given the following data
|
||||
|
||||
```php
|
||||
$siteurl = "https://mysite.com/"
|
||||
```
|
||||
|
||||
Removes the protocol and the last slash.
|
||||
|
||||
```php
|
||||
"transformers": [
|
||||
{
|
||||
"use": "prepare_url",
|
||||
}
|
||||
],
|
||||
```
|
||||
|
||||
**Output:** "mysite.com"
|
|
@ -0,0 +1,34 @@
|
|||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers;
|
||||
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* An interface to define a transformer.
|
||||
*
|
||||
* Interface TransformerInterface
|
||||
*
|
||||
* @package Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers
|
||||
*/
|
||||
interface TransformerInterface {
|
||||
/**
|
||||
* Transform given value to a different value.
|
||||
*
|
||||
* @param mixed $value a value to transform.
|
||||
* @param stdClass|null $arguments arguments.
|
||||
* @param string|null $default_value default value.
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function transform( $value, stdClass $arguments = null, $default_value = null );
|
||||
|
||||
/**
|
||||
* Validate Transformer arguments.
|
||||
*
|
||||
* @param stdClass|null $arguments arguments to validate.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function validate( stdClass $arguments = null );
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
<?php
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* A simple service class for the Transformer classes.
|
||||
*
|
||||
* Class TransformerService
|
||||
*
|
||||
* @package Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers
|
||||
*/
|
||||
class TransformerService {
|
||||
/**
|
||||
* Create a transformer object by name.
|
||||
*
|
||||
* @param string $name name of the transformer.
|
||||
*
|
||||
* @return TransformerInterface|null
|
||||
*/
|
||||
public static function create_transformer( $name ) {
|
||||
$camel_cased = str_replace( ' ', '', ucwords( str_replace( '_', ' ', $name ) ) );
|
||||
|
||||
$classname = __NAMESPACE__ . '\\' . $camel_cased;
|
||||
if ( ! class_exists( $classname ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new $classname();
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply transformers to the given value.
|
||||
*
|
||||
* @param mixed $target_value a value to transform.
|
||||
* @param array $transformer_configs transform configuration.
|
||||
* @param bool $is_default_set flag on is default value set.
|
||||
* @param string $default_value default value.
|
||||
*
|
||||
* @throws InvalidArgumentException Throws when one of the requried arguments is missing.
|
||||
* @return mixed|null
|
||||
*/
|
||||
public static function apply( $target_value, array $transformer_configs, $is_default_set, $default_value ) {
|
||||
foreach ( $transformer_configs as $transformer_config ) {
|
||||
if ( ! isset( $transformer_config->use ) ) {
|
||||
throw new InvalidArgumentException( 'Missing required config value: use' );
|
||||
}
|
||||
|
||||
if ( ! isset( $transformer_config->arguments ) ) {
|
||||
$transformer_config->arguments = null;
|
||||
}
|
||||
|
||||
$transformer = self::create_transformer( $transformer_config->use );
|
||||
if ( null === $transformer ) {
|
||||
throw new InvalidArgumentException( "Unable to find a transformer by name: {$transformer_config->use}" ); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
|
||||
}
|
||||
|
||||
$target_value = $transformer->transform( $target_value, $transformer_config->arguments, $is_default_set ? $default_value : null );
|
||||
|
||||
// Break early when there's no more value to traverse.
|
||||
if ( null === $target_value ) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $is_default_set ) {
|
||||
// Nulls always return the default value.
|
||||
if ( null === $target_value ) {
|
||||
return $default_value;
|
||||
}
|
||||
|
||||
// When type of the default value is different from the target value, return the default value
|
||||
// to ensure type safety.
|
||||
if ( gettype( $default_value ) !== gettype( $target_value ) ) {
|
||||
return $default_value;
|
||||
}
|
||||
}
|
||||
|
||||
return $target_value;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
/**
|
||||
* WCAdmin active for provider.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
use Automattic\WooCommerce\Admin\WCAdminHelper;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* WCAdminActiveForProvider class
|
||||
*/
|
||||
class WCAdminActiveForProvider {
|
||||
/**
|
||||
* Get the number of seconds that the store has been active.
|
||||
*
|
||||
* @return number Number of seconds.
|
||||
*/
|
||||
public function get_wcadmin_active_for_in_seconds() {
|
||||
return WCAdminHelper::get_wcadmin_active_for_in_seconds();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
/**
|
||||
* Rule processor for publishing if wc-admin has been active for at least the
|
||||
* given number of seconds.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Rule processor for publishing if wc-admin has been active for at least the
|
||||
* given number of seconds.
|
||||
*/
|
||||
class WCAdminActiveForRuleProcessor implements RuleProcessorInterface {
|
||||
|
||||
/**
|
||||
* Provides the amount of time wcadmin has been active for.
|
||||
*
|
||||
* @var WCAdminActiveForProvider
|
||||
*/
|
||||
protected $wcadmin_active_for_provider;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param object $wcadmin_active_for_provider Provides the amount of time wcadmin has been active for.
|
||||
*/
|
||||
public function __construct( $wcadmin_active_for_provider = null ) {
|
||||
$this->wcadmin_active_for_provider = null === $wcadmin_active_for_provider
|
||||
? new WCAdminActiveForProvider()
|
||||
: $wcadmin_active_for_provider;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a comparison operation against the amount of time wc-admin has
|
||||
* been active for in days.
|
||||
*
|
||||
* @param object $rule The rule being processed.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool The result of the operation.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
$active_for_seconds = $this->wcadmin_active_for_provider->get_wcadmin_active_for_in_seconds();
|
||||
|
||||
if ( ! $active_for_seconds || ! is_numeric( $active_for_seconds ) || $active_for_seconds < 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$rule_seconds = $rule->days * DAY_IN_SECONDS;
|
||||
|
||||
return ComparisonOperation::compare(
|
||||
$active_for_seconds,
|
||||
$rule_seconds,
|
||||
$rule->operation
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
// Ensure that 'days' property is set and is a valid numeric value.
|
||||
if ( ! isset( $rule->days ) || ! is_numeric( $rule->days ) || $rule->days < 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $rule->operation ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
/**
|
||||
* Rule processor for sending when WooCommerce Admin has been updated.
|
||||
*/
|
||||
|
||||
namespace Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors;
|
||||
|
||||
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\RemoteInboxNotificationsEngine;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Rule processor for sending when WooCommerce Admin has been updated.
|
||||
*/
|
||||
class WooCommerceAdminUpdatedRuleProcessor implements RuleProcessorInterface {
|
||||
/**
|
||||
* Process the rule.
|
||||
*
|
||||
* @param object $rule The specific rule being processed by this rule processor.
|
||||
* @param object $stored_state Stored state.
|
||||
*
|
||||
* @return bool Whether the rule passes or not.
|
||||
*/
|
||||
public function process( $rule, $stored_state ) {
|
||||
return get_option( RemoteInboxNotificationsEngine::WCA_UPDATED_OPTION_NAME, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the rule.
|
||||
*
|
||||
* @param object $rule The rule to validate.
|
||||
*
|
||||
* @return bool Pass/fail.
|
||||
*/
|
||||
public function validate( $rule ) {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -8,7 +8,7 @@ namespace Automattic\WooCommerce\Internal\Admin;
|
|||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\Features\Features;
|
||||
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\DataSourcePoller;
|
||||
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\RemoteInboxNotificationsDataSourcePoller;
|
||||
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\RemoteInboxNotificationsEngine;
|
||||
use Automattic\WooCommerce\Internal\Admin\Notes\AddFirstProduct;
|
||||
use Automattic\WooCommerce\Internal\Admin\Notes\ChoosingTheme;
|
||||
|
@ -146,7 +146,7 @@ class Events {
|
|||
$this->possibly_refresh_data_source_pollers();
|
||||
|
||||
if ( $this->is_remote_inbox_notifications_enabled() ) {
|
||||
DataSourcePoller::get_instance()->read_specs_from_data_sources();
|
||||
RemoteInboxNotificationsDataSourcePoller::get_instance()->read_specs_from_data_sources();
|
||||
RemoteInboxNotificationsEngine::run();
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ namespace Automattic\WooCommerce\Internal\Admin\RemoteFreeExtensions;
|
|||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
use Automattic\WooCommerce\Admin\PluginsHelper;
|
||||
use Automattic\WooCommerce\Admin\RemoteInboxNotifications\RuleEvaluator;
|
||||
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\RuleEvaluator;
|
||||
|
||||
/**
|
||||
* Evaluates the extension and returns it.
|
||||
|
|
|
@ -2,10 +2,11 @@
|
|||
|
||||
namespace Automattic\WooCommerce\Internal\Admin\RemoteFreeExtensions;
|
||||
|
||||
use Automattic\WooCommerce\Admin\RemoteSpecs\DataSourcePoller;
|
||||
/**
|
||||
* Specs data source poller class for remote free extensions.
|
||||
*/
|
||||
class RemoteFreeExtensionsDataSourcePoller extends \Automattic\WooCommerce\Admin\DataSourcePoller {
|
||||
class RemoteFreeExtensionsDataSourcePoller extends DataSourcePoller {
|
||||
|
||||
const ID = 'remote_free_extensions';
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?php
|
||||
namespace Automattic\WooCommerce\Internal\Admin\WCPayPromotion;
|
||||
|
||||
use Automattic\WooCommerce\Admin\DataSourcePoller;
|
||||
use Automattic\WooCommerce\Admin\RemoteSpecs\DataSourcePoller;
|
||||
|
||||
/**
|
||||
* Specs data source poller class for WooCommerce Payment Promotion.
|
||||
|
@ -20,7 +20,7 @@ class WCPayPromotionDataSourcePoller extends DataSourcePoller {
|
|||
/**
|
||||
* Class instance.
|
||||
*
|
||||
* @var Analytics instance
|
||||
* @var WCPayPromotionDataSourcePoller instance
|
||||
*/
|
||||
protected static $instance = null;
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue