initial
This commit is contained in:
+245
@@ -0,0 +1,245 @@
|
||||
<?php
|
||||
/**
|
||||
* Author Condition
|
||||
*
|
||||
* @package GenerateBlocks
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Author condition evaluator.
|
||||
*/
|
||||
class GenerateBlocks_Pro_Condition_Author extends GenerateBlocks_Pro_Condition_Abstract {
|
||||
/**
|
||||
* Evaluate the condition.
|
||||
*
|
||||
* @param string $rule The condition rule.
|
||||
* @param string $operator The condition operator.
|
||||
* @param mixed $value The value to check against.
|
||||
* @param array $context Additional context data.
|
||||
* @return bool
|
||||
*/
|
||||
public function evaluate( $rule, $operator, $value, $context = [] ) {
|
||||
$author_id = null;
|
||||
|
||||
// Use context if provided, otherwise get current post.
|
||||
$post_id = ! empty( $context['post_id'] ) ? $context['post_id'] : get_the_ID();
|
||||
if ( $post_id ) {
|
||||
$post = get_post( $post_id );
|
||||
if ( $post ) {
|
||||
$author_id = $post->post_author;
|
||||
}
|
||||
} elseif ( is_author() ) {
|
||||
// Special case for author archive pages.
|
||||
$author_id = get_queried_object_id();
|
||||
}
|
||||
|
||||
if ( ! $author_id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle author meta custom fields.
|
||||
if ( 'author_meta' === $rule ) {
|
||||
$parsed = $this->parse_meta_field( $rule, $value );
|
||||
$meta_key = $parsed['field_name'];
|
||||
$comparison_value = $parsed['comparison_value'];
|
||||
|
||||
if ( empty( $meta_key ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle existence operators using standardized method.
|
||||
if ( in_array( $operator, [ 'exists', 'not_exists' ], true ) ) {
|
||||
return $this->evaluate_meta_existence( 'user', $author_id, $meta_key, $operator );
|
||||
}
|
||||
|
||||
// Handle other operators using standardized method.
|
||||
return $this->evaluate_meta_value( 'user', $author_id, $meta_key, $operator, $comparison_value );
|
||||
}
|
||||
|
||||
// Handle multi-value operators for author selection.
|
||||
if ( $this->is_multi_value_operator( $operator ) ) {
|
||||
return $this->evaluate_multi_value_generic(
|
||||
$operator,
|
||||
$value,
|
||||
function( $check_value ) use ( $rule, $author_id ) {
|
||||
return $this->check_single_author_match( $rule, $check_value, $author_id );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
$is_match = false;
|
||||
|
||||
switch ( $rule ) {
|
||||
case 'author_name':
|
||||
// Check author display name or login.
|
||||
if ( empty( $value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$author = get_userdata( $author_id );
|
||||
if ( $author ) {
|
||||
$is_match = ( $author->display_name === $value ) || ( $author->user_login === $value );
|
||||
}
|
||||
break;
|
||||
|
||||
case 'author_id':
|
||||
if ( empty( $value ) || '' === $value ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check specific author ID.
|
||||
$is_match = ( $author_id == $value ); // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
|
||||
break;
|
||||
|
||||
case 'first_name':
|
||||
case 'last_name':
|
||||
case 'nickname':
|
||||
case 'description':
|
||||
// Check specific user meta fields using standardized method.
|
||||
if ( in_array( $operator, [ 'exists', 'not_exists' ], true ) ) {
|
||||
return $this->evaluate_meta_existence( 'user', $author_id, $rule, $operator );
|
||||
}
|
||||
|
||||
return $this->evaluate_meta_value( 'user', $author_id, $rule, $operator, $value );
|
||||
}
|
||||
|
||||
return 'is_not' === $operator ? ! $is_match : $is_match;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a single author value matches the current author.
|
||||
*
|
||||
* @param string $rule The condition rule.
|
||||
* @param mixed $value The value to check.
|
||||
* @param int $author_id Current author ID.
|
||||
* @return bool
|
||||
*/
|
||||
private function check_single_author_match( $rule, $value, $author_id ) {
|
||||
switch ( $rule ) {
|
||||
case 'author_id':
|
||||
if ( empty( $value ) || '' === $value ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ( $author_id == $value ); // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
|
||||
|
||||
case 'author_name':
|
||||
if ( empty( $value ) || '' === $value ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$author = get_userdata( $author_id );
|
||||
if ( $author ) {
|
||||
return ( $author->display_name === $value ) || ( $author->user_login === $value );
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available rules for this condition type.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_rules() {
|
||||
$rules = [
|
||||
'author_id' => __( 'Author ID', 'generateblocks-pro' ),
|
||||
'author_name' => __( 'Author Name', 'generateblocks-pro' ),
|
||||
'author_meta' => __( 'Author Meta Key', 'generateblocks-pro' ),
|
||||
];
|
||||
|
||||
// Add common author meta fields.
|
||||
$author_fields = [
|
||||
'first_name' => __( 'First Name', 'generateblocks-pro' ),
|
||||
'last_name' => __( 'Last Name', 'generateblocks-pro' ),
|
||||
'nickname' => __( 'Nickname', 'generateblocks-pro' ),
|
||||
'description' => __( 'Biographical Info', 'generateblocks-pro' ),
|
||||
];
|
||||
|
||||
$rules = array_merge( $rules, $author_fields );
|
||||
|
||||
return apply_filters( 'generateblocks_author_rules', $rules );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get metadata for a specific rule.
|
||||
*
|
||||
* @param string $rule The rule key.
|
||||
* @return array
|
||||
*/
|
||||
public function get_rule_metadata( $rule ) {
|
||||
if ( 'author_meta' === $rule ) {
|
||||
return [
|
||||
'needs_value' => true,
|
||||
'value_type' => 'custom_field',
|
||||
'supports_multi' => true,
|
||||
];
|
||||
}
|
||||
|
||||
if ( 'author_id' === $rule ) {
|
||||
return [
|
||||
'needs_value' => true,
|
||||
'value_type' => 'object_selector',
|
||||
'supports_multi' => true,
|
||||
];
|
||||
}
|
||||
|
||||
// Text fields don't need greater_than/less_than.
|
||||
return [
|
||||
'needs_value' => true,
|
||||
'value_type' => 'text',
|
||||
'supports_multi' => false,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize the condition value.
|
||||
*
|
||||
* @param mixed $value The value to sanitize.
|
||||
* @param string $rule The rule being used.
|
||||
* @return mixed
|
||||
*/
|
||||
public function sanitize_value( $value, $rule ) {
|
||||
if ( 'author_meta' === $rule ) {
|
||||
return $this->sanitize_custom_value( $value );
|
||||
}
|
||||
|
||||
// Handle array values for multi-select.
|
||||
if ( is_array( $value ) ) {
|
||||
return array_map( 'sanitize_text_field', $value );
|
||||
}
|
||||
|
||||
return sanitize_text_field( $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get operators available for a specific author rule.
|
||||
*
|
||||
* @param string $rule The rule key.
|
||||
* @return array Array of operator keys.
|
||||
*/
|
||||
public function get_operators_for_rule( $rule ) {
|
||||
// Author meta supports all operators.
|
||||
if ( 'author_meta' === $rule ) {
|
||||
return [ 'exists', 'not_exists', 'equals', 'contains', 'not_contains', 'includes_any', 'includes_all', 'excludes_any', 'excludes_all' ];
|
||||
}
|
||||
|
||||
// Author ID supports multi-select.
|
||||
if ( 'author_id' === $rule ) {
|
||||
return [ 'is', 'is_not', 'includes_any', 'excludes_any' ];
|
||||
}
|
||||
|
||||
// Text fields - no greater_than/less_than.
|
||||
if ( in_array( $rule, [ 'author_name', 'first_name', 'last_name', 'nickname', 'description' ], true ) ) {
|
||||
return [ 'exists', 'not_exists', 'equals', 'contains', 'not_contains' ];
|
||||
}
|
||||
|
||||
return [ 'is', 'is_not' ];
|
||||
}
|
||||
}
|
||||
+153
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
/**
|
||||
* Cookie Condition
|
||||
*
|
||||
* @package GenerateBlocks
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cookie condition evaluator.
|
||||
*/
|
||||
class GenerateBlocks_Pro_Condition_Cookie extends GenerateBlocks_Pro_Condition_Abstract {
|
||||
/**
|
||||
* Evaluate the condition.
|
||||
*
|
||||
* @param string $rule The condition rule.
|
||||
* @param string $operator The condition operator.
|
||||
* @param mixed $value The value to check against.
|
||||
* @param array $context Additional context data.
|
||||
* @return bool
|
||||
*/
|
||||
public function evaluate( $rule, $operator, $value, $context = [] ) {
|
||||
// Parse the cookie name and comparison value using standardized method.
|
||||
$parsed = $this->parse_meta_field( $rule, $value );
|
||||
$cookie_name = $parsed['field_name'];
|
||||
$comparison_value = $parsed['comparison_value'];
|
||||
|
||||
if ( empty( $cookie_name ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch ( $operator ) {
|
||||
case 'exists':
|
||||
return $this->cookie_exists( $cookie_name );
|
||||
|
||||
case 'not_exists':
|
||||
return ! $this->cookie_exists( $cookie_name );
|
||||
|
||||
case 'has_value':
|
||||
return $this->cookie_has_value( $cookie_name );
|
||||
|
||||
case 'no_value':
|
||||
return ! $this->cookie_has_value( $cookie_name );
|
||||
|
||||
case 'equals':
|
||||
$cookie_value = $this->get_cookie_value( $cookie_name );
|
||||
return null !== $cookie_value && $cookie_value === $comparison_value;
|
||||
|
||||
case 'contains':
|
||||
$cookie_value = $this->get_cookie_value( $cookie_name );
|
||||
return null !== $cookie_value && false !== strpos( $cookie_value, $comparison_value );
|
||||
|
||||
case 'not_contains':
|
||||
$cookie_value = $this->get_cookie_value( $cookie_name );
|
||||
return null === $cookie_value || false === strpos( $cookie_value, $comparison_value );
|
||||
|
||||
case 'starts_with':
|
||||
$cookie_value = $this->get_cookie_value( $cookie_name );
|
||||
return null !== $cookie_value && 0 === strpos( $cookie_value, $comparison_value );
|
||||
|
||||
case 'ends_with':
|
||||
$cookie_value = $this->get_cookie_value( $cookie_name );
|
||||
return null !== $cookie_value && substr( $cookie_value, -strlen( $comparison_value ) ) === $comparison_value;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available rules for this condition type.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_rules() {
|
||||
$rules = [
|
||||
'custom' => __( 'Custom Cookie', 'generateblocks-pro' ),
|
||||
];
|
||||
|
||||
// Add common cookie rules that might be useful.
|
||||
$common_cookies = [
|
||||
'wordpress_logged_in' => __( 'WordPress Logged In Cookie', 'generateblocks-pro' ),
|
||||
'comment_author' => __( 'Comment Author Cookie', 'generateblocks-pro' ),
|
||||
];
|
||||
|
||||
$rules = array_merge( $rules, $common_cookies );
|
||||
|
||||
// Allow filtering to add predefined cookies.
|
||||
return apply_filters( 'generateblocks_cookie_rules', $rules );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get metadata for a specific rule.
|
||||
*
|
||||
* @param string $rule The rule key.
|
||||
* @return array
|
||||
*/
|
||||
public function get_rule_metadata( $rule ) {
|
||||
if ( 'custom' === $rule ) {
|
||||
return [
|
||||
'needs_value' => true,
|
||||
'value_type' => 'custom_field',
|
||||
];
|
||||
}
|
||||
|
||||
// WordPress cookies typically need existence checks only.
|
||||
if ( in_array( $rule, [ 'wordpress_logged_in', 'comment_author' ], true ) ) {
|
||||
return [
|
||||
'needs_value' => false,
|
||||
'value_type' => 'none',
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'needs_value' => true,
|
||||
'value_type' => 'text',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize the condition value.
|
||||
*
|
||||
* @param mixed $value The value to sanitize.
|
||||
* @param string $rule The rule being used.
|
||||
* @return mixed
|
||||
*/
|
||||
public function sanitize_value( $value, $rule ) {
|
||||
if ( 'custom' === $rule ) {
|
||||
return $this->sanitize_custom_value( $value );
|
||||
}
|
||||
|
||||
return sanitize_text_field( $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get operators available for a specific cookie rule.
|
||||
*
|
||||
* @param string $rule The rule key.
|
||||
* @return array Array of operator keys.
|
||||
*/
|
||||
public function get_operators_for_rule( $rule ) {
|
||||
// WordPress cookies typically only need existence checks.
|
||||
if ( in_array( $rule, [ 'wordpress_logged_in', 'comment_author' ], true ) ) {
|
||||
return [ 'exists', 'not_exists', 'has_value', 'no_value' ];
|
||||
}
|
||||
|
||||
// Custom cookies support all text operators including not_contains.
|
||||
return [ 'exists', 'not_exists', 'has_value', 'no_value', 'equals', 'contains', 'not_contains', 'starts_with', 'ends_with' ];
|
||||
}
|
||||
}
|
||||
+399
@@ -0,0 +1,399 @@
|
||||
<?php
|
||||
/**
|
||||
* Date Time Condition
|
||||
*
|
||||
* @package GenerateBlocks
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Date/time condition evaluator.
|
||||
*/
|
||||
class GenerateBlocks_Pro_Condition_Date_Time extends GenerateBlocks_Pro_Condition_Abstract {
|
||||
/**
|
||||
* Evaluate the condition.
|
||||
*
|
||||
* @param string $rule The condition rule.
|
||||
* @param string $operator The condition operator.
|
||||
* @param mixed $value The value to check against.
|
||||
* @param array $context Additional context data.
|
||||
* @return bool
|
||||
*/
|
||||
public function evaluate( $rule, $operator, $value, $context = [] ) {
|
||||
// Handle day of week separately with multi-select support.
|
||||
if ( 'day_of_week' === $rule ) {
|
||||
return $this->evaluate_day_of_week( $operator, $value );
|
||||
}
|
||||
|
||||
// Get current time as DateTime object for proper timezone handling.
|
||||
$current_datetime = current_datetime();
|
||||
|
||||
if ( empty( $value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle time-only rules (current_time and time_of_day).
|
||||
if ( in_array( $rule, [ 'current_time', 'time_of_day' ], true ) ) {
|
||||
return $this->evaluate_time_only( $current_datetime, $operator, $value );
|
||||
}
|
||||
|
||||
// For date-based rules, use full timestamp comparison.
|
||||
$current_time = $current_datetime->getTimestamp();
|
||||
|
||||
switch ( $operator ) {
|
||||
case 'before':
|
||||
return $this->is_before( $current_time, $value );
|
||||
|
||||
case 'after':
|
||||
return $this->is_after( $current_time, $value );
|
||||
|
||||
case 'on':
|
||||
return $this->is_on( $current_time, $value, $rule );
|
||||
|
||||
case 'between':
|
||||
return $this->is_between( $current_time, $value );
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate time-only condition (ignoring date).
|
||||
*
|
||||
* @param DateTime $current_datetime Current DateTime object.
|
||||
* @param string $operator The condition operator.
|
||||
* @param mixed $value The value to check against.
|
||||
* @return bool
|
||||
*/
|
||||
private function evaluate_time_only( $current_datetime, $operator, $value ) {
|
||||
// Convert current time to seconds since midnight.
|
||||
$current_hours = (int) $current_datetime->format( 'H' );
|
||||
$current_minutes = (int) $current_datetime->format( 'i' );
|
||||
$current_seconds_component = (int) $current_datetime->format( 's' );
|
||||
|
||||
$current_seconds = ( $current_hours * HOUR_IN_SECONDS ) +
|
||||
( $current_minutes * MINUTE_IN_SECONDS ) +
|
||||
$current_seconds_component;
|
||||
|
||||
switch ( $operator ) {
|
||||
case 'before':
|
||||
$target_seconds = $this->parse_time_to_seconds( $value );
|
||||
return false !== $target_seconds && $current_seconds < $target_seconds;
|
||||
|
||||
case 'after':
|
||||
$target_seconds = $this->parse_time_to_seconds( $value );
|
||||
return false !== $target_seconds && $current_seconds > $target_seconds;
|
||||
|
||||
case 'on':
|
||||
// For time "on", check if within the same hour.
|
||||
$target_seconds = $this->parse_time_to_seconds( $value );
|
||||
if ( false === $target_seconds ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$target_hour = intval( $target_seconds / HOUR_IN_SECONDS );
|
||||
return $current_hours === $target_hour;
|
||||
|
||||
case 'between':
|
||||
// Handle time range (e.g., "09:00, 17:00" or "22:00, 02:00" for overnight).
|
||||
$times = array_map( 'trim', explode( ',', $value ) );
|
||||
if ( 2 !== count( $times ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$start_seconds = $this->parse_time_to_seconds( $times[0] );
|
||||
$end_seconds = $this->parse_time_to_seconds( $times[1] );
|
||||
|
||||
if ( false === $start_seconds || false === $end_seconds ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle overnight ranges (e.g., 22:00 to 02:00).
|
||||
if ( $start_seconds > $end_seconds ) {
|
||||
// Current time is either after start OR before end.
|
||||
return $current_seconds >= $start_seconds || $current_seconds <= $end_seconds;
|
||||
} else {
|
||||
// Normal range within same day.
|
||||
return $current_seconds >= $start_seconds && $current_seconds <= $end_seconds;
|
||||
}
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse time string to seconds since midnight.
|
||||
*
|
||||
* @param string $time_str Time string (HH:MM or full datetime).
|
||||
* @return int|false Seconds since midnight or false on failure.
|
||||
*/
|
||||
private function parse_time_to_seconds( $time_str ) {
|
||||
if ( empty( $time_str ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// For time-only values (HH:MM format), parse directly in WordPress timezone
|
||||
// to avoid timezone conversion issues.
|
||||
try {
|
||||
// Create DateTime in WordPress timezone directly.
|
||||
$datetime = new DateTime( $time_str, wp_timezone() );
|
||||
} catch ( Exception $e ) {
|
||||
// If parsing fails, try with today's date prepended.
|
||||
try {
|
||||
$today = current_datetime()->format( 'Y-m-d' );
|
||||
$datetime = new DateTime( $today . ' ' . $time_str, wp_timezone() );
|
||||
} catch ( Exception $e2 ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Extract time components.
|
||||
$hours = (int) $datetime->format( 'H' );
|
||||
$minutes = (int) $datetime->format( 'i' );
|
||||
$seconds = (int) $datetime->format( 's' );
|
||||
|
||||
// Calculate seconds since midnight.
|
||||
$result = ( $hours * HOUR_IN_SECONDS ) + ( $minutes * MINUTE_IN_SECONDS ) + $seconds;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate day of week condition.
|
||||
*
|
||||
* @param string $operator The condition operator.
|
||||
* @param mixed $value The value to check against.
|
||||
* @return bool
|
||||
*/
|
||||
private function evaluate_day_of_week( $operator, $value ) {
|
||||
// Get current day of week (1 = Monday, 7 = Sunday).
|
||||
$current_day = intval( current_datetime()->format( 'N' ) );
|
||||
|
||||
// Handle multi-value operators.
|
||||
if ( $this->is_multi_value_operator( $operator ) ) {
|
||||
return $this->evaluate_multi_value( $operator, $current_day, $value );
|
||||
}
|
||||
|
||||
// Parse value for single operators.
|
||||
$target_day = intval( $value );
|
||||
|
||||
switch ( $operator ) {
|
||||
case 'is':
|
||||
return $current_day === $target_day;
|
||||
|
||||
case 'is_not':
|
||||
return $current_day !== $target_day;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current time is before target time.
|
||||
*
|
||||
* @param int $current_time Current timestamp.
|
||||
* @param string $target_time Target time string.
|
||||
* @return bool
|
||||
*/
|
||||
private function is_before( $current_time, $target_time ) {
|
||||
try {
|
||||
// Parse the target time using WordPress timezone.
|
||||
$target_datetime = new DateTime( $target_time, wp_timezone() );
|
||||
$compare_time = $target_datetime->getTimestamp();
|
||||
return $current_time < $compare_time;
|
||||
} catch ( Exception $e ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current time is after target time.
|
||||
*
|
||||
* @param int $current_time Current timestamp.
|
||||
* @param string $target_time Target time string.
|
||||
* @return bool
|
||||
*/
|
||||
private function is_after( $current_time, $target_time ) {
|
||||
try {
|
||||
// Parse the target time using WordPress timezone.
|
||||
$target_datetime = new DateTime( $target_time, wp_timezone() );
|
||||
$compare_time = $target_datetime->getTimestamp();
|
||||
return $current_time > $compare_time;
|
||||
} catch ( Exception $e ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current time is on target date.
|
||||
*
|
||||
* @param int $current_time Current timestamp.
|
||||
* @param string $target_time Target time string.
|
||||
* @param string $rule The rule type.
|
||||
* @return bool
|
||||
*/
|
||||
private function is_on( $current_time, $target_time, $rule ) {
|
||||
try {
|
||||
// Parse the target time using WordPress timezone.
|
||||
$target_datetime = new DateTime( $target_time, wp_timezone() );
|
||||
$current_datetime = new DateTime();
|
||||
$current_datetime->setTimestamp( $current_time );
|
||||
$current_datetime->setTimezone( wp_timezone() );
|
||||
|
||||
if ( 'current_date' === $rule ) {
|
||||
// Compare dates in WordPress timezone.
|
||||
return $current_datetime->format( 'Y-m-d' ) === $target_datetime->format( 'Y-m-d' );
|
||||
}
|
||||
|
||||
// For time comparison, check if within the same hour.
|
||||
return $current_datetime->format( 'Y-m-d H' ) === $target_datetime->format( 'Y-m-d H' );
|
||||
} catch ( Exception $e ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current time is between two times.
|
||||
*
|
||||
* @param int $current_time Current timestamp.
|
||||
* @param string $value Comma-separated start and end times.
|
||||
* @return bool
|
||||
*/
|
||||
private function is_between( $current_time, $value ) {
|
||||
$dates = array_map( 'trim', explode( ',', $value ) );
|
||||
if ( 2 !== count( $dates ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
// Parse both dates using WordPress timezone.
|
||||
$start_datetime = new DateTime( $dates[0], wp_timezone() );
|
||||
$end_datetime = new DateTime( $dates[1], wp_timezone() );
|
||||
|
||||
$start_time = $start_datetime->getTimestamp();
|
||||
$end_time = $end_datetime->getTimestamp();
|
||||
|
||||
return $current_time >= $start_time && $current_time <= $end_time;
|
||||
} catch ( Exception $e ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available rules for this condition type.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_rules() {
|
||||
$rules = [
|
||||
'current_date' => __( 'Date', 'generateblocks-pro' ),
|
||||
'current_time' => __( 'Time', 'generateblocks-pro' ),
|
||||
'day_of_week' => __( 'Day of Week', 'generateblocks-pro' ),
|
||||
'time_of_day' => __( 'Time of Day', 'generateblocks-pro' ), // Hidden in UI, kept for backward compatibility.
|
||||
];
|
||||
|
||||
return apply_filters( 'generateblocks_date_time_rules', $rules );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get metadata for a specific rule.
|
||||
*
|
||||
* @param string $rule The rule key.
|
||||
* @return array
|
||||
*/
|
||||
public function get_rule_metadata( $rule ) {
|
||||
if ( 'day_of_week' === $rule ) {
|
||||
return [
|
||||
'needs_value' => true,
|
||||
'value_type' => 'day_selector',
|
||||
'supports_multi' => true,
|
||||
];
|
||||
}
|
||||
|
||||
// Time-only rules use time picker.
|
||||
if ( in_array( $rule, [ 'current_time', 'time_of_day' ], true ) ) {
|
||||
return [
|
||||
'needs_value' => true,
|
||||
'value_type' => 'time',
|
||||
];
|
||||
}
|
||||
|
||||
// Date rule uses datetime picker.
|
||||
return [
|
||||
'needs_value' => true,
|
||||
'value_type' => 'datetime',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get operators available for a specific date/time rule.
|
||||
*
|
||||
* @param string $rule The rule key.
|
||||
* @return array Array of operator keys.
|
||||
*/
|
||||
public function get_operators_for_rule( $rule ) {
|
||||
if ( 'day_of_week' === $rule ) {
|
||||
return [ 'is', 'is_not', 'includes_any', 'excludes_any' ];
|
||||
}
|
||||
|
||||
// Other date/time rules use temporal operators.
|
||||
return [ 'before', 'after', 'between', 'on' ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available day options.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_day_options() {
|
||||
return [
|
||||
'1' => __( 'Monday', 'generateblocks-pro' ),
|
||||
'2' => __( 'Tuesday', 'generateblocks-pro' ),
|
||||
'3' => __( 'Wednesday', 'generateblocks-pro' ),
|
||||
'4' => __( 'Thursday', 'generateblocks-pro' ),
|
||||
'5' => __( 'Friday', 'generateblocks-pro' ),
|
||||
'6' => __( 'Saturday', 'generateblocks-pro' ),
|
||||
'7' => __( 'Sunday', 'generateblocks-pro' ),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize the condition value.
|
||||
*
|
||||
* @param mixed $value The value to sanitize.
|
||||
* @param string $rule The rule being used.
|
||||
* @return mixed
|
||||
*/
|
||||
public function sanitize_value( $value, $rule ) {
|
||||
if ( 'day_of_week' === $rule ) {
|
||||
// Handle array values for multi-select.
|
||||
if ( is_array( $value ) ) {
|
||||
return array_map( 'intval', $value );
|
||||
}
|
||||
|
||||
// Try to decode JSON array.
|
||||
$decoded = json_decode( $value, true );
|
||||
if ( is_array( $decoded ) ) {
|
||||
return wp_json_encode( array_map( 'intval', $decoded ) );
|
||||
}
|
||||
|
||||
// Single value.
|
||||
return intval( $value );
|
||||
}
|
||||
|
||||
// For between operator, ensure proper format.
|
||||
if ( false !== strpos( $value, ',' ) ) {
|
||||
$dates = array_map( 'trim', explode( ',', $value ) );
|
||||
$sanitized_dates = array_map( 'sanitize_text_field', $dates );
|
||||
return implode( ', ', $sanitized_dates );
|
||||
}
|
||||
|
||||
return sanitize_text_field( $value );
|
||||
}
|
||||
}
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
/**
|
||||
* Device Condition
|
||||
*
|
||||
* @package GenerateBlocks
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Device condition evaluator.
|
||||
*/
|
||||
class GenerateBlocks_Pro_Condition_Device extends GenerateBlocks_Pro_Condition_Abstract {
|
||||
/**
|
||||
* Evaluate the condition.
|
||||
*
|
||||
* @param string $rule The condition rule.
|
||||
* @param string $operator The condition operator.
|
||||
* @param mixed $value The value to check against.
|
||||
* @param array $context Additional context data.
|
||||
* @return bool
|
||||
*/
|
||||
public function evaluate( $rule, $operator, $value, $context = [] ) {
|
||||
$is_match = false;
|
||||
|
||||
if ( ! function_exists( 'wp_is_mobile' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch ( $rule ) {
|
||||
case 'mobile':
|
||||
$is_match = wp_is_mobile() && ! $this->is_tablet();
|
||||
break;
|
||||
|
||||
case 'tablet':
|
||||
$is_match = $this->is_tablet();
|
||||
break;
|
||||
|
||||
case 'desktop':
|
||||
$is_match = ! wp_is_mobile();
|
||||
break;
|
||||
|
||||
case 'ios':
|
||||
$is_match = $this->is_ios();
|
||||
break;
|
||||
|
||||
case 'android':
|
||||
$is_match = $this->is_android();
|
||||
break;
|
||||
}
|
||||
|
||||
return 'is_not' === $operator ? ! $is_match : $is_match;
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic tablet detection.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_tablet() {
|
||||
$user_agent = $this->get_server_var( 'HTTP_USER_AGENT' );
|
||||
return (bool) preg_match( '/(tablet|ipad|playbook|silk)|(android(?!.*mobile))/i', $user_agent );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if device is iOS.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_ios() {
|
||||
$user_agent = $this->get_server_var( 'HTTP_USER_AGENT' );
|
||||
return (bool) preg_match( '/(iPhone|iPod|iPad)/i', $user_agent );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if device is Android.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_android() {
|
||||
$user_agent = $this->get_server_var( 'HTTP_USER_AGENT' );
|
||||
return (bool) preg_match( '/Android/i', $user_agent );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available rules for this condition type.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_rules() {
|
||||
$rules = [
|
||||
'mobile' => __( 'Mobile', 'generateblocks-pro' ),
|
||||
'tablet' => __( 'Tablet', 'generateblocks-pro' ),
|
||||
'desktop' => __( 'Desktop', 'generateblocks-pro' ),
|
||||
'ios' => __( 'iOS', 'generateblocks-pro' ),
|
||||
'android' => __( 'Android', 'generateblocks-pro' ),
|
||||
];
|
||||
|
||||
return apply_filters( 'generateblocks_device_rules', $rules );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get metadata for a specific rule.
|
||||
*
|
||||
* @param string $rule The rule key.
|
||||
* @return array
|
||||
*/
|
||||
public function get_rule_metadata( $rule ) {
|
||||
return [
|
||||
'needs_value' => false,
|
||||
'value_type' => 'none',
|
||||
];
|
||||
}
|
||||
}
|
||||
+199
@@ -0,0 +1,199 @@
|
||||
<?php
|
||||
/**
|
||||
* Language Condition
|
||||
*
|
||||
* @package GenerateBlocks
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Language condition evaluator.
|
||||
*/
|
||||
class GenerateBlocks_Pro_Condition_Language extends GenerateBlocks_Pro_Condition_Abstract {
|
||||
/**
|
||||
* Evaluate the condition.
|
||||
*
|
||||
* @param string $rule The condition rule.
|
||||
* @param string $operator The condition operator.
|
||||
* @param mixed $value The value to check against.
|
||||
* @param array $context Additional context data.
|
||||
* @return bool
|
||||
*/
|
||||
public function evaluate( $rule, $operator, $value, $context = [] ) {
|
||||
$current_locale = $this->get_current_locale();
|
||||
$is_match = false;
|
||||
|
||||
switch ( $rule ) {
|
||||
case 'locale':
|
||||
// Full locale match (e.g., en_US).
|
||||
$is_match = $current_locale === $value;
|
||||
break;
|
||||
|
||||
case 'language':
|
||||
// Language code match (e.g., en).
|
||||
$current_lang = substr( $current_locale, 0, 2 );
|
||||
$is_match = $current_lang === $value;
|
||||
break;
|
||||
|
||||
case 'rtl':
|
||||
// Check if Right-to-Left language.
|
||||
$is_match = is_rtl();
|
||||
break;
|
||||
|
||||
case 'custom':
|
||||
// Custom locale check.
|
||||
$is_match = $current_locale === $value;
|
||||
break;
|
||||
|
||||
default:
|
||||
// For predefined locales (en_US, fr_FR, etc.), check directly.
|
||||
$is_match = $current_locale === $rule;
|
||||
break;
|
||||
}
|
||||
|
||||
return 'is_not' === $operator ? ! $is_match : $is_match;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current locale.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_current_locale() {
|
||||
// Check for WPML.
|
||||
if ( defined( 'ICL_LANGUAGE_CODE' ) ) {
|
||||
global $sitepress;
|
||||
if ( $sitepress && method_exists( $sitepress, 'get_locale' ) ) {
|
||||
$locale = $sitepress->get_locale( ICL_LANGUAGE_CODE );
|
||||
if ( $locale ) {
|
||||
return $locale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for Polylang.
|
||||
if ( function_exists( 'pll_current_language' ) ) {
|
||||
$locale = pll_current_language( 'locale' );
|
||||
if ( $locale ) {
|
||||
return $locale;
|
||||
}
|
||||
}
|
||||
|
||||
// Default WordPress locale.
|
||||
return get_locale();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available rules for this condition type.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_rules() {
|
||||
$rules = [
|
||||
'locale' => __( 'Full Locale (e.g., en_US)', 'generateblocks-pro' ),
|
||||
'language' => __( 'Language Code (e.g., en)', 'generateblocks-pro' ),
|
||||
'rtl' => __( 'RTL Language', 'generateblocks-pro' ),
|
||||
'custom' => __( 'Custom Locale', 'generateblocks-pro' ),
|
||||
];
|
||||
|
||||
// Add common locales.
|
||||
$common_locales = [
|
||||
'en_US' => __( 'English (United States)', 'generateblocks-pro' ),
|
||||
'en_GB' => __( 'English (UK)', 'generateblocks-pro' ),
|
||||
'en_CA' => __( 'English (Canada)', 'generateblocks-pro' ),
|
||||
'en_AU' => __( 'English (Australia)', 'generateblocks-pro' ),
|
||||
'es_ES' => __( 'Spanish (Spain)', 'generateblocks-pro' ),
|
||||
'es_MX' => __( 'Spanish (Mexico)', 'generateblocks-pro' ),
|
||||
'fr_FR' => __( 'French (France)', 'generateblocks-pro' ),
|
||||
'fr_CA' => __( 'French (Canada)', 'generateblocks-pro' ),
|
||||
'de_DE' => __( 'German', 'generateblocks-pro' ),
|
||||
'it_IT' => __( 'Italian', 'generateblocks-pro' ),
|
||||
'pt_BR' => __( 'Portuguese (Brazil)', 'generateblocks-pro' ),
|
||||
'pt_PT' => __( 'Portuguese (Portugal)', 'generateblocks-pro' ),
|
||||
'nl_NL' => __( 'Dutch', 'generateblocks-pro' ),
|
||||
'ru_RU' => __( 'Russian', 'generateblocks-pro' ),
|
||||
'ja' => __( 'Japanese', 'generateblocks-pro' ),
|
||||
'zh_CN' => __( 'Chinese (Simplified)', 'generateblocks-pro' ),
|
||||
'zh_TW' => __( 'Chinese (Traditional)', 'generateblocks-pro' ),
|
||||
'ko_KR' => __( 'Korean', 'generateblocks-pro' ),
|
||||
'ar' => __( 'Arabic', 'generateblocks-pro' ),
|
||||
'he_IL' => __( 'Hebrew', 'generateblocks-pro' ),
|
||||
];
|
||||
|
||||
// Get installed languages if available.
|
||||
if ( function_exists( 'get_available_languages' ) ) {
|
||||
$installed = get_available_languages();
|
||||
foreach ( $installed as $locale ) {
|
||||
if ( ! isset( $common_locales[ $locale ] ) && 'en_US' !== $locale ) {
|
||||
$common_locales[ $locale ] = $locale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$rules = array_merge( $rules, $common_locales );
|
||||
|
||||
return apply_filters( 'generateblocks_language_rules', $rules );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get metadata for a specific rule.
|
||||
*
|
||||
* @param string $rule The rule key.
|
||||
* @return array
|
||||
*/
|
||||
public function get_rule_metadata( $rule ) {
|
||||
// RTL check doesn't need a value.
|
||||
if ( 'rtl' === $rule ) {
|
||||
return [
|
||||
'needs_value' => false,
|
||||
'value_type' => 'none',
|
||||
];
|
||||
}
|
||||
|
||||
// Language code needs a 2-letter code.
|
||||
if ( 'language' === $rule ) {
|
||||
return [
|
||||
'needs_value' => true,
|
||||
'value_type' => 'text',
|
||||
];
|
||||
}
|
||||
|
||||
// Custom and locale need full locale codes.
|
||||
if ( in_array( $rule, [ 'locale', 'custom' ], true ) ) {
|
||||
return [
|
||||
'needs_value' => true,
|
||||
'value_type' => 'text',
|
||||
];
|
||||
}
|
||||
|
||||
// Predefined locales don't need values.
|
||||
return [
|
||||
'needs_value' => false,
|
||||
'value_type' => 'none',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize the condition value.
|
||||
*
|
||||
* @param mixed $value The value to sanitize.
|
||||
* @param string $rule The rule being used.
|
||||
* @return mixed
|
||||
*/
|
||||
public function sanitize_value( $value, $rule ) {
|
||||
// For language codes, ensure lowercase and 2 characters.
|
||||
if ( 'language' === $rule ) {
|
||||
return strtolower( substr( sanitize_text_field( $value ), 0, 2 ) );
|
||||
}
|
||||
|
||||
// For locales, allow underscores and dashes.
|
||||
if ( in_array( $rule, [ 'locale', 'custom' ], true ) ) {
|
||||
return preg_replace( '/[^a-zA-Z0-9_-]/', '', sanitize_text_field( $value ) );
|
||||
}
|
||||
|
||||
return sanitize_text_field( $value );
|
||||
}
|
||||
}
|
||||
+537
@@ -0,0 +1,537 @@
|
||||
<?php
|
||||
/**
|
||||
* Location Condition
|
||||
*
|
||||
* @package GenerateBlocks
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Location condition evaluator.
|
||||
*/
|
||||
class GenerateBlocks_Pro_Condition_Location extends GenerateBlocks_Pro_Condition_Abstract {
|
||||
/**
|
||||
* Evaluate the condition.
|
||||
*
|
||||
* @param string $rule The condition rule.
|
||||
* @param string $operator The condition operator.
|
||||
* @param mixed $value The value to check against.
|
||||
* @param array $context Additional context data.
|
||||
* @return bool
|
||||
*/
|
||||
public function evaluate( $rule, $operator, $value, $context = [] ) {
|
||||
$current_location = $this->get_current_location();
|
||||
|
||||
// Handle parent/child relationships first (they have their own multi-value handling).
|
||||
if ( in_array( $rule, [ 'child_of', 'parent_of' ], true ) ) {
|
||||
return $this->evaluate_hierarchy( $rule, $operator, $value, $context );
|
||||
}
|
||||
|
||||
// Handle post taxonomy terms.
|
||||
if ( 0 === strpos( $rule, 'post_terms:' ) ) {
|
||||
return $this->evaluate_post_terms( $rule, $operator, $value, $context );
|
||||
}
|
||||
|
||||
// Handle multi-value operators for non-hierarchical rules.
|
||||
if ( $this->is_multi_value_operator( $operator ) ) {
|
||||
return $this->evaluate_multi_value_generic(
|
||||
$operator,
|
||||
$value,
|
||||
function( $check_value ) use ( $rule, $current_location ) {
|
||||
return $this->check_single_location_match( $rule, $check_value, $current_location );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
$is_match = false;
|
||||
|
||||
// Check if current location matches the rule.
|
||||
if ( in_array( $rule, $current_location['location'], true ) ) {
|
||||
if ( empty( $value ) ) {
|
||||
$is_match = true;
|
||||
} else {
|
||||
// Check specific object (post ID, term ID, etc.).
|
||||
$is_match = ( $current_location['object'] == $value ); // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
|
||||
}
|
||||
}
|
||||
|
||||
// Special cases - use true original query to check page context, not loop context.
|
||||
if ( ! $is_match ) {
|
||||
global $wp_the_query;
|
||||
switch ( $rule ) {
|
||||
case 'general:site':
|
||||
$is_match = true;
|
||||
break;
|
||||
case 'general:singular':
|
||||
$is_match = $wp_the_query->is_singular ?? is_singular();
|
||||
break;
|
||||
case 'general:archive':
|
||||
$is_match = $wp_the_query->is_archive ?? is_archive();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 'is_not' === $operator ? ! $is_match : $is_match;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a single location value matches the current location.
|
||||
*
|
||||
* @param string $rule The condition rule.
|
||||
* @param mixed $check_value The value to check.
|
||||
* @param array $current_location Current location data.
|
||||
* @return bool
|
||||
*/
|
||||
private function check_single_location_match( $rule, $check_value, $current_location ) {
|
||||
// Check if current location rule matches.
|
||||
if ( in_array( $rule, $current_location['location'], true ) ) {
|
||||
if ( empty( $check_value ) ) {
|
||||
return true;
|
||||
} else {
|
||||
// Check specific object (post ID, term ID, etc.).
|
||||
return ( $current_location['object'] == $check_value ); // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
|
||||
}
|
||||
}
|
||||
|
||||
// Special cases for general rules - use true original query.
|
||||
global $wp_the_query;
|
||||
switch ( $rule ) {
|
||||
case 'general:site':
|
||||
return true;
|
||||
case 'general:singular':
|
||||
return $wp_the_query->is_singular ?? is_singular();
|
||||
case 'general:archive':
|
||||
return $wp_the_query->is_archive ?? is_archive();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate post taxonomy terms condition.
|
||||
*
|
||||
* @param string $rule The condition rule.
|
||||
* @param string $operator The condition operator.
|
||||
* @param mixed $value The value to check against.
|
||||
* @param array $context Additional context data.
|
||||
* @return bool
|
||||
*/
|
||||
private function evaluate_post_terms( $rule, $operator, $value, $context = [] ) {
|
||||
// Use context if provided, otherwise get current post ID.
|
||||
$post_id = ! empty( $context['post_id'] ) ? $context['post_id'] : get_the_ID();
|
||||
|
||||
if ( ! $post_id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$post = get_post( $post_id );
|
||||
if ( ! $post ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Extract taxonomy from rule.
|
||||
$taxonomy = str_replace( 'post_terms:', '', $rule );
|
||||
if ( empty( $taxonomy ) || ! taxonomy_exists( $taxonomy ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get post terms.
|
||||
$post_terms = get_the_terms( $post->ID, $taxonomy );
|
||||
if ( is_wp_error( $post_terms ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert to array of term IDs.
|
||||
$post_term_ids = [];
|
||||
if ( $post_terms && is_array( $post_terms ) ) {
|
||||
$post_term_ids = wp_list_pluck( $post_terms, 'term_id' );
|
||||
$post_term_ids = array_map( 'strval', $post_term_ids ); // Convert to strings for comparison.
|
||||
}
|
||||
|
||||
// Handle multi-value operators.
|
||||
if ( $this->is_multi_value_operator( $operator ) ) {
|
||||
return $this->evaluate_multi_value_array( $operator, $post_term_ids, $value );
|
||||
}
|
||||
|
||||
// For single value operators.
|
||||
if ( empty( $value ) ) {
|
||||
// No specific term - just check if post has any terms.
|
||||
return 'is_not' === $operator ? empty( $post_term_ids ) : ! empty( $post_term_ids );
|
||||
}
|
||||
|
||||
$has_term = in_array( strval( $value ), $post_term_ids, true );
|
||||
return 'is_not' === $operator ? ! $has_term : $has_term;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate hierarchical relationships.
|
||||
*
|
||||
* @param string $rule The condition rule.
|
||||
* @param string $operator The condition operator.
|
||||
* @param mixed $value The value to check against.
|
||||
* @param array $context Additional context data.
|
||||
* @return bool
|
||||
*/
|
||||
private function evaluate_hierarchy( $rule, $operator, $value, $context = [] ) {
|
||||
// Use context if provided, otherwise get current post ID.
|
||||
$post_id = ! empty( $context['post_id'] ) ? $context['post_id'] : get_the_ID();
|
||||
|
||||
if ( ! $post_id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$post = get_post( $post_id );
|
||||
if ( ! $post ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if post type is hierarchical.
|
||||
$post_type_object = get_post_type_object( $post->post_type );
|
||||
if ( ! $post_type_object || ! $post_type_object->hierarchical ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle empty value - check for any parent/child relationship.
|
||||
if ( empty( $value ) ) {
|
||||
return $this->check_any_hierarchy( $rule, $operator, $post );
|
||||
}
|
||||
|
||||
// Handle multi-value for hierarchy.
|
||||
if ( $this->is_multi_value_operator( $operator ) ) {
|
||||
return $this->evaluate_multi_value_generic(
|
||||
$operator,
|
||||
$value,
|
||||
function( $check_value ) use ( $rule, $post ) {
|
||||
return $this->check_single_hierarchy( $rule, $check_value, $post );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
$is_match = $this->check_single_hierarchy( $rule, $value, $post );
|
||||
return 'is_not' === $operator ? ! $is_match : $is_match;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check single hierarchy relationship.
|
||||
*
|
||||
* @param string $rule The hierarchy rule.
|
||||
* @param mixed $value The value to check.
|
||||
* @param WP_Post $post The post object to check.
|
||||
* @return bool
|
||||
*/
|
||||
private function check_single_hierarchy( $rule, $value, $post ) {
|
||||
|
||||
if ( 'child_of' === $rule ) {
|
||||
// Check if current post is a child of the specified post.
|
||||
$ancestors = get_post_ancestors( $post->ID );
|
||||
return in_array( intval( $value ), $ancestors, true );
|
||||
} elseif ( 'parent_of' === $rule ) {
|
||||
// Check if current post is a parent of the specified post.
|
||||
$target_post = get_post( intval( $value ) );
|
||||
if ( $target_post ) {
|
||||
$target_ancestors = get_post_ancestors( $target_post->ID );
|
||||
return in_array( $post->ID, $target_ancestors, true );
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if post has any hierarchical relationship.
|
||||
*
|
||||
* @param string $rule The hierarchy rule.
|
||||
* @param string $operator The condition operator.
|
||||
* @param WP_Post $post The post object to check.
|
||||
* @return bool
|
||||
*/
|
||||
private function check_any_hierarchy( $rule, $operator, $post ) {
|
||||
|
||||
if ( 'child_of' === $rule ) {
|
||||
// Check if current post has any parent.
|
||||
$has_parent = 0 < $post->post_parent;
|
||||
return 'is_not' === $operator ? ! $has_parent : $has_parent;
|
||||
} elseif ( 'parent_of' === $rule ) {
|
||||
// Check if current post has any children.
|
||||
$children = get_children(
|
||||
array(
|
||||
'post_parent' => $post->ID,
|
||||
'post_type' => $post->post_type,
|
||||
'numberposts' => 1,
|
||||
'post_status' => array( 'publish', 'private', 'draft' ),
|
||||
)
|
||||
);
|
||||
$has_children = ! empty( $children );
|
||||
return 'is_not' === $operator ? ! $has_children : $has_children;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available rules for this condition type.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_rules() {
|
||||
$rules = [
|
||||
'general:site' => __( 'Entire Site', 'generateblocks-pro' ),
|
||||
'general:front_page' => __( 'Front Page', 'generateblocks-pro' ),
|
||||
'general:blog' => __( 'Blog', 'generateblocks-pro' ),
|
||||
'general:singular' => __( 'All Singular', 'generateblocks-pro' ),
|
||||
'general:archive' => __( 'All Archives', 'generateblocks-pro' ),
|
||||
'general:author' => __( 'Author Archives', 'generateblocks-pro' ),
|
||||
'general:date' => __( 'Date Archives', 'generateblocks-pro' ),
|
||||
'general:search' => __( 'Search Results', 'generateblocks-pro' ),
|
||||
'general:no_results' => __( 'No Results', 'generateblocks-pro' ),
|
||||
'general:404' => __( '404 Template', 'generateblocks-pro' ),
|
||||
];
|
||||
|
||||
// Add hierarchical relationships.
|
||||
$rules['child_of'] = __( 'Child of', 'generateblocks-pro' );
|
||||
$rules['parent_of'] = __( 'Parent of', 'generateblocks-pro' );
|
||||
|
||||
// Add post types.
|
||||
$post_types = get_post_types( [ 'public' => true ], 'objects' );
|
||||
foreach ( $post_types as $post_type_slug => $post_type ) {
|
||||
$rules[ 'post:' . $post_type_slug ] = $post_type->labels->singular_name;
|
||||
if ( $post_type->has_archive ) {
|
||||
$rules[ 'archive:' . $post_type_slug ] = sprintf(
|
||||
/* translators: %s: post type singular name */
|
||||
__( '%s Archive', 'generateblocks-pro' ),
|
||||
$post_type->labels->singular_name
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Add taxonomies for archive pages.
|
||||
$taxonomies = get_taxonomies( [ 'public' => true ], 'objects' );
|
||||
foreach ( $taxonomies as $taxonomy_slug => $taxonomy ) {
|
||||
$rules[ 'taxonomy:' . $taxonomy_slug ] = sprintf(
|
||||
/* translators: %s: taxonomy singular name */
|
||||
__( '%s Archive', 'generateblocks-pro' ),
|
||||
$taxonomy->labels->singular_name
|
||||
);
|
||||
}
|
||||
|
||||
// Add post taxonomy terms - for checking if current post has specific terms.
|
||||
foreach ( $taxonomies as $taxonomy_slug => $taxonomy ) {
|
||||
// Use name if available, fallback to singular_name for tests.
|
||||
$taxonomy_name = isset( $taxonomy->labels->name ) ? $taxonomy->labels->name : $taxonomy->labels->singular_name;
|
||||
|
||||
$rules[ 'post_terms:' . $taxonomy_slug ] = sprintf(
|
||||
/* translators: %s: taxonomy name */
|
||||
__( 'Post %s', 'generateblocks-pro' ),
|
||||
$taxonomy_name
|
||||
);
|
||||
}
|
||||
|
||||
return apply_filters( 'generateblocks_location_rules', $rules );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get metadata for a specific rule.
|
||||
*
|
||||
* @param string $rule The rule key.
|
||||
* @return array
|
||||
*/
|
||||
public function get_rule_metadata( $rule ) {
|
||||
$general_location_rules = array(
|
||||
'general:site',
|
||||
'general:front_page',
|
||||
'general:blog',
|
||||
'general:singular',
|
||||
'general:archive',
|
||||
'general:author',
|
||||
'general:date',
|
||||
'general:search',
|
||||
'general:no_results',
|
||||
'general:404',
|
||||
);
|
||||
|
||||
if ( in_array( $rule, $general_location_rules, true ) ) {
|
||||
return array(
|
||||
'needs_value' => false,
|
||||
'value_type' => 'none',
|
||||
'supports_multi' => false,
|
||||
);
|
||||
}
|
||||
|
||||
// Parent/child relationships need object selection but allow empty values.
|
||||
if ( in_array( $rule, array( 'child_of', 'parent_of' ), true ) ) {
|
||||
return array(
|
||||
'needs_value' => false,
|
||||
'value_type' => 'hierarchical_object_selector',
|
||||
'supports_multi' => true,
|
||||
);
|
||||
}
|
||||
|
||||
// Archive rules typically don't need values.
|
||||
if ( 0 === strpos( $rule, 'archive:' ) ) {
|
||||
return array(
|
||||
'needs_value' => false,
|
||||
'value_type' => 'none',
|
||||
'supports_multi' => false,
|
||||
);
|
||||
}
|
||||
|
||||
// Post taxonomy terms need term selection.
|
||||
if ( 0 === strpos( $rule, 'post_terms:' ) ) {
|
||||
return array(
|
||||
'needs_value' => false,
|
||||
'value_type' => 'object_selector',
|
||||
'supports_multi' => true,
|
||||
);
|
||||
}
|
||||
|
||||
// Post and taxonomy rules can optionally have specific object selection.
|
||||
if ( 0 === strpos( $rule, 'post:' ) || 0 === strpos( $rule, 'taxonomy:' ) ) {
|
||||
return array(
|
||||
'needs_value' => false,
|
||||
'value_type' => 'object_selector',
|
||||
'supports_multi' => true,
|
||||
);
|
||||
}
|
||||
|
||||
return $this->get_default_rule_metadata();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current location data.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function get_current_location() {
|
||||
global $wp_the_query;
|
||||
|
||||
$location = [];
|
||||
$object = null;
|
||||
|
||||
// Always use the true original query to determine location, not the current loop item.
|
||||
// This ensures Location conditions check "where you are" not "what you're looking at".
|
||||
// Using $wp_the_query is bulletproof against query_posts() and other query manipulations.
|
||||
// Falls back to global functions if $wp_the_query is not available.
|
||||
if ( $wp_the_query->is_front_page ?? is_front_page() ) {
|
||||
$location[] = 'general:front_page';
|
||||
|
||||
// When "Your homepage displays" is set to "Your latest posts",
|
||||
// both is_front_page() and is_home() are true.
|
||||
if ( $wp_the_query->is_home ?? is_home() ) {
|
||||
$location[] = 'general:blog';
|
||||
}
|
||||
|
||||
if ( $wp_the_query->is_page ?? is_page() ) {
|
||||
$location[] = 'post:page';
|
||||
$location[] = 'general:singular';
|
||||
|
||||
// Get the front page ID for specific page targeting.
|
||||
$front_page_id = get_option( 'page_on_front' );
|
||||
if ( $front_page_id ) {
|
||||
$object = $front_page_id;
|
||||
}
|
||||
}
|
||||
} elseif ( $wp_the_query->is_home ?? is_home() ) {
|
||||
$location[] = 'general:blog';
|
||||
} elseif ( $wp_the_query->is_singular ?? is_singular() ) {
|
||||
$location[] = 'general:singular';
|
||||
$queried_object = isset( $wp_the_query ) ? $wp_the_query->get_queried_object() : get_queried_object();
|
||||
if ( $queried_object && isset( $queried_object->post_type ) ) {
|
||||
$location[] = 'post:' . $queried_object->post_type;
|
||||
$object = $queried_object->ID;
|
||||
}
|
||||
} elseif ( $wp_the_query->is_archive ?? is_archive() ) {
|
||||
$location[] = 'general:archive';
|
||||
if ( ( $wp_the_query->is_category ?? is_category() ) || ( $wp_the_query->is_tag ?? is_tag() ) || ( $wp_the_query->is_tax ?? is_tax() ) ) {
|
||||
$queried_object = isset( $wp_the_query ) ? $wp_the_query->get_queried_object() : get_queried_object();
|
||||
if ( $queried_object && isset( $queried_object->taxonomy ) ) {
|
||||
$location[] = 'taxonomy:' . $queried_object->taxonomy;
|
||||
$object = $queried_object->term_id;
|
||||
}
|
||||
} elseif ( $wp_the_query->is_post_type_archive ?? is_post_type_archive() ) {
|
||||
$post_type = isset( $wp_the_query ) ? $wp_the_query->get( 'post_type' ) : get_query_var( 'post_type' );
|
||||
if ( $post_type ) {
|
||||
$location[] = 'archive:' . $post_type;
|
||||
}
|
||||
} elseif ( $wp_the_query->is_author ?? is_author() ) {
|
||||
$location[] = 'general:author';
|
||||
} elseif ( $wp_the_query->is_date ?? is_date() ) {
|
||||
$location[] = 'general:date';
|
||||
}
|
||||
} elseif ( $wp_the_query->is_search ?? is_search() ) {
|
||||
$location[] = 'general:search';
|
||||
|
||||
// Check if search has no results.
|
||||
if ( ( $wp_the_query->found_posts ?? 0 ) === 0 ) {
|
||||
$location[] = 'general:no_results';
|
||||
}
|
||||
} elseif ( $wp_the_query->is_404 ?? is_404() ) {
|
||||
$location[] = 'general:404';
|
||||
}
|
||||
|
||||
// Always include site.
|
||||
$location[] = 'general:site';
|
||||
|
||||
return [
|
||||
'location' => $location,
|
||||
'object' => $object,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get operators available for a specific location rule.
|
||||
*
|
||||
* @param string $rule The rule key.
|
||||
* @return array Array of operator keys.
|
||||
*/
|
||||
public function get_operators_for_rule( $rule ) {
|
||||
// General location rules - only basic operators (you're either there or not).
|
||||
$general_rules = array(
|
||||
'general:site',
|
||||
'general:front_page',
|
||||
'general:blog',
|
||||
'general:singular',
|
||||
'general:archive',
|
||||
'general:author',
|
||||
'general:date',
|
||||
'general:search',
|
||||
'general:no_results',
|
||||
'general:404',
|
||||
);
|
||||
|
||||
if ( in_array( $rule, $general_rules, true ) ) {
|
||||
return array( 'is', 'is_not' );
|
||||
}
|
||||
|
||||
// Archive rules - only basic operators.
|
||||
if ( 0 === strpos( $rule, 'archive:' ) ) {
|
||||
return array( 'is', 'is_not' );
|
||||
}
|
||||
|
||||
// Hierarchical relationships - simplified operators (no includes_all/excludes_all).
|
||||
if ( in_array( $rule, array( 'child_of', 'parent_of' ), true ) ) {
|
||||
return array( 'is', 'is_not', 'includes_any', 'excludes_any' );
|
||||
}
|
||||
|
||||
// Post taxonomy terms - full multi-value support.
|
||||
if ( 0 === strpos( $rule, 'post_terms:' ) ) {
|
||||
return array( 'is', 'is_not', 'includes_any', 'includes_all', 'excludes_any', 'excludes_all' );
|
||||
}
|
||||
|
||||
// For all other rules, check if multi-select is actually supported.
|
||||
if ( $this->rule_supports_multi_select( $rule ) ) {
|
||||
// Multi-select interface available.
|
||||
if ( 0 === strpos( $rule, 'post:' ) ) {
|
||||
// Posts: can select multiple but can't be on all simultaneously.
|
||||
return array( 'is', 'is_not', 'includes_any', 'excludes_any' );
|
||||
}
|
||||
// Taxonomies: full support.
|
||||
return array( 'is', 'is_not', 'includes_any', 'includes_all', 'excludes_any', 'excludes_all' );
|
||||
} else {
|
||||
// Single input only: no any/all operators.
|
||||
return array( 'is', 'is_not' );
|
||||
}
|
||||
}
|
||||
}
|
||||
+195
@@ -0,0 +1,195 @@
|
||||
<?php
|
||||
/**
|
||||
* Options Condition
|
||||
*
|
||||
* @package GenerateBlocks
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options condition evaluator.
|
||||
*/
|
||||
class GenerateBlocks_Pro_Condition_Options extends GenerateBlocks_Pro_Condition_Abstract {
|
||||
/**
|
||||
* Evaluate the condition.
|
||||
*
|
||||
* @param string $rule The condition rule.
|
||||
* @param string $operator The condition operator.
|
||||
* @param mixed $value The value to check against.
|
||||
* @param array $context Additional context data.
|
||||
* @return bool
|
||||
*/
|
||||
public function evaluate( $rule, $operator, $value, $context = [] ) {
|
||||
// Parse the option name and comparison value using standardized method.
|
||||
$parsed = $this->parse_meta_field( $rule, $value );
|
||||
$option_name = $parsed['field_name'];
|
||||
$comparison_value = $parsed['comparison_value'];
|
||||
|
||||
if ( empty( $option_name ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle existence operators using standardized method.
|
||||
if ( in_array( $operator, [ 'exists', 'not_exists' ], true ) ) {
|
||||
return $this->evaluate_meta_existence( 'option', 0, $option_name, $operator );
|
||||
}
|
||||
|
||||
// Handle has_value/no_value operators.
|
||||
if ( 'has_value' === $operator ) {
|
||||
return $this->evaluate_meta_has_value( 'option', 0, $option_name );
|
||||
}
|
||||
if ( 'no_value' === $operator ) {
|
||||
return ! $this->evaluate_meta_has_value( 'option', 0, $option_name );
|
||||
}
|
||||
|
||||
// Handle all other operators using standardized method.
|
||||
return $this->evaluate_meta_value( 'option', 0, $option_name, $operator, $comparison_value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available rules for this condition type.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_rules() {
|
||||
$rules = [
|
||||
'custom' => __( 'Custom Option', 'generateblocks-pro' ),
|
||||
];
|
||||
|
||||
// Add common WordPress options.
|
||||
$common_options = [
|
||||
'blogname' => __( 'Site Title', 'generateblocks-pro' ),
|
||||
'blogdescription' => __( 'Site Tagline', 'generateblocks-pro' ),
|
||||
'timezone_string' => __( 'Timezone', 'generateblocks-pro' ),
|
||||
'date_format' => __( 'Date Format', 'generateblocks-pro' ),
|
||||
'time_format' => __( 'Time Format', 'generateblocks-pro' ),
|
||||
];
|
||||
|
||||
$rules = array_merge( $rules, $common_options );
|
||||
|
||||
// Allow themes/plugins to add their options.
|
||||
return apply_filters( 'generateblocks_options_rules', $rules );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get metadata for a specific rule.
|
||||
*
|
||||
* @param string $rule The rule key.
|
||||
* @return array
|
||||
*/
|
||||
public function get_rule_metadata( $rule ) {
|
||||
if ( 'custom' === $rule ) {
|
||||
return [
|
||||
'needs_value' => true,
|
||||
'value_type' => 'custom_field',
|
||||
'supports_multi' => true,
|
||||
];
|
||||
}
|
||||
|
||||
// Boolean options need special handling.
|
||||
$boolean_options = [
|
||||
'users_can_register',
|
||||
'comment_registration',
|
||||
'close_comments_for_old_posts',
|
||||
'comment_moderation',
|
||||
'moderation_notify',
|
||||
'comments_notify',
|
||||
];
|
||||
|
||||
if ( in_array( $rule, $boolean_options, true ) ) {
|
||||
return [
|
||||
'needs_value' => false,
|
||||
'value_type' => 'none',
|
||||
'supports_multi' => false,
|
||||
];
|
||||
}
|
||||
|
||||
// Numeric options.
|
||||
$numeric_options = [
|
||||
'posts_per_page',
|
||||
'comments_per_page',
|
||||
'start_of_week',
|
||||
];
|
||||
|
||||
if ( in_array( $rule, $numeric_options, true ) ) {
|
||||
return [
|
||||
'needs_value' => true,
|
||||
'value_type' => 'number',
|
||||
'supports_multi' => true,
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'needs_value' => true,
|
||||
'value_type' => 'text',
|
||||
'supports_multi' => true,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize the condition value.
|
||||
*
|
||||
* @param mixed $value The value to sanitize.
|
||||
* @param string $rule The rule being used.
|
||||
* @return mixed
|
||||
*/
|
||||
public function sanitize_value( $value, $rule ) {
|
||||
if ( 'custom' === $rule ) {
|
||||
return $this->sanitize_custom_value( $value );
|
||||
}
|
||||
|
||||
// Handle array values for multi-select.
|
||||
if ( is_array( $value ) ) {
|
||||
return array_map( 'sanitize_text_field', $value );
|
||||
}
|
||||
|
||||
return sanitize_text_field( $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get operators available for a specific option rule.
|
||||
*
|
||||
* @param string $rule The rule key.
|
||||
* @return array Array of operator keys.
|
||||
*/
|
||||
public function get_operators_for_rule( $rule ) {
|
||||
// Boolean options only need existence checks.
|
||||
$boolean_options = [
|
||||
'users_can_register',
|
||||
'comment_registration',
|
||||
'close_comments_for_old_posts',
|
||||
'comment_moderation',
|
||||
'moderation_notify',
|
||||
'comments_notify',
|
||||
];
|
||||
|
||||
if ( in_array( $rule, $boolean_options, true ) ) {
|
||||
return [ 'exists', 'not_exists', 'has_value', 'no_value' ];
|
||||
}
|
||||
|
||||
// Numeric options support all operators.
|
||||
$numeric_options = [
|
||||
'posts_per_page',
|
||||
'comments_per_page',
|
||||
'start_of_week',
|
||||
];
|
||||
|
||||
if ( in_array( $rule, $numeric_options, true ) ) {
|
||||
if ( $this->rule_supports_multi_select( $rule ) ) {
|
||||
return [ 'exists', 'not_exists', 'has_value', 'no_value', 'equals', 'greater_than', 'less_than', 'includes_any', 'includes_all', 'excludes_any', 'excludes_all' ];
|
||||
} else {
|
||||
return [ 'exists', 'not_exists', 'has_value', 'no_value', 'equals', 'greater_than', 'less_than' ];
|
||||
}
|
||||
}
|
||||
|
||||
// Text options support text operators.
|
||||
if ( $this->rule_supports_multi_select( $rule ) ) {
|
||||
return [ 'exists', 'not_exists', 'has_value', 'no_value', 'equals', 'contains', 'not_contains', 'includes_any', 'includes_all', 'excludes_any', 'excludes_all' ];
|
||||
} else {
|
||||
return [ 'exists', 'not_exists', 'has_value', 'no_value', 'equals', 'contains', 'not_contains' ];
|
||||
}
|
||||
}
|
||||
}
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
/**
|
||||
* Post Meta Condition
|
||||
*
|
||||
* @package GenerateBlocks
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Post meta condition evaluator.
|
||||
*/
|
||||
class GenerateBlocks_Pro_Condition_Post_Meta extends GenerateBlocks_Pro_Condition_Abstract {
|
||||
/**
|
||||
* Evaluate the condition.
|
||||
*
|
||||
* @param string $rule The condition rule.
|
||||
* @param string $operator The condition operator.
|
||||
* @param mixed $value The value to check against.
|
||||
* @param array $context Additional context data.
|
||||
* @return bool
|
||||
*/
|
||||
public function evaluate( $rule, $operator, $value, $context = [] ) {
|
||||
// Use context if provided, otherwise get current post ID.
|
||||
$post_id = ! empty( $context['post_id'] ) ? $context['post_id'] : get_the_ID();
|
||||
|
||||
if ( ! $post_id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$post = get_post( $post_id );
|
||||
if ( ! $post ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse the meta key and comparison value using standardized method.
|
||||
$parsed = $this->parse_meta_field( $rule, $value );
|
||||
$meta_key = $parsed['field_name'];
|
||||
$comparison_value = $parsed['comparison_value'];
|
||||
|
||||
if ( empty( $meta_key ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle existence operators using standardized method.
|
||||
if ( in_array( $operator, [ 'exists', 'not_exists' ], true ) ) {
|
||||
return $this->evaluate_meta_existence( 'post', $post->ID, $meta_key, $operator );
|
||||
}
|
||||
|
||||
// Handle has_value/no_value operators.
|
||||
if ( 'has_value' === $operator ) {
|
||||
return $this->evaluate_meta_has_value( 'post', $post->ID, $meta_key );
|
||||
}
|
||||
if ( 'no_value' === $operator ) {
|
||||
return ! $this->evaluate_meta_has_value( 'post', $post->ID, $meta_key );
|
||||
}
|
||||
|
||||
// Handle all other operators using standardized method.
|
||||
return $this->evaluate_meta_value( 'post', $post->ID, $meta_key, $operator, $comparison_value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available rules for this condition type.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_rules() {
|
||||
$rules = [
|
||||
'custom' => __( 'Custom Meta Key', 'generateblocks-pro' ),
|
||||
];
|
||||
|
||||
// Add common meta keys.
|
||||
$common_keys = [
|
||||
'_thumbnail_id' => __( 'Has Featured Image', 'generateblocks-pro' ),
|
||||
'_wp_page_template' => __( 'Page Template', 'generateblocks-pro' ),
|
||||
];
|
||||
|
||||
$rules = array_merge( $rules, $common_keys );
|
||||
|
||||
// Allow themes/plugins to add their meta keys.
|
||||
return apply_filters( 'generateblocks_post_meta_rules', $rules );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get metadata for a specific rule.
|
||||
*
|
||||
* @param string $rule The rule key.
|
||||
* @return array
|
||||
*/
|
||||
public function get_rule_metadata( $rule ) {
|
||||
if ( 'custom' === $rule ) {
|
||||
return [
|
||||
'needs_value' => true,
|
||||
'value_type' => 'custom_field',
|
||||
'supports_multi' => true,
|
||||
];
|
||||
}
|
||||
|
||||
// Special handling for specific meta keys.
|
||||
if ( '_thumbnail_id' === $rule ) {
|
||||
return [
|
||||
'needs_value' => false,
|
||||
'value_type' => 'none',
|
||||
'supports_multi' => false,
|
||||
];
|
||||
}
|
||||
|
||||
// Page template is text-based.
|
||||
if ( '_wp_page_template' === $rule ) {
|
||||
return [
|
||||
'needs_value' => true,
|
||||
'value_type' => 'text',
|
||||
'supports_multi' => true,
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'needs_value' => true,
|
||||
'value_type' => 'text',
|
||||
'supports_multi' => true,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get operators available for a specific post meta rule.
|
||||
*
|
||||
* @param string $rule The rule key.
|
||||
* @return array Array of operator keys.
|
||||
*/
|
||||
public function get_operators_for_rule( $rule ) {
|
||||
// Special case for thumbnail - only existence checks.
|
||||
if ( '_thumbnail_id' === $rule ) {
|
||||
return [ 'exists', 'not_exists', 'has_value', 'no_value' ];
|
||||
}
|
||||
|
||||
// Page template - only text operations, no greater_than/less_than.
|
||||
if ( '_wp_page_template' === $rule ) {
|
||||
if ( $this->rule_supports_multi_select( $rule ) ) {
|
||||
return [ 'exists', 'not_exists', 'has_value', 'no_value', 'equals', 'contains', 'not_contains', 'includes_any', 'includes_all', 'excludes_any', 'excludes_all' ];
|
||||
} else {
|
||||
return [ 'exists', 'not_exists', 'has_value', 'no_value', 'equals', 'contains', 'not_contains' ];
|
||||
}
|
||||
}
|
||||
|
||||
// Custom meta key supports all operators including numeric.
|
||||
if ( $this->rule_supports_multi_select( $rule ) ) {
|
||||
return [ 'exists', 'not_exists', 'has_value', 'no_value', 'equals', 'contains', 'not_contains', 'greater_than', 'less_than', 'includes_any', 'includes_all', 'excludes_any', 'excludes_all' ];
|
||||
} else {
|
||||
return [ 'exists', 'not_exists', 'has_value', 'no_value', 'equals', 'contains', 'not_contains', 'greater_than', 'less_than' ];
|
||||
}
|
||||
}
|
||||
}
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
<?php
|
||||
/**
|
||||
* Query Argument Condition
|
||||
*
|
||||
* @package GenerateBlocks
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Query argument condition evaluator.
|
||||
*/
|
||||
class GenerateBlocks_Pro_Condition_Query_Arg extends GenerateBlocks_Pro_Condition_Abstract {
|
||||
/**
|
||||
* Evaluate the condition.
|
||||
*
|
||||
* @param string $rule The condition rule.
|
||||
* @param string $operator The condition operator.
|
||||
* @param mixed $value The value to check against.
|
||||
* @param array $context Additional context data.
|
||||
* @return bool
|
||||
*/
|
||||
public function evaluate( $rule, $operator, $value, $context = [] ) {
|
||||
// Parse the parameter name and comparison value using standardized method.
|
||||
$parsed = $this->parse_meta_field( $rule, $value );
|
||||
$param_name = $parsed['field_name'];
|
||||
$comparison_value = $parsed['comparison_value'];
|
||||
|
||||
if ( empty( $param_name ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch ( $operator ) {
|
||||
case 'exists':
|
||||
return $this->query_param_exists( $param_name );
|
||||
|
||||
case 'not_exists':
|
||||
return ! $this->query_param_exists( $param_name );
|
||||
|
||||
case 'has_value':
|
||||
return $this->query_param_has_value( $param_name );
|
||||
|
||||
case 'no_value':
|
||||
return ! $this->query_param_has_value( $param_name );
|
||||
|
||||
case 'equals':
|
||||
$param_value = $this->get_query_param_raw( $param_name );
|
||||
// For arrays, check if comparison value is in the array.
|
||||
if ( is_array( $param_value ) ) {
|
||||
return in_array( $comparison_value, $param_value, true );
|
||||
}
|
||||
return null !== $param_value && $param_value === $comparison_value;
|
||||
|
||||
case 'contains':
|
||||
$param_value = $this->get_query_param_raw( $param_name );
|
||||
// String operations only work on strings, return false for arrays.
|
||||
if ( ! is_string( $param_value ) ) {
|
||||
return false;
|
||||
}
|
||||
return false !== strpos( $param_value, $comparison_value );
|
||||
|
||||
case 'not_contains':
|
||||
$param_value = $this->get_query_param_raw( $param_name );
|
||||
// String operations only work on strings, return true for arrays (they don't "contain" the string).
|
||||
if ( ! is_string( $param_value ) ) {
|
||||
return true;
|
||||
}
|
||||
return false === strpos( $param_value, $comparison_value );
|
||||
|
||||
case 'starts_with':
|
||||
$param_value = $this->get_query_param_raw( $param_name );
|
||||
// String operations only work on strings, return false for arrays.
|
||||
if ( ! is_string( $param_value ) ) {
|
||||
return false;
|
||||
}
|
||||
return 0 === strpos( $param_value, $comparison_value );
|
||||
|
||||
case 'ends_with':
|
||||
$param_value = $this->get_query_param_raw( $param_name );
|
||||
// String operations only work on strings, return false for arrays.
|
||||
if ( ! is_string( $param_value ) ) {
|
||||
return false;
|
||||
}
|
||||
return substr( $param_value, -strlen( $comparison_value ) ) === $comparison_value;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get raw query parameter value without sanitization to preserve arrays.
|
||||
*
|
||||
* @param string $param_name Parameter name.
|
||||
* @return mixed|null
|
||||
*/
|
||||
private function get_query_param_raw( $param_name ) {
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
if ( ! isset( $_GET[ $param_name ] ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
$value = wp_unslash( $_GET[ $param_name ] );
|
||||
|
||||
// Sanitize based on type.
|
||||
if ( is_array( $value ) ) {
|
||||
return array_map( 'sanitize_text_field', $value );
|
||||
}
|
||||
|
||||
return sanitize_text_field( $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available rules for this condition type.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_rules() {
|
||||
$rules = [
|
||||
'custom' => __( 'Custom Parameter', 'generateblocks-pro' ),
|
||||
];
|
||||
|
||||
// Allow filtering to add predefined parameters.
|
||||
return apply_filters( 'generateblocks_query_arg_rules', $rules );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get metadata for a specific rule.
|
||||
*
|
||||
* @param string $rule The rule key.
|
||||
* @return array
|
||||
*/
|
||||
public function get_rule_metadata( $rule ) {
|
||||
if ( 'custom' === $rule ) {
|
||||
return [
|
||||
'needs_value' => true,
|
||||
'value_type' => 'custom_field',
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'needs_value' => true,
|
||||
'value_type' => 'text',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get operators available for a specific query arg rule.
|
||||
*
|
||||
* @param string $rule The rule key.
|
||||
* @return array Array of operator keys.
|
||||
*/
|
||||
public function get_operators_for_rule( $rule ) {
|
||||
// All query args support the same text operators.
|
||||
return [ 'exists', 'not_exists', 'has_value', 'no_value', 'equals', 'contains', 'not_contains', 'starts_with', 'ends_with' ];
|
||||
}
|
||||
}
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
/**
|
||||
* Referrer Condition
|
||||
*
|
||||
* @package GenerateBlocks
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Referrer condition evaluator.
|
||||
*/
|
||||
class GenerateBlocks_Pro_Condition_Referrer extends GenerateBlocks_Pro_Condition_Abstract {
|
||||
/**
|
||||
* Evaluate the condition.
|
||||
*
|
||||
* @param string $rule The condition rule.
|
||||
* @param string $operator The condition operator.
|
||||
* @param mixed $value The value to check against.
|
||||
* @param array $context Additional context data.
|
||||
* @return bool
|
||||
*/
|
||||
public function evaluate( $rule, $operator, $value, $context = [] ) {
|
||||
$referrer = $this->get_server_var( 'HTTP_REFERER' );
|
||||
|
||||
// Handle direct traffic (no referrer).
|
||||
if ( 'direct' === $rule ) {
|
||||
$has_referrer = ! empty( $referrer );
|
||||
return 'is_not' === $operator ? $has_referrer : ! $has_referrer;
|
||||
}
|
||||
|
||||
// Handle custom referrer.
|
||||
if ( 'custom' === $rule ) {
|
||||
// Handle has_value/no_value operators first.
|
||||
if ( 'has_value' === $operator ) {
|
||||
return $this->referrer_has_value();
|
||||
}
|
||||
if ( 'no_value' === $operator ) {
|
||||
return ! $this->referrer_has_value();
|
||||
}
|
||||
|
||||
$parsed = $this->parse_custom_value( $value );
|
||||
$comparison_value = $parsed['comparison_value'] ? $parsed['comparison_value'] : $parsed['field_name'];
|
||||
|
||||
if ( empty( $comparison_value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$is_match = false;
|
||||
|
||||
switch ( $operator ) {
|
||||
case 'contains':
|
||||
$is_match = false !== strpos( $referrer, $comparison_value );
|
||||
break;
|
||||
|
||||
case 'not_contains':
|
||||
$is_match = false === strpos( $referrer, $comparison_value );
|
||||
break;
|
||||
|
||||
case 'equals':
|
||||
$is_match = $referrer === $comparison_value;
|
||||
break;
|
||||
|
||||
case 'starts_with':
|
||||
$is_match = 0 === strpos( $referrer, $comparison_value );
|
||||
break;
|
||||
|
||||
case 'ends_with':
|
||||
$is_match = substr( $referrer, -strlen( $comparison_value ) ) === $comparison_value;
|
||||
break;
|
||||
}
|
||||
|
||||
return $is_match;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available rules for this condition type.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_rules() {
|
||||
$rules = [
|
||||
'direct' => __( 'Direct Traffic (No Referrer)', 'generateblocks-pro' ),
|
||||
'custom' => __( 'Custom Referrer', 'generateblocks-pro' ),
|
||||
];
|
||||
|
||||
return apply_filters( 'generateblocks_referrer_rules', $rules );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get metadata for a specific rule.
|
||||
*
|
||||
* @param string $rule The rule key.
|
||||
* @return array
|
||||
*/
|
||||
public function get_rule_metadata( $rule ) {
|
||||
if ( 'custom' === $rule ) {
|
||||
return [
|
||||
'needs_value' => true,
|
||||
'value_type' => 'custom_field',
|
||||
];
|
||||
}
|
||||
|
||||
if ( 'direct' === $rule ) {
|
||||
return [
|
||||
'needs_value' => false,
|
||||
'value_type' => 'none',
|
||||
];
|
||||
}
|
||||
|
||||
return $this->get_default_rule_metadata();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get operators available for a specific referrer rule.
|
||||
*
|
||||
* @param string $rule The rule key.
|
||||
* @return array Array of operator keys.
|
||||
*/
|
||||
public function get_operators_for_rule( $rule ) {
|
||||
if ( 'direct' === $rule ) {
|
||||
// Direct traffic only supports is/is_not.
|
||||
return [ 'is', 'is_not' ];
|
||||
}
|
||||
|
||||
if ( 'custom' === $rule ) {
|
||||
// Custom referrer supports all text comparison operators including not_contains.
|
||||
return [ 'has_value', 'no_value', 'contains', 'not_contains', 'equals', 'starts_with', 'ends_with' ];
|
||||
}
|
||||
|
||||
return [ 'contains', 'not_contains', 'equals', 'starts_with' ];
|
||||
}
|
||||
}
|
||||
+166
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
/**
|
||||
* User Meta Condition
|
||||
*
|
||||
* @package GenerateBlocks
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* User meta condition evaluator.
|
||||
*/
|
||||
class GenerateBlocks_Pro_Condition_User_Meta extends GenerateBlocks_Pro_Condition_Abstract {
|
||||
/**
|
||||
* Evaluate the condition.
|
||||
*
|
||||
* @param string $rule The condition rule.
|
||||
* @param string $operator The condition operator.
|
||||
* @param mixed $value The value to check against.
|
||||
* @param array $context Additional context data.
|
||||
* @return bool
|
||||
*/
|
||||
public function evaluate( $rule, $operator, $value, $context = [] ) {
|
||||
// User must be logged in for user meta conditions.
|
||||
if ( ! is_user_logged_in() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$user_id = get_current_user_id();
|
||||
if ( ! $user_id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Parse the meta key and comparison value using standardized method.
|
||||
$parsed = $this->parse_meta_field( $rule, $value );
|
||||
$meta_key = $parsed['field_name'];
|
||||
$comparison_value = $parsed['comparison_value'];
|
||||
|
||||
if ( empty( $meta_key ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle existence operators using standardized method.
|
||||
if ( in_array( $operator, [ 'exists', 'not_exists' ], true ) ) {
|
||||
return $this->evaluate_meta_existence( 'user', $user_id, $meta_key, $operator );
|
||||
}
|
||||
|
||||
// Handle has_value/no_value operators.
|
||||
if ( 'has_value' === $operator ) {
|
||||
return $this->evaluate_meta_has_value( 'user', $user_id, $meta_key );
|
||||
}
|
||||
if ( 'no_value' === $operator ) {
|
||||
return ! $this->evaluate_meta_has_value( 'user', $user_id, $meta_key );
|
||||
}
|
||||
|
||||
// Handle all other operators using standardized method.
|
||||
return $this->evaluate_meta_value( 'user', $user_id, $meta_key, $operator, $comparison_value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available rules for this condition type.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_rules() {
|
||||
$rules = [
|
||||
'custom' => __( 'Custom Meta Key', 'generateblocks-pro' ),
|
||||
];
|
||||
|
||||
// Add common user meta keys.
|
||||
$common_keys = [
|
||||
'first_name' => __( 'First Name', 'generateblocks-pro' ),
|
||||
'last_name' => __( 'Last Name', 'generateblocks-pro' ),
|
||||
'nickname' => __( 'Nickname', 'generateblocks-pro' ),
|
||||
'description' => __( 'Biographical Info', 'generateblocks-pro' ),
|
||||
'show_admin_bar_front' => __( 'Show Admin Bar', 'generateblocks-pro' ),
|
||||
];
|
||||
|
||||
$rules = array_merge( $rules, $common_keys );
|
||||
|
||||
// Allow themes/plugins to add their meta keys.
|
||||
return apply_filters( 'generateblocks_user_meta_rules', $rules );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get metadata for a specific rule.
|
||||
*
|
||||
* @param string $rule The rule key.
|
||||
* @return array
|
||||
*/
|
||||
public function get_rule_metadata( $rule ) {
|
||||
if ( 'custom' === $rule ) {
|
||||
return [
|
||||
'needs_value' => true,
|
||||
'value_type' => 'custom_field',
|
||||
'supports_multi' => true,
|
||||
];
|
||||
}
|
||||
|
||||
// Show admin bar is a boolean stored as string.
|
||||
if ( 'show_admin_bar_front' === $rule ) {
|
||||
return [
|
||||
'needs_value' => false,
|
||||
'value_type' => 'none',
|
||||
'supports_multi' => false,
|
||||
];
|
||||
}
|
||||
|
||||
return [
|
||||
'needs_value' => true,
|
||||
'value_type' => 'text',
|
||||
'supports_multi' => true,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize the condition value.
|
||||
*
|
||||
* @param mixed $value The value to sanitize.
|
||||
* @param string $rule The rule being used.
|
||||
* @return mixed
|
||||
*/
|
||||
public function sanitize_value( $value, $rule ) {
|
||||
if ( 'custom' === $rule ) {
|
||||
return $this->sanitize_custom_value( $value );
|
||||
}
|
||||
|
||||
// Handle array values for multi-select.
|
||||
if ( is_array( $value ) ) {
|
||||
return array_map( 'sanitize_text_field', $value );
|
||||
}
|
||||
|
||||
return sanitize_text_field( $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get operators available for a specific user meta rule.
|
||||
*
|
||||
* @param string $rule The rule key.
|
||||
* @return array Array of operator keys.
|
||||
*/
|
||||
public function get_operators_for_rule( $rule ) {
|
||||
// Show admin bar only needs existence checks.
|
||||
if ( 'show_admin_bar_front' === $rule ) {
|
||||
return [ 'exists', 'not_exists', 'has_value', 'no_value' ];
|
||||
}
|
||||
|
||||
// Text fields - no greater_than/less_than as per feedback.
|
||||
if ( in_array( $rule, [ 'first_name', 'last_name', 'nickname', 'description' ], true ) ) {
|
||||
if ( $this->rule_supports_multi_select( $rule ) ) {
|
||||
return [ 'exists', 'not_exists', 'has_value', 'no_value', 'equals', 'contains', 'not_contains', 'includes_any', 'includes_all', 'excludes_any', 'excludes_all' ];
|
||||
} else {
|
||||
return [ 'exists', 'not_exists', 'has_value', 'no_value', 'equals', 'contains', 'not_contains' ];
|
||||
}
|
||||
}
|
||||
|
||||
// Custom meta key supports all operators.
|
||||
if ( $this->rule_supports_multi_select( $rule ) ) {
|
||||
return [ 'exists', 'not_exists', 'has_value', 'no_value', 'equals', 'contains', 'not_contains', 'greater_than', 'less_than', 'includes_any', 'includes_all', 'excludes_any', 'excludes_all' ];
|
||||
} else {
|
||||
return [ 'exists', 'not_exists', 'has_value', 'no_value', 'equals', 'contains', 'not_contains', 'greater_than', 'less_than' ];
|
||||
}
|
||||
}
|
||||
}
|
||||
+179
@@ -0,0 +1,179 @@
|
||||
<?php
|
||||
/**
|
||||
* User Role Condition
|
||||
*
|
||||
* @package GenerateBlocks
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* User role condition evaluator.
|
||||
*/
|
||||
class GenerateBlocks_Pro_Condition_User_Role extends GenerateBlocks_Pro_Condition_Abstract {
|
||||
/**
|
||||
* Evaluate the condition.
|
||||
*
|
||||
* @param string $rule The condition rule.
|
||||
* @param string $operator The condition operator.
|
||||
* @param mixed $value The value to check against.
|
||||
* @param array $context Additional context data.
|
||||
* @return bool
|
||||
*/
|
||||
public function evaluate( $rule, $operator, $value, $context = [] ) {
|
||||
// Handle multi-value operators for roles and capabilities only.
|
||||
if ( $this->is_multi_value_operator( $operator ) && $this->rule_supports_multi_select( $rule ) ) {
|
||||
return $this->evaluate_multi_value_generic(
|
||||
$operator,
|
||||
$value,
|
||||
function( $check_value ) {
|
||||
return $this->check_single_user_role( $check_value );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
$is_match = false;
|
||||
|
||||
switch ( $rule ) {
|
||||
case 'general:logged_in':
|
||||
$is_match = is_user_logged_in();
|
||||
break;
|
||||
|
||||
case 'general:logged_out':
|
||||
$is_match = ! is_user_logged_in();
|
||||
break;
|
||||
|
||||
default:
|
||||
// Check specific role or capability.
|
||||
$user = wp_get_current_user();
|
||||
if ( $user && $user->exists() ) {
|
||||
// Check if it's a capability (prefixed with 'cap:').
|
||||
if ( 0 === strpos( $rule, 'cap:' ) ) {
|
||||
// Remove prefix.
|
||||
$capability = substr( $rule, 4 );
|
||||
$is_match = user_can( $user, $capability );
|
||||
} else {
|
||||
// It's a role.
|
||||
$is_match = in_array( $rule, (array) $user->roles, true );
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return 'is_not' === $operator ? ! $is_match : $is_match;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current user matches a single role/capability.
|
||||
*
|
||||
* @param string $check_value The role or capability to check.
|
||||
* @return bool
|
||||
*/
|
||||
private function check_single_user_role( $check_value ) {
|
||||
$user = wp_get_current_user();
|
||||
if ( ! $user || ! $user->exists() ) {
|
||||
// For logged out users, only check against general rules.
|
||||
return 'general:logged_out' === $check_value;
|
||||
}
|
||||
|
||||
switch ( $check_value ) {
|
||||
case 'general:logged_in':
|
||||
return true; // User is logged in if we reach this point.
|
||||
|
||||
case 'general:logged_out':
|
||||
return false; // User is logged in.
|
||||
|
||||
default:
|
||||
// Check specific role or capability.
|
||||
if ( 0 === strpos( $check_value, 'cap:' ) ) {
|
||||
// Remove prefix.
|
||||
$capability = substr( $check_value, 4 );
|
||||
return user_can( $user, $capability );
|
||||
} else {
|
||||
// It's a role.
|
||||
$user_roles = (array) $user->roles;
|
||||
return in_array( $check_value, $user_roles, true );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available rules for this condition type.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_rules() {
|
||||
$rules = [
|
||||
'general:logged_in' => __( 'Logged In', 'generateblocks-pro' ),
|
||||
'general:logged_out' => __( 'Logged Out', 'generateblocks-pro' ),
|
||||
];
|
||||
|
||||
// Ensure get_editable_roles() is available.
|
||||
if ( ! function_exists( 'get_editable_roles' ) ) {
|
||||
require_once ABSPATH . 'wp-admin/includes/user.php';
|
||||
}
|
||||
|
||||
// Add WordPress roles.
|
||||
if ( function_exists( 'get_editable_roles' ) ) {
|
||||
$roles = get_editable_roles();
|
||||
foreach ( $roles as $slug => $data ) {
|
||||
$rules[ $slug ] = translate_user_role( $data['name'] );
|
||||
}
|
||||
}
|
||||
|
||||
// Add capabilities - keep the most commonly used ones.
|
||||
$capabilities = [
|
||||
'edit_posts' => __( 'Can Edit Posts', 'generateblocks-pro' ),
|
||||
'edit_pages' => __( 'Can Edit Pages', 'generateblocks-pro' ),
|
||||
'edit_published_posts' => __( 'Can Edit Published Posts', 'generateblocks-pro' ),
|
||||
'edit_others_posts' => __( 'Can Edit Others Posts', 'generateblocks-pro' ),
|
||||
'publish_posts' => __( 'Can Publish Posts', 'generateblocks-pro' ),
|
||||
'manage_options' => __( 'Can Manage Options', 'generateblocks-pro' ),
|
||||
'moderate_comments' => __( 'Can Moderate Comments', 'generateblocks-pro' ),
|
||||
];
|
||||
|
||||
// Capabilities are prefixed with 'cap:' to distinguish from roles.
|
||||
foreach ( $capabilities as $cap => $label ) {
|
||||
$rules[ 'cap:' . $cap ] = $label;
|
||||
}
|
||||
|
||||
return apply_filters( 'generateblocks_user_role_rules', $rules );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get metadata for a specific rule.
|
||||
*
|
||||
* @param string $rule The rule key.
|
||||
* @return array
|
||||
*/
|
||||
public function get_rule_metadata( $rule ) {
|
||||
return [
|
||||
'needs_value' => false,
|
||||
'value_type' => 'none',
|
||||
'supports_multi' => false,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get operators available for a specific user role rule.
|
||||
*
|
||||
* @param string $rule The rule key.
|
||||
* @return array Array of operator keys.
|
||||
*/
|
||||
public function get_operators_for_rule( $rule ) {
|
||||
// General status rules - simple is/is_not only.
|
||||
if ( in_array( $rule, [ 'general:logged_in', 'general:logged_out' ], true ) ) {
|
||||
return [ 'is', 'is_not' ];
|
||||
}
|
||||
|
||||
// For individual roles and capabilities, support multi-select if UI supports it.
|
||||
if ( $this->rule_supports_multi_select( $rule ) ) {
|
||||
return [ 'is', 'is_not', 'includes_any', 'excludes_any' ];
|
||||
}
|
||||
|
||||
// Fallback to simple operators.
|
||||
return [ 'is', 'is_not' ];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user