PluginProbe
Content Control – The Ultimate Content Restriction Plugin! Restrict Content, Create Conditional Blocks & More / 2.0.0
Content Control – The Ultimate Content Restriction Plugin! Restrict Content, Create Conditional Blocks & More v2.0.0
trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.10 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 2.0.0 2.0.1 2.0.10 2.0.11 2.0.12 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 All 47 releases
content-control / classes / RuleEngine / Rules.php

Rules.php in Content Control – The Ultimate Content Restriction Plugin! Restrict Content, Create Conditional Blocks & More 2.0.0, at classes/RuleEngine/Rules.php

650 lines 18.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Rule registery
4 *
5 * @package ContentControl
6 */
7
8 namespace ContentControl\RuleEngine;
9
10 /**
11 * Rules registry
12 */
13 class Rules {
14
15 /**
16 * Array of rules.
17 *
18 * @var array
19 */
20 private $data = [];
21
22 /**
23 * Current global rule instance.
24 *
25 * @var Rule
26 */
27 public $current_rule = null;
28
29 /**
30 * Get the current global rule instance.
31 *
32 * @param Rule|null|false $rule Rule instance to set.
33 * @return Rule|null
34 */
35 public function current_rule( $rule = false ) {
36 if ( false === $rule ) {
37 return $this->current_rule;
38 }
39
40 $this->current_rule = $rule;
41 }
42
43 /**
44 * Set up rules list.
45 *
46 * @return void
47 */
48 public function init() {
49 // Register rules.
50 $this->register_built_in_rules();
51
52 // Register deprecated rules (using old filter).
53 $this->register_deprecated_rules();
54 }
55
56 /**
57 * Register new rule type.
58 *
59 * @param array $rule New rule to register.
60 * @return void
61 */
62 public function register_rule( $rule ) {
63 if ( $this->is_rule_valid( $rule ) ) {
64 $rule = wp_parse_args( $rule, $this->get_rule_defaults() );
65
66 $index = $rule['name'];
67 /**
68 * In the case multiple conditions are registered with the same
69 * identifier, we append an integer. This do/while quickly increases
70 * the integer by one until a valid new key is found.
71 */
72 if ( array_key_exists( $index, $this->data ) ) {
73 $i = 0;
74 do {
75 ++$i;
76 $index = $rule['name'] . '-' . $i;
77 } while ( array_key_exists( $index, $this->data ) );
78 }
79
80 $indexs[] = $index;
81 $this->data[ $index ] = $rule;
82 }
83 }
84
85 /**
86 * Check if rule is valid.
87 *
88 * @param array $rule Rule to test.
89 * @return boolean
90 */
91 public function is_rule_valid( $rule ) {
92 return ! empty( $rule ) && true;
93 }
94
95 /**
96 * Get array of all registered rules.
97 *
98 * @return array
99 */
100 public function get_rules() {
101 if ( ! did_action( 'content_control/rule_engine/register_rules' ) ) {
102 $this->init();
103 }
104
105 return $this->data;
106 }
107
108 /**
109 * Get a rule definition by name.
110 *
111 * @param string $rule_name Rule definition or null.
112 * @return array|null
113 */
114 public function get_rule( $rule_name ) {
115 $rules = $this->get_rules();
116 return isset( $rules[ $rule_name ] ) ? $rules[ $rule_name ] : null;
117 }
118
119 /**
120 * Get array of registered rules filtered for the block-editor.
121 *
122 * @return array
123 */
124 public function get_block_editor_rules() {
125 $rules = $this->get_rules();
126
127 /**
128 * Filter the rules.
129 *
130 * @param array $rules Rules.
131 *
132 * @return array
133 */
134 return apply_filters( 'content_control/rule_engine/get_block_editor_rules', $rules );
135 }
136
137 /**
138 * Get list of verbs.
139 *
140 * @return array List of verbs with translatable text.
141 */
142 public function get_verbs() {
143 return [
144 'are' => __( 'Are', 'content-control' ),
145 'arenot' => __( 'Are Not', 'content-control' ),
146 'is' => __( 'Is', 'content-control' ),
147 'isnot' => __( 'Is Not', 'content-control' ),
148 'has' => __( 'Has', 'content-control' ),
149 'hasnot' => __( 'Has Not', 'content-control' ),
150 'can' => __( 'Can', 'content-control' ),
151 'cannot' => __( 'Can Not', 'content-control' ),
152 'doesnothave' => __( 'Does Not Have', 'content-control' ),
153 'does' => __( 'Does', 'content-control' ),
154 'doesnot' => __( 'Does Not', 'content-control' ),
155 'was' => __( 'Was', 'content-control' ),
156 'wasnot' => __( 'Was Not', 'content-control' ),
157 'were' => __( 'Were', 'content-control' ),
158 'werenot' => __( 'Were Not', 'content-control' ),
159 ];
160 }
161
162 /**
163 * Get a list of built in rules.
164 *
165 * @return void
166 */
167 private function register_built_in_rules() {
168 $rules = array_merge(
169 $this->get_user_rules(),
170 $this->get_general_content_rules(),
171 $this->get_post_type_rules(),
172 $this->get_taxonomy_rules()
173 );
174
175 /**
176 * Allow registering additional rules quickly.
177 *
178 * @param array $rules Rules.
179 *
180 * @return array
181 */
182 $rules = apply_filters( 'content_control/rule_engine/rules', $rules );
183
184 foreach ( $rules as $rule ) {
185 $this->register_rule( $rule );
186 }
187
188 /**
189 * Allow manipulating registered rules.
190 *
191 * @param Rules $this Rules instance.
192 *
193 * @return void
194 */
195 do_action( 'content_control/rule_engine/register_rules', $this );
196 }
197
198 /**
199 * Get a list of user rules.
200 *
201 * @return array
202 */
203 public function get_user_rules() {
204 $verbs = $this->get_verbs();
205 return [
206 'user_is_logged_in' => [
207 'name' => 'user_is_logged_in',
208 'label' => __( 'Logged In', 'content-control' ),
209 'context' => [ 'user' ],
210 'category' => __( 'User', 'content-control' ),
211 'format' => '{category} {verb} {label}',
212 'verbs' => [ $verbs['is'], $verbs['isnot'] ],
213 'callback' => '\is_user_logged_in',
214 ],
215 'user_has_role' => [
216 'name' => 'user_has_role',
217 'label' => __( 'Role(s)', 'content-control' ),
218 'context' => [ 'user' ],
219 'category' => __( 'User', 'content-control' ),
220 'format' => '{category} {verb} {label}',
221 'verbs' => [ $verbs['has'], $verbs['doesnothave'] ],
222 'fields' => [
223 'roles' => [
224 'label' => __( 'Role(s)', 'content-control' ),
225 'type' => 'tokenselect',
226 'multiple' => true,
227 'options' => wp_roles()->get_names(),
228 ],
229 ],
230 'callback' => '\ContentControl\Rules\user_has_role',
231 ],
232 ];
233 }
234
235 /**
236 * Get a list of general content rules.
237 *
238 * @return array
239 */
240 public function get_general_content_rules() {
241 $rules = [];
242 $verbs = $this->get_verbs();
243
244 $rules['entire_site'] = [
245 'name' => 'entire_site',
246 'label' => __( 'Entire Site (Any Page, Post, or Archive)', 'content-control' ),
247 'context' => [ 'content' ],
248 'category' => __( 'Content', 'content-control' ),
249 'format' => '{category} {verb} {label}',
250 'verbs' => [ $verbs['is'], $verbs['isnot'] ],
251 'callback' => '__return_true',
252 ];
253
254 $rules['content_is_front_page'] = [
255 'name' => 'content_is_front_page',
256 'label' => __( 'The Home Page', 'content-control' ),
257 'context' => [ 'content' ],
258 'category' => __( 'Content', 'content-control' ),
259 'format' => '{category} {verb} {label}',
260 'verbs' => [ $verbs['is'], $verbs['isnot'] ],
261 'callback' => '\ContentControl\Rules\content_is_home_page',
262 ];
263
264 $rules['content_is_blog_index'] = [
265 'name' => 'content_is_blog_index',
266 'label' => __( 'The Blog Index', 'content-control' ),
267 'context' => [ 'content', 'posttype:post' ],
268 'category' => __( 'Content', 'content-control' ),
269 'format' => '{category} {verb} {label}',
270 'verbs' => [ $verbs['is'], $verbs['isnot'] ],
271 'callback' => '\ContentControl\Rules\content_is_blog_index',
272 ];
273
274 $rules['content_is_search_results'] = [
275 'name' => 'content_is_search_results',
276 'label' => __( 'A Search Result Page', 'content-control' ),
277 'context' => [ 'content', 'search' ],
278 'category' => __( 'Content', 'content-control' ),
279 'format' => '{category} {verb} {label}',
280 'verbs' => [ $verbs['is'], $verbs['isnot'] ],
281 'callback' => '\is_search',
282 ];
283
284 $rules['content_is_404_page'] = [
285 'name' => 'content_is_404_page',
286 'label' => __( 'A 404 Error Page', 'content-control' ),
287 'context' => [ 'content', '404' ],
288 'category' => __( 'Content', 'content-control' ),
289 'format' => '{category} {verb} {label}',
290 'verbs' => [ $verbs['is'], $verbs['isnot'] ],
291 'callback' => '\is_404',
292 ];
293
294 return $rules;
295 }
296
297 /**
298 * Get a list of WP post type rules.
299 *
300 * @return array
301 */
302 public function get_post_type_rules() {
303 $verbs = $this->get_verbs();
304
305 $rules = [];
306 $post_types = get_post_types( [ 'public' => true ], 'objects' );
307
308 foreach ( $post_types as $name => $post_type ) {
309 $type_rules = [];
310
311 if ( $post_type->has_archive || 'post' === $name ) {
312 $type_rules[ "content_is_{$name}_archive" ] = [
313 'name' => "content_is_{$name}_archive",
314 /* translators: %s: Post type singular name */
315 'label' => sprintf( __( 'A %s Archive', 'content-control' ), $post_type->labels->singular_name ),
316 'callback' => '\ContentControl\Rules\content_is_post_type_archive',
317 ];
318 }
319
320 $type_rules[ "content_is_{$name}" ] = [
321 'name' => "content_is_{$name}",
322 /* translators: %s: Post type singular name */
323 'label' => sprintf( __( 'A %s', 'content-control' ), $post_type->labels->singular_name ),
324 'callback' => '\ContentControl\Rules\content_is_post_type',
325 ];
326
327 $type_rules[ "content_is_selected_{$name}" ] = [
328 'name' => "content_is_selected_{$name}",
329 /* translators: %s: Post type singular name */
330 'label' => sprintf( __( 'A Selected %s', 'content-control' ), $post_type->labels->singular_name ),
331 'fields' => [
332 'selected' => [
333 /* translators: %s: Post type plurals name */
334 'placeholder' => sprintf( __( 'Select %s.', 'content-control' ), strtolower( $post_type->labels->name ) ),
335 'type' => 'postselect',
336 'post_type' => $name,
337 'multiple' => true,
338 ],
339 ],
340 'callback' => '\ContentControl\Rules\content_is_selected_post',
341 ];
342
343 $type_rules[ "content_is_{$name}_with_id" ] = [
344 'name' => "content_is_{$name}_with_id",
345 /* translators: %s: Post type singular name */
346 'label' => sprintf( __( 'A %s with ID', 'content-control' ), $post_type->labels->singular_name ),
347 'fields' => [
348 'selected' => [
349 /* translators: %s: Post type singular name */
350 'placeholder' => sprintf( __( '%s IDs: 128, 129', 'content-control' ), strtolower( $post_type->labels->name ) ),
351 'type' => 'text',
352 ],
353 ],
354 'callback' => '\ContentControl\Rules\content_is_selected_post',
355 ];
356
357 if ( is_post_type_hierarchical( $name ) ) {
358 $type_rules[ "content_is_child_of_{$name}" ] = [
359 'name' => "content_is_child_of_{$name}",
360 /* translators: %s: Post type plural name */
361 'label' => sprintf( __( 'A Child of Selected %s', 'content-control' ), $post_type->labels->name ),
362 'fields' => [
363 'selected' => [
364 /* translators: %s: Post type plural name */
365 'placeholder' => sprintf( __( 'Select %s.', 'content-control' ), strtolower( $post_type->labels->name ) ),
366 'type' => 'postselect',
367 'post_type' => $name,
368 'multiple' => true,
369 ],
370 ],
371 'callback' => '\ContentControl\Rules\content_is_child_of_post',
372 ];
373
374 $type_rules[ "content_is_ancestor_of_{$name}" ] = [
375 'name' => "content_is_ancestor_of_{$name}",
376 /* translators: %s: Post type plural name */
377 'label' => sprintf( __( 'An Ancestor of Selected %s', 'content-control' ), $post_type->labels->name ),
378 'fields' => [
379 'selected' => [
380 /* translators: %s: Post type plural name */
381 'placeholder' => sprintf( __( 'Select %s.', 'content-control' ), strtolower( $post_type->labels->name ) ),
382 'type' => 'postselect',
383 'post_type' => $name,
384 'multiple' => true,
385 ],
386 ],
387 'callback' => '\ContentControl\Rules\content_is_ancestor_of_post',
388 ];
389 }
390
391 $templates = wp_get_theme()->get_page_templates();
392
393 if ( 'page' === $name && ! empty( $templates ) ) {
394 $type_rules[ "content_is_{$name}_with_template" ] = [
395 'name' => "content_is_{$name}_with_template",
396 /* translators: %s: Post type singular name */
397 'label' => sprintf( __( 'A %s With Template', 'content-control' ), $post_type->labels->singular_name ),
398 'fields' => [
399 'selected' => [
400 'type' => 'tokenselect',
401 'multiple' => true,
402 'options' => array_merge( [ 'default' => __( 'Default', 'content-control' ) ], $templates ),
403 ],
404 ],
405 'callback' => '\ContentControl\Rules\content_is_post_with_template',
406 ];
407 }
408
409 foreach ( $type_rules as $rule ) {
410 // Merge defaults.
411 $type_rules[ $rule['name'] ] = wp_parse_args( $rule, [
412 'category' => __( 'Content', 'content-control' ),
413 'context' => [ 'content', "posttype:{$name}" ],
414 'format' => '{category} {verb} {label}',
415 'verbs' => [ $verbs['is'], $verbs['isnot'] ],
416 'fields' => [],
417 'extras' => [
418 'post_type' => $name,
419 ],
420 ] );
421 }
422
423 // Merge type rules & type tax rules.
424 $rules = array_merge( $rules, $type_rules, $this->get_post_type_tax_rules( $name ) );
425 }
426
427 return $rules;
428 }
429
430 /**
431 * Generate post type taxonomy rules.
432 *
433 * @param string $name Post type name.
434 *
435 * @return array
436 */
437 public function get_post_type_tax_rules( $name ) {
438 $verbs = $this->get_verbs();
439
440 $post_type = get_post_type_object( $name );
441 $taxonomies = get_object_taxonomies( $name, 'object' );
442 $rules = [];
443
444 foreach ( $taxonomies as $tax_name => $taxonomy ) {
445 $rules[ "content_is_{$name}_with_{$tax_name}" ] = [
446 'name' => "content_is_{$name}_with_{$tax_name}",
447 /* translators: %1$s: Post type singular name, %2$s: Taxonomy singular name */
448 '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 ),
449 'context' => [ 'content', "posttype:{$name}", "taxonomy:{$tax_name}" ],
450 'category' => __( 'Content', 'content-control' ),
451 'format' => '{category} {verb} {label}',
452 'verbs' => [ $verbs['is'], $verbs['isnot'] ],
453 'fields' => [
454 'selected' => [
455 /* translators: %s: Taxonomy singular name */
456 'placeholder' => sprintf( _x( 'Select %s.', 'condition: post type plural label ie. Select categories', 'content-control' ), strtolower( $taxonomy->labels->name ) ),
457 'type' => 'taxonomyselect',
458 'taxonomy' => $tax_name,
459 'multiple' => true,
460 ],
461 ],
462 'extras' => [
463 'post_type' => $name,
464 'taxonomy' => $tax_name,
465 ],
466 'callback' => '\ContentControl\Rules\content_is_post_with_tax_term',
467 ];
468 }
469
470 return $rules;
471 }
472
473 /**
474 * Generates conditions for all public taxonomies.
475 *
476 * @return array
477 */
478 public function get_taxonomy_rules() {
479 $rules = [];
480 $taxonomies = get_taxonomies( [ 'public' => true ], 'objects' );
481 $verbs = $this->get_verbs();
482
483 foreach ( $taxonomies as $tax_name => $taxonomy ) {
484 $tax_defaults = [
485 'category' => __( 'Content', 'content-control' ),
486 'context' => [ 'content', "taxonomy:{$tax_name}" ],
487 'format' => '{category} {verb} {label}',
488 'verbs' => [ $verbs['is'], $verbs['isnot'] ],
489 'fields' => [],
490 'extras' => [
491 'taxonomy' => $tax_name,
492 ],
493 ];
494
495 $rules[ "content_is_{$tax_name}_archive" ] = wp_parse_args( [
496 'name' => "content_is_{$tax_name}_archive",
497 /* translators: %s: Taxonomy plural name */
498 'label' => sprintf( _x( 'A %s Archive', 'condition: taxonomy plural label ie. A Category Archive', 'content-control' ), $taxonomy->labels->singular_name ),
499 'callback' => '\ContentControl\Rules\content_is_taxonomy_archive',
500 ], $tax_defaults );
501
502 $rules[ "content_is_selected_tax_{$tax_name}" ] = wp_parse_args( [
503 'name' => "content_is_selected_tax_{$tax_name}",
504 /* translators: %s: Taxonomy plural name */
505 'label' => sprintf( _x( 'A Selected %s', 'condition: taxonomy plural label ie. A Selected Category', 'content-control' ), $taxonomy->labels->singular_name ),
506 'fields' => [
507 'selected' => [
508 /* translators: %s: Taxonomy plural name */
509 'placeholder' => sprintf( _x( 'Select %s.', 'condition: taxonomy plural label ie. Select Categories', 'content-control' ), strtolower( $taxonomy->labels->name ) ),
510 'type' => 'taxonomyselect',
511 'taxonomy' => $tax_name,
512 'multiple' => true,
513 ],
514 ],
515 'callback' => '\ContentControl\Rules\content_is_selected_term',
516 ], $tax_defaults );
517
518 $rules[ "content_is_tax_{$tax_name}_with_id" ] = wp_parse_args( [
519 'name' => "content_is_tax_{$tax_name}_with_id",
520 /* translators: %s: Taxonomy plural name */
521 'label' => sprintf( _x( 'A %s with ID', 'condition: taxonomy plural label ie. A Category with ID: Selected', 'content-control' ), $taxonomy->labels->name ),
522 'fields' => [
523 'selected' => [
524 /* translators: %s: Taxonomy plural name */
525 'placeholder' => sprintf( _x( '%s IDs: 128, 129', 'condition: taxonomy plural label ie. Category IDs', 'content-control' ), strtolower( $taxonomy->labels->singular_name ) ),
526 'type' => 'text',
527 ],
528 ],
529 'callback' => '\ContentControl\Rules\content_is_selected_term',
530 ], $tax_defaults );
531 }
532
533 return $rules;
534 }
535
536 /**
537 * Get an array of rule default values.
538 *
539 * @return array Array of rule default values.
540 */
541 public function get_rule_defaults() {
542 $verbs = $this->get_verbs();
543 return [
544 'name' => '',
545 'label' => '',
546 'context' => [],
547 'category' => __( 'Content', 'content-control' ),
548 'format' => '{category} {verb} {label}',
549 'verbs' => [ $verbs['is'], $verbs['isnot'] ],
550 'fields' => [],
551 'callback' => null,
552 'frontend' => false,
553 ];
554 }
555
556 /**
557 * Register & remap deprecated conditions to rules.
558 *
559 * @return void
560 */
561 public function register_deprecated_rules() {
562 /**
563 * Filters the old conditions to be registered as rules.
564 *
565 * @deprecated 2.0.0
566 *
567 * @param array $old_rules Array of old rules to manipulate.
568 *
569 * @return array
570 */
571 $old_rules = apply_filters( 'content_control/old_conditions', [] );
572
573 if ( ! empty( $old_rules ) ) {
574 $old_rules = $this->parse_old_rules( $old_rules );
575
576 foreach ( $old_rules as $rule ) {
577 $rule['deprecated'] = true;
578 $this->register_rule( $rule );
579 }
580 }
581 }
582
583 /**
584 * Parse rules that are still registered using the older deprecated methods.
585 *
586 * @param array $old_rules Array of old rules to manipulate.
587 * @return array
588 */
589 public function parse_old_rules( $old_rules ) {
590 $new_rules = [];
591
592 foreach ( $old_rules as $key => $old_rule ) {
593 $new_rules[ $key ] = $this->remap_old_rule( $old_rule );
594 }
595
596 return $new_rules;
597 }
598
599 /**
600 * Remaps keys & values from an old `condition` into a new `rule`.
601 *
602 * @param array $old_rule Old rule definition.
603 * @return array New rule definition.
604 */
605 public function remap_old_rule( $old_rule ) {
606 $old_rule = wp_parse_args( $old_rule, $this->get_old_rule_defaults() );
607
608 $new_rule = [
609 'format' => '{label}',
610 ];
611
612 $remaped_keys = [
613 'id' => 'name',
614 'name' => 'label',
615 'group' => 'category',
616 'fields' => 'fields',
617 'callback' => 'callback',
618 'advanced' => 'frontend',
619 'priority' => 'priority',
620 ];
621
622 foreach ( $remaped_keys as $old_key => $new_key ) {
623 if ( isset( $old_rule[ $old_key ] ) ) {
624 $new_rule[ $new_key ] = $old_rule[ $old_key ];
625 unset( $old_rule[ $old_key ] );
626 }
627 }
628
629 // Merge any leftover 'unknonw' keys, with new stuff second.
630 return array_merge( $new_rule, $old_rule );
631 }
632
633 /**
634 * Get an array of old rule default values.
635 *
636 * @return array Array of old rule default values.
637 */
638 private function get_old_rule_defaults() {
639 return [
640 'id' => '',
641 'callback' => null,
642 'group' => '',
643 'name' => '',
644 'priority' => 10,
645 'fields' => [],
646 'advanced' => false,
647 ];
648 }
649 }
650