# content-control/2.0.0/classes/RuleEngine/Rules.php

Content Control – The Ultimate Content Restriction Plugin! Restrict Content, Create Conditional Blocks &amp; More, version 2.0.0. 650 lines.

- Page: https://pluginprobe.com/plugins/content-control/2.0.0/code/classes/RuleEngine/Rules.php
- Raw: https://pluginprobe.com/plugins/content-control/2.0.0/raw/classes/RuleEngine/Rules.php
- Modified: 2023-09-18T01:47:10+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/content-control/2.0.0/code/classes/RuleEngine/Rules.php#L10-L20`.

```php
<?php
/**
 * Rule registery
 *
 * @package ContentControl
 */

namespace ContentControl\RuleEngine;

/**
 * Rules registry
 */
class Rules {

	/**
	 * Array of rules.
	 *
	 * @var array
	 */
	private $data = [];

	/**
	 * Current global rule instance.
	 *
	 * @var Rule
	 */
	public $current_rule = null;

	/**
	 * Get the current global rule instance.
	 *
	 * @param Rule|null|false $rule Rule instance to set.
	 * @return Rule|null
	 */
	public function current_rule( $rule = false ) {
		if ( false === $rule ) {
			return $this->current_rule;
		}

		$this->current_rule = $rule;
	}

	/**
	 * Set up rules list.
	 *
	 * @return void
	 */
	public function init() {
		// Register rules.
		$this->register_built_in_rules();

		// Register deprecated rules (using old filter).
		$this->register_deprecated_rules();
	}

	/**
	 * Register new rule type.
	 *
	 * @param array $rule New rule to register.
	 * @return void
	 */
	public function register_rule( $rule ) {
		if ( $this->is_rule_valid( $rule ) ) {
			$rule = wp_parse_args( $rule, $this->get_rule_defaults() );

			$index = $rule['name'];
			/**
			 * In the case multiple conditions are registered with the same
			 * identifier, we append an integer. This do/while quickly increases
			 * the integer by one until a valid new key is found.
			 */
			if ( array_key_exists( $index, $this->data ) ) {
				$i = 0;
				do {
					++$i;
					$index = $rule['name'] . '-' . $i;
				} while ( array_key_exists( $index, $this->data ) );
			}

			$indexs[]             = $index;
			$this->data[ $index ] = $rule;
		}
	}

	/**
	 * Check if rule is valid.
	 *
	 * @param array $rule Rule to test.
	 * @return boolean
	 */
	public function is_rule_valid( $rule ) {
		return ! empty( $rule ) && true;
	}

	/**
	 * Get array of all registered rules.
	 *
	 * @return array
	 */
	public function get_rules() {
		if ( ! did_action( 'content_control/rule_engine/register_rules' ) ) {
			$this->init();
		}

		return $this->data;
	}

	/**
	 * Get a rule definition by name.
	 *
	 * @param string $rule_name Rule definition or null.
	 * @return array|null
	 */
	public function get_rule( $rule_name ) {
		$rules = $this->get_rules();
		return isset( $rules[ $rule_name ] ) ? $rules[ $rule_name ] : null;
	}

	/**
	 * Get array of registered rules filtered for the block-editor.
	 *
	 * @return array
	 */
	public function get_block_editor_rules() {
		$rules = $this->get_rules();

		/**
		 * Filter the rules.
		 *
		 * @param array $rules Rules.
		 *
		 * @return array
		 */
		return apply_filters( 'content_control/rule_engine/get_block_editor_rules', $rules );
	}

	/**
	 * Get list of verbs.
	 *
	 * @return array List of verbs with translatable text.
	 */
	public function get_verbs() {
		return [
			'are'         => __( 'Are', 'content-control' ),
			'arenot'      => __( 'Are Not', 'content-control' ),
			'is'          => __( 'Is', 'content-control' ),
			'isnot'       => __( 'Is Not', 'content-control' ),
			'has'         => __( 'Has', 'content-control' ),
			'hasnot'      => __( 'Has Not', 'content-control' ),
			'can'         => __( 'Can', 'content-control' ),
			'cannot'      => __( 'Can Not', 'content-control' ),
			'doesnothave' => __( 'Does Not Have', 'content-control' ),
			'does'        => __( 'Does', 'content-control' ),
			'doesnot'     => __( 'Does Not', 'content-control' ),
			'was'         => __( 'Was', 'content-control' ),
			'wasnot'      => __( 'Was Not', 'content-control' ),
			'were'        => __( 'Were', 'content-control' ),
			'werenot'     => __( 'Were Not', 'content-control' ),
		];
	}

	/**
	 * Get a list of built in rules.
	 *
	 * @return void
	 */
	private function register_built_in_rules() {
		$rules = array_merge(
			$this->get_user_rules(),
			$this->get_general_content_rules(),
			$this->get_post_type_rules(),
			$this->get_taxonomy_rules()
		);

		/**
		 * Allow registering additional rules quickly.
		 *
		 * @param array $rules Rules.
		 *
		 * @return array
		 */
		$rules = apply_filters( 'content_control/rule_engine/rules', $rules );

		foreach ( $rules as $rule ) {
			$this->register_rule( $rule );
		}

		/**
		 * Allow manipulating registered rules.
		 *
		 * @param Rules $this Rules instance.
		 *
		 * @return void
		 */
		do_action( 'content_control/rule_engine/register_rules', $this );
	}

	/**
	 * Get a list of user rules.
	 *
	 * @return array
	 */
	public function get_user_rules() {
		$verbs = $this->get_verbs();
		return [
			'user_is_logged_in' => [
				'name'     => 'user_is_logged_in',
				'label'    => __( 'Logged In', 'content-control' ),
				'context'  => [ 'user' ],
				'category' => __( 'User', 'content-control' ),
				'format'   => '{category} {verb} {label}',
				'verbs'    => [ $verbs['is'], $verbs['isnot'] ],
				'callback' => '\is_user_logged_in',
			],
			'user_has_role'     => [
				'name'     => 'user_has_role',
				'label'    => __( 'Role(s)', 'content-control' ),
				'context'  => [ 'user' ],
				'category' => __( 'User', 'content-control' ),
				'format'   => '{category} {verb} {label}',
				'verbs'    => [ $verbs['has'], $verbs['doesnothave'] ],
				'fields'   => [
					'roles' => [
						'label'    => __( 'Role(s)', 'content-control' ),
						'type'     => 'tokenselect',
						'multiple' => true,
						'options'  => wp_roles()->get_names(),
					],
				],
				'callback' => '\ContentControl\Rules\user_has_role',
			],
		];
	}

	/**
	 * Get a list of general content rules.
	 *
	 * @return array
	 */
	public function get_general_content_rules() {
		$rules = [];
		$verbs = $this->get_verbs();

		$rules['entire_site'] = [
			'name'     => 'entire_site',
			'label'    => __( 'Entire Site (Any Page, Post, or Archive)', 'content-control' ),
			'context'  => [ 'content' ],
			'category' => __( 'Content', 'content-control' ),
			'format'   => '{category} {verb} {label}',
			'verbs'    => [ $verbs['is'], $verbs['isnot'] ],
			'callback' => '__return_true',
		];

		$rules['content_is_front_page'] = [
			'name'     => 'content_is_front_page',
			'label'    => __( 'The Home Page', 'content-control' ),
			'context'  => [ 'content' ],
			'category' => __( 'Content', 'content-control' ),
			'format'   => '{category} {verb} {label}',
			'verbs'    => [ $verbs['is'], $verbs['isnot'] ],
			'callback' => '\ContentControl\Rules\content_is_home_page',
		];

		$rules['content_is_blog_index'] = [
			'name'     => 'content_is_blog_index',
			'label'    => __( 'The Blog Index', 'content-control' ),
			'context'  => [ 'content', 'posttype:post' ],
			'category' => __( 'Content', 'content-control' ),
			'format'   => '{category} {verb} {label}',
			'verbs'    => [ $verbs['is'], $verbs['isnot'] ],
			'callback' => '\ContentControl\Rules\content_is_blog_index',
		];

		$rules['content_is_search_results'] = [
			'name'     => 'content_is_search_results',
			'label'    => __( 'A Search Result Page', 'content-control' ),
			'context'  => [ 'content', 'search' ],
			'category' => __( 'Content', 'content-control' ),
			'format'   => '{category} {verb} {label}',
			'verbs'    => [ $verbs['is'], $verbs['isnot'] ],
			'callback' => '\is_search',
		];

		$rules['content_is_404_page'] = [
			'name'     => 'content_is_404_page',
			'label'    => __( 'A 404 Error Page', 'content-control' ),
			'context'  => [ 'content', '404' ],
			'category' => __( 'Content', 'content-control' ),
			'format'   => '{category} {verb} {label}',
			'verbs'    => [ $verbs['is'], $verbs['isnot'] ],
			'callback' => '\is_404',
		];

		return $rules;
	}

	/**
	 * Get a list of WP post type rules.
	 *
	 * @return array
	 */
	public function get_post_type_rules() {
		$verbs = $this->get_verbs();

		$rules      = [];
		$post_types = get_post_types( [ 'public' => true ], 'objects' );

		foreach ( $post_types as $name => $post_type ) {
			$type_rules = [];

			if ( $post_type->has_archive || 'post' === $name ) {
				$type_rules[ "content_is_{$name}_archive" ] = [
					'name'     => "content_is_{$name}_archive",
					/* translators: %s: Post type singular name */
					'label'    => sprintf( __( 'A %s Archive', 'content-control' ), $post_type->labels->singular_name ),
					'callback' => '\ContentControl\Rules\content_is_post_type_archive',
				];
			}

			$type_rules[ "content_is_{$name}" ] = [
				'name'     => "content_is_{$name}",
				/* translators: %s: Post type singular name */
				'label'    => sprintf( __( 'A %s', 'content-control' ), $post_type->labels->singular_name ),
				'callback' => '\ContentControl\Rules\content_is_post_type',
			];

			$type_rules[ "content_is_selected_{$name}" ] = [
				'name'     => "content_is_selected_{$name}",
				/* translators: %s: Post type singular name */
				'label'    => sprintf( __( 'A Selected %s', 'content-control' ), $post_type->labels->singular_name ),
				'fields'   => [
					'selected' => [
						/* translators: %s: Post type plurals name */
						'placeholder' => sprintf( __( 'Select %s.', 'content-control' ), strtolower( $post_type->labels->name ) ),
						'type'        => 'postselect',
						'post_type'   => $name,
						'multiple'    => true,
					],
				],
				'callback' => '\ContentControl\Rules\content_is_selected_post',
			];

			$type_rules[ "content_is_{$name}_with_id" ] = [
				'name'     => "content_is_{$name}_with_id",
				/* translators: %s: Post type singular name */
				'label'    => sprintf( __( 'A %s with ID', 'content-control' ), $post_type->labels->singular_name ),
				'fields'   => [
					'selected' => [
						/* translators: %s: Post type singular name */
						'placeholder' => sprintf( __( '%s IDs: 128, 129', 'content-control' ), strtolower( $post_type->labels->name ) ),
						'type'        => 'text',
					],
				],
				'callback' => '\ContentControl\Rules\content_is_selected_post',
			];

			if ( is_post_type_hierarchical( $name ) ) {
				$type_rules[ "content_is_child_of_{$name}" ] = [
					'name'     => "content_is_child_of_{$name}",
					/* translators: %s: Post type plural name */
					'label'    => sprintf( __( 'A Child of Selected %s', 'content-control' ), $post_type->labels->name ),
					'fields'   => [
						'selected' => [
							/* translators: %s: Post type plural name */
							'placeholder' => sprintf( __( 'Select %s.', 'content-control' ), strtolower( $post_type->labels->name ) ),
							'type'        => 'postselect',
							'post_type'   => $name,
							'multiple'    => true,
						],
					],
					'callback' => '\ContentControl\Rules\content_is_child_of_post',
				];

				$type_rules[ "content_is_ancestor_of_{$name}" ] = [
					'name'     => "content_is_ancestor_of_{$name}",
					/* translators: %s: Post type plural name */
					'label'    => sprintf( __( 'An Ancestor of Selected %s', 'content-control' ), $post_type->labels->name ),
					'fields'   => [
						'selected' => [
							/* translators: %s: Post type plural name */
							'placeholder' => sprintf( __( 'Select %s.', 'content-control' ), strtolower( $post_type->labels->name ) ),
							'type'        => 'postselect',
							'post_type'   => $name,
							'multiple'    => true,
						],
					],
					'callback' => '\ContentControl\Rules\content_is_ancestor_of_post',
				];
			}

			$templates = wp_get_theme()->get_page_templates();

			if ( 'page' === $name && ! empty( $templates ) ) {
				$type_rules[ "content_is_{$name}_with_template" ] = [
					'name'     => "content_is_{$name}_with_template",
					/* translators: %s: Post type singular name */
					'label'    => sprintf( __( 'A %s With Template', 'content-control' ), $post_type->labels->singular_name ),
					'fields'   => [
						'selected' => [
							'type'     => 'tokenselect',
							'multiple' => true,
							'options'  => array_merge( [ 'default' => __( 'Default', 'content-control' ) ], $templates ),
						],
					],
					'callback' => '\ContentControl\Rules\content_is_post_with_template',
				];
			}

			foreach ( $type_rules as $rule ) {
				// Merge defaults.
				$type_rules[ $rule['name'] ] = wp_parse_args( $rule, [
					'category' => __( 'Content', 'content-control' ),
					'context'  => [ 'content', "posttype:{$name}" ],
					'format'   => '{category} {verb} {label}',
					'verbs'    => [ $verbs['is'], $verbs['isnot'] ],
					'fields'   => [],
					'extras'   => [
						'post_type' => $name,
					],
				] );
			}

			// Merge type rules & type tax rules.
			$rules = array_merge( $rules, $type_rules, $this->get_post_type_tax_rules( $name ) );
		}

		return $rules;
	}

	/**
	 * Generate post type taxonomy rules.
	 *
	 * @param string $name Post type name.
	 *
	 * @return array
	 */
	public function get_post_type_tax_rules( $name ) {
		$verbs = $this->get_verbs();

		$post_type  = get_post_type_object( $name );
		$taxonomies = get_object_taxonomies( $name, 'object' );
		$rules      = [];

		foreach ( $taxonomies as $tax_name => $taxonomy ) {
			$rules[ "content_is_{$name}_with_{$tax_name}" ] = [
				'name'     => "content_is_{$name}_with_{$tax_name}",
				/* translators: %1$s: Post type singular name, %2$s: Taxonomy singular name */
				'label'    => sprintf( _x( 'A %1$s with %2$s', 'condition: post type plural and taxonomy singular label ie. A Post With Category', 'content-control' ), $post_type->labels->singular_name, $taxonomy->labels->singular_name ),
				'context'  => [ 'content', "posttype:{$name}", "taxonomy:{$tax_name}" ],
				'category' => __( 'Content', 'content-control' ),
				'format'   => '{category} {verb} {label}',
				'verbs'    => [ $verbs['is'], $verbs['isnot'] ],
				'fields'   => [
					'selected' => [
						/* translators: %s: Taxonomy singular name */
						'placeholder' => sprintf( _x( 'Select %s.', 'condition: post type plural label ie. Select categories', 'content-control' ), strtolower( $taxonomy->labels->name ) ),
						'type'        => 'taxonomyselect',
						'taxonomy'    => $tax_name,
						'multiple'    => true,
					],
				],
				'extras'   => [
					'post_type' => $name,
					'taxonomy'  => $tax_name,
				],
				'callback' => '\ContentControl\Rules\content_is_post_with_tax_term',
			];
		}

		return $rules;
	}

	/**
	 * Generates conditions for all public taxonomies.
	 *
	 * @return array
	 */
	public function get_taxonomy_rules() {
		$rules      = [];
		$taxonomies = get_taxonomies( [ 'public' => true ], 'objects' );
		$verbs      = $this->get_verbs();

		foreach ( $taxonomies as $tax_name => $taxonomy ) {
			$tax_defaults = [
				'category' => __( 'Content', 'content-control' ),
				'context'  => [ 'content', "taxonomy:{$tax_name}" ],
				'format'   => '{category} {verb} {label}',
				'verbs'    => [ $verbs['is'], $verbs['isnot'] ],
				'fields'   => [],
				'extras'   => [
					'taxonomy' => $tax_name,
				],
			];

			$rules[ "content_is_{$tax_name}_archive" ] = wp_parse_args( [
				'name'     => "content_is_{$tax_name}_archive",
				/* translators: %s: Taxonomy plural name */
				'label'    => sprintf( _x( 'A %s Archive', 'condition: taxonomy plural label ie. A Category Archive', 'content-control' ), $taxonomy->labels->singular_name ),
				'callback' => '\ContentControl\Rules\content_is_taxonomy_archive',
			], $tax_defaults );

			$rules[ "content_is_selected_tax_{$tax_name}" ] = wp_parse_args( [
				'name'     => "content_is_selected_tax_{$tax_name}",
				/* translators: %s: Taxonomy plural name */
				'label'    => sprintf( _x( 'A Selected %s', 'condition: taxonomy plural label ie. A Selected Category', 'content-control' ), $taxonomy->labels->singular_name ),
				'fields'   => [
					'selected' => [
						/* translators: %s: Taxonomy plural name */
						'placeholder' => sprintf( _x( 'Select %s.', 'condition: taxonomy plural label ie. Select Categories', 'content-control' ), strtolower( $taxonomy->labels->name ) ),
						'type'        => 'taxonomyselect',
						'taxonomy'    => $tax_name,
						'multiple'    => true,
					],
				],
				'callback' => '\ContentControl\Rules\content_is_selected_term',
			], $tax_defaults );

			$rules[ "content_is_tax_{$tax_name}_with_id" ] = wp_parse_args( [
				'name'     => "content_is_tax_{$tax_name}_with_id",
				/* translators: %s: Taxonomy plural name */
				'label'    => sprintf( _x( 'A %s with ID', 'condition: taxonomy plural label ie. A Category with ID: Selected', 'content-control' ), $taxonomy->labels->name ),
				'fields'   => [
					'selected' => [
						/* translators: %s: Taxonomy plural name */
						'placeholder' => sprintf( _x( '%s IDs: 128, 129', 'condition: taxonomy plural label ie. Category IDs', 'content-control' ), strtolower( $taxonomy->labels->singular_name ) ),
						'type'        => 'text',
					],
				],
				'callback' => '\ContentControl\Rules\content_is_selected_term',
			], $tax_defaults );
		}

		return $rules;
	}

	/**
	 * Get an array of rule default values.
	 *
	 * @return array Array of rule default values.
	 */
	public function get_rule_defaults() {
		$verbs = $this->get_verbs();
		return [
			'name'     => '',
			'label'    => '',
			'context'  => [],
			'category' => __( 'Content', 'content-control' ),
			'format'   => '{category} {verb} {label}',
			'verbs'    => [ $verbs['is'], $verbs['isnot'] ],
			'fields'   => [],
			'callback' => null,
			'frontend' => false,
		];
	}

	/**
	 * Register & remap deprecated conditions to rules.
	 *
	 * @return void
	 */
	public function register_deprecated_rules() {
		/**
		 * Filters the old conditions to be registered as rules.
		 *
		 * @deprecated 2.0.0
		 *
		 * @param array $old_rules Array of old rules to manipulate.
		 *
		 * @return array
		 */
		$old_rules = apply_filters( 'content_control/old_conditions', [] );

		if ( ! empty( $old_rules ) ) {
			$old_rules = $this->parse_old_rules( $old_rules );

			foreach ( $old_rules as $rule ) {
				$rule['deprecated'] = true;
				$this->register_rule( $rule );
			}
		}
	}

	/**
	 * Parse rules that are still registered using the older deprecated methods.
	 *
	 * @param array $old_rules Array of old rules to manipulate.
	 * @return array
	 */
	public function parse_old_rules( $old_rules ) {
		$new_rules = [];

		foreach ( $old_rules as $key => $old_rule ) {
			$new_rules[ $key ] = $this->remap_old_rule( $old_rule );
		}

		return $new_rules;
	}

	/**
	 * Remaps keys & values from an old `condition` into a new `rule`.
	 *
	 * @param array $old_rule Old rule definition.
	 * @return array New rule definition.
	 */
	public function remap_old_rule( $old_rule ) {
		$old_rule = wp_parse_args( $old_rule, $this->get_old_rule_defaults() );

		$new_rule = [
			'format' => '{label}',
		];

		$remaped_keys = [
			'id'       => 'name',
			'name'     => 'label',
			'group'    => 'category',
			'fields'   => 'fields',
			'callback' => 'callback',
			'advanced' => 'frontend',
			'priority' => 'priority',
		];

		foreach ( $remaped_keys as $old_key => $new_key ) {
			if ( isset( $old_rule[ $old_key ] ) ) {
				$new_rule[ $new_key ] = $old_rule[ $old_key ];
				unset( $old_rule[ $old_key ] );
			}
		}

		// Merge any leftover 'unknonw' keys, with new stuff second.
		return array_merge( $new_rule, $old_rule );
	}

	/**
	 * Get an array of old rule default values.
	 *
	 * @return array Array of old rule default values.
	 */
	private function get_old_rule_defaults() {
		return [
			'id'       => '',
			'callback' => null,
			'group'    => '',
			'name'     => '',
			'priority' => 10,
			'fields'   => [],
			'advanced' => false,
		];
	}
}

```
