339 lines
7.8 KiB
PHP
339 lines
7.8 KiB
PHP
<?php
|
|
/**
|
|
* Conditions Registry
|
|
*
|
|
* @package GenerateBlocks
|
|
*/
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Registry for condition types.
|
|
*/
|
|
class GenerateBlocks_Pro_Conditions_Registry {
|
|
/**
|
|
* Registered condition types.
|
|
*
|
|
* @var array
|
|
*/
|
|
private static $condition_types = [];
|
|
|
|
/**
|
|
* Condition instances cache.
|
|
*
|
|
* @var array
|
|
*/
|
|
private static $instances = [];
|
|
|
|
/**
|
|
* Evaluation results cache (per-request).
|
|
*
|
|
* @var array
|
|
*/
|
|
private static $evaluation_cache = [];
|
|
|
|
/**
|
|
* Register a condition type.
|
|
*
|
|
* @param string $type Condition type identifier.
|
|
* @param array $args Condition arguments.
|
|
* @param string $classname Condition evaluator class name.
|
|
* @return bool
|
|
*/
|
|
public static function register( $type, $args, $classname ) {
|
|
if ( empty( $type ) || empty( $classname ) ) {
|
|
return false;
|
|
}
|
|
|
|
if ( ! class_exists( $classname ) ) {
|
|
return false;
|
|
}
|
|
|
|
// Ensure the class implements our interface.
|
|
$interfaces = class_implements( $classname );
|
|
if ( ! isset( $interfaces['GenerateBlocks_Pro_Condition_Interface'] ) ) {
|
|
return false;
|
|
}
|
|
|
|
$defaults = [
|
|
'label' => '',
|
|
'operators' => [],
|
|
'priority' => 10,
|
|
];
|
|
|
|
$args = wp_parse_args( $args, $defaults );
|
|
|
|
self::$condition_types[ $type ] = [
|
|
'label' => $args['label'],
|
|
'class' => $classname,
|
|
'operators' => $args['operators'],
|
|
'priority' => $args['priority'],
|
|
];
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Unregister a condition type.
|
|
*
|
|
* @param string $type Condition type identifier.
|
|
* @return bool
|
|
*/
|
|
public static function unregister( $type ) {
|
|
if ( ! isset( self::$condition_types[ $type ] ) ) {
|
|
return false;
|
|
}
|
|
|
|
unset( self::$condition_types[ $type ] );
|
|
|
|
if ( isset( self::$instances[ $type ] ) ) {
|
|
unset( self::$instances[ $type ] );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Get all registered condition types.
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function get_all() {
|
|
// Sort by priority.
|
|
uasort(
|
|
self::$condition_types,
|
|
function( $a, $b ) {
|
|
return $a['priority'] <=> $b['priority'];
|
|
}
|
|
);
|
|
|
|
return self::$condition_types;
|
|
}
|
|
|
|
/**
|
|
* Get a specific condition type.
|
|
*
|
|
* @param string $type Condition type identifier.
|
|
* @return array|null
|
|
*/
|
|
public static function get( $type ) {
|
|
return isset( self::$condition_types[ $type ] ) ? self::$condition_types[ $type ] : null;
|
|
}
|
|
|
|
/**
|
|
* Get condition instance.
|
|
*
|
|
* @param string $type Condition type identifier.
|
|
* @return GenerateBlocks_Pro_Condition_Interface|null
|
|
*/
|
|
public static function get_instance( $type ) {
|
|
if ( ! isset( self::$condition_types[ $type ] ) ) {
|
|
return null;
|
|
}
|
|
|
|
if ( ! isset( self::$instances[ $type ] ) ) {
|
|
$classname = self::$condition_types[ $type ]['class'];
|
|
self::$instances[ $type ] = new $classname();
|
|
}
|
|
|
|
return self::$instances[ $type ];
|
|
}
|
|
|
|
/**
|
|
* Evaluate a condition.
|
|
*
|
|
* @param string $type Condition type.
|
|
* @param string $rule Condition rule.
|
|
* @param string $operator Condition operator.
|
|
* @param mixed $value Condition value.
|
|
* @param array $context Additional context.
|
|
* @return bool
|
|
*/
|
|
public static function evaluate( $type, $rule, $operator, $value, $context = [] ) {
|
|
$instance = self::get_instance( $type );
|
|
|
|
if ( ! $instance ) {
|
|
return false;
|
|
}
|
|
|
|
// Cache key for performance - per-request only using class property.
|
|
$cache_data = wp_json_encode( [ $type, $rule, $operator, $value, $context ] );
|
|
$cache_key = md5( $cache_data );
|
|
|
|
if ( isset( self::$evaluation_cache[ $cache_key ] ) ) {
|
|
return self::$evaluation_cache[ $cache_key ];
|
|
}
|
|
|
|
$result = $instance->evaluate( $rule, $operator, $value, $context );
|
|
|
|
// Cache for current request only using class property.
|
|
self::$evaluation_cache[ $cache_key ] = $result;
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Clear the evaluation cache.
|
|
* Used primarily for testing purposes to reset state between tests.
|
|
*
|
|
* @return void
|
|
*/
|
|
public static function clear_evaluation_cache() {
|
|
self::$evaluation_cache = [];
|
|
}
|
|
|
|
/**
|
|
* Register core condition types.
|
|
*/
|
|
public static function register_core_types() {
|
|
// Location.
|
|
self::register(
|
|
'location',
|
|
[
|
|
'label' => __( 'Location', 'generateblocks-pro' ),
|
|
'operators' => [ 'is', 'is_not', 'includes_any', 'includes_all', 'excludes_any', 'excludes_all' ],
|
|
'priority' => 10,
|
|
],
|
|
'GenerateBlocks_Pro_Condition_Location'
|
|
);
|
|
|
|
// Query Parameter.
|
|
self::register(
|
|
'query_arg',
|
|
[
|
|
'label' => __( 'Query Parameter', 'generateblocks-pro' ),
|
|
'operators' => [ 'exists', 'not_exists', 'equals', 'contains', 'not_contains', 'starts_with', 'ends_with' ],
|
|
'priority' => 20,
|
|
],
|
|
'GenerateBlocks_Pro_Condition_Query_Arg'
|
|
);
|
|
|
|
// User Role.
|
|
self::register(
|
|
'user_role',
|
|
[
|
|
'label' => __( 'User Role', 'generateblocks-pro' ),
|
|
'operators' => [ 'is', 'is_not', 'includes_any', 'includes_all' ],
|
|
'priority' => 30,
|
|
],
|
|
'GenerateBlocks_Pro_Condition_User_Role'
|
|
);
|
|
|
|
// Date & Time.
|
|
self::register(
|
|
'date_time',
|
|
[
|
|
'label' => __( 'Date & Time', 'generateblocks-pro' ),
|
|
'operators' => [ 'before', 'after', 'between', 'on' ],
|
|
'priority' => 40,
|
|
],
|
|
'GenerateBlocks_Pro_Condition_Date_Time'
|
|
);
|
|
|
|
// Device.
|
|
self::register(
|
|
'device',
|
|
[
|
|
'label' => __( 'Device', 'generateblocks-pro' ),
|
|
'operators' => [ 'is', 'is_not' ],
|
|
'priority' => 50,
|
|
],
|
|
'GenerateBlocks_Pro_Condition_Device'
|
|
);
|
|
|
|
// Referrer.
|
|
self::register(
|
|
'referrer',
|
|
[
|
|
'label' => __( 'Referrer', 'generateblocks-pro' ),
|
|
'operators' => [ 'is', 'is_not', 'contains', 'not_contains', 'equals', 'starts_with', 'ends_with' ],
|
|
'priority' => 60,
|
|
],
|
|
'GenerateBlocks_Pro_Condition_Referrer'
|
|
);
|
|
|
|
// Post Meta.
|
|
self::register(
|
|
'post_meta',
|
|
[
|
|
'label' => __( 'Post Meta', 'generateblocks-pro' ),
|
|
'operators' => [ 'exists', 'not_exists', 'equals', 'contains', 'not_contains', 'greater_than', 'less_than', 'includes_any', 'includes_all' ],
|
|
'priority' => 70,
|
|
],
|
|
'GenerateBlocks_Pro_Condition_Post_Meta'
|
|
);
|
|
|
|
// User Meta.
|
|
self::register(
|
|
'user_meta',
|
|
[
|
|
'label' => __( 'User Meta', 'generateblocks-pro' ),
|
|
'operators' => [ 'exists', 'not_exists', 'equals', 'contains', 'not_contains', 'greater_than', 'less_than', 'includes_any', 'includes_all' ],
|
|
'priority' => 80,
|
|
],
|
|
'GenerateBlocks_Pro_Condition_User_Meta'
|
|
);
|
|
|
|
// Cookie.
|
|
self::register(
|
|
'cookie',
|
|
[
|
|
'label' => __( 'Cookie', 'generateblocks-pro' ),
|
|
'operators' => [ 'exists', 'not_exists', 'equals', 'contains', 'not_contains', 'starts_with', 'ends_with' ],
|
|
'priority' => 90,
|
|
],
|
|
'GenerateBlocks_Pro_Condition_Cookie'
|
|
);
|
|
|
|
// Language.
|
|
self::register(
|
|
'language',
|
|
[
|
|
'label' => __( 'Language', 'generateblocks-pro' ),
|
|
'operators' => [ 'is', 'is_not' ],
|
|
'priority' => 95,
|
|
],
|
|
'GenerateBlocks_Pro_Condition_Language'
|
|
);
|
|
|
|
// Options.
|
|
self::register(
|
|
'options',
|
|
[
|
|
'label' => __( 'Site Options', 'generateblocks-pro' ),
|
|
'operators' => [ 'exists', 'not_exists', 'equals', 'contains', 'not_contains', 'greater_than', 'less_than', 'includes_any', 'includes_all' ],
|
|
'priority' => 100,
|
|
],
|
|
'GenerateBlocks_Pro_Condition_Options'
|
|
);
|
|
|
|
// Author.
|
|
self::register(
|
|
'author',
|
|
[
|
|
'label' => __( 'Author', 'generateblocks-pro' ),
|
|
'operators' => [ 'is', 'is_not', 'exists', 'not_exists', 'equals', 'contains', 'not_contains', 'includes_any', 'excludes_any' ],
|
|
'priority' => 110,
|
|
],
|
|
'GenerateBlocks_Pro_Condition_Author'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Reset registry for testing purposes only.
|
|
*
|
|
* @since 2.2.0
|
|
*/
|
|
public static function reset_for_testing() {
|
|
// Only allow in testing environment.
|
|
if ( ! defined( 'GB_TESTING' ) || ! GB_TESTING ) {
|
|
return;
|
|
}
|
|
|
|
self::$condition_types = [];
|
|
self::$instances = [];
|
|
}
|
|
}
|