PluginProbe
Groups – Memberships and Access Control / 4.7.0
Groups – Memberships and Access Control v4.7.0
4.7.1 4.7.0 4.6.0 4.5.0 4.4.0 4.3.0 trunk 1.0.0-beta-1 1.0.0-beta-2 1.0.0-beta-3 1.0.0-beta-3b 1.0.0-beta-3c 1.0.0-beta-3d 1.1.4 1.1.5 1.10.0 1.10.1 1.10.2 1.10.3 1.11.0 1.11.1 1.11.2 1.11.3 1.12.0 1.13.0 All 131 releases
groups / lib / core / class-groups-cache-robot.php

class-groups-cache-robot.php in Groups – Memberships and Access Control 4.7.0, at lib/core/class-groups-cache-robot.php

593 lines 15.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * class-groups-cache-robot.php
4 *
5 * Copyright (c) "kento" Karim Rahimpur www.itthinx.com
6 *
7 * This code is released under the GNU General Public License.
8 * See COPYRIGHT.txt and LICENSE.txt.
9 *
10 * This code is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * This header and all notices must be kept intact.
16 *
17 * @author Karim Rahimpur
18 * @package groups
19 * @since groups 4.0.0
20 */
21
22 if ( !defined( 'ABSPATH' ) ) {
23 exit;
24 }
25
26 /**
27 * Cache robot automates cache actions and invalidation.
28 */
29 class Groups_Cache_Robot {
30
31 /**
32 * @var string[]
33 */
34 private static $comment_groups = array();
35
36 /**
37 * @var string[]
38 */
39 private static $post_groups = array();
40
41 /**
42 * @var string[]
43 */
44 private static $user_groups = array();
45
46 /**
47 * @var string[]
48 */
49 private static $term_groups = array();
50
51 /**
52 * @var string[]
53 */
54 private static $flush_groups = array();
55
56 /**
57 * @var boolean
58 */
59 private static $debug = false;
60
61 /**
62 * Register groups and actions.
63 */
64 public static function init() {
65 // * Currently, all cache groups resolve to 'groups' but as these may change
66 // and others can be added, all applicable should be processed here.
67 // * Apparent redundancy is by design. Multiple triggered actions resulting
68 // in flush scheduled will only cause a single group flush to be processed
69 // during shutdown.
70 // * If group flush is not supported, full cache is flushed.
71
72 if ( defined( 'GROUPS_CACHE_DEBUG' ) && GROUPS_CACHE_DEBUG ) {
73 self::$debug = true;
74 }
75
76 if ( class_exists( 'Groups_Post_Access_Legacy' ) ) {
77 self::$post_groups[] = Groups_Post_Access_Legacy::CACHE_GROUP;
78 self::$user_groups[] = Groups_Post_Access_Legacy::CACHE_GROUP;
79 }
80
81 self::$comment_groups[] = Groups_Comment_Access::CACHE_GROUP;
82 self::$post_groups[] = Groups_Comment_Access::CACHE_GROUP;
83 self::$user_groups[] = Groups_Comment_Access::CACHE_GROUP;
84
85 self::$post_groups[] = Groups_Post_Access::CACHE_GROUP;
86 self::$user_groups[] = Groups_Post_Access::CACHE_GROUP;
87
88 if ( class_exists( 'Groups_Admin_Post_Columns' ) ) {
89 self::$term_groups[] = Groups_Admin_Post_Columns::CACHE_GROUP;
90 self::$user_groups[] = Groups_Admin_Post_Columns::CACHE_GROUP;
91 }
92
93 self::$user_groups[] = Groups_WordPress::CACHE_GROUP;
94
95 // comments
96 add_action( 'deleted_comment', array( __CLASS__, 'comment' ), 10, 2 );
97 add_action( 'trashed_comment', array( __CLASS__, 'comment' ), 10, 2 );
98 add_action( 'untrashed_comment', array( __CLASS__, 'comment' ), 10, 2 );
99 add_action( 'spammed_comment', array( __CLASS__, 'comment' ), 10, 2 );
100 add_action( 'unspammed_comment', array( __CLASS__, 'comment' ), 10, 2 );
101 add_action( 'transition_comment_status', array( __CLASS__, 'comment' ), 10, 3 );
102 add_action( 'wp_insert_comment', array( __CLASS__, 'comment' ), 10, 2 );
103 add_action( 'edit_comment', array( __CLASS__, 'comment' ), 10, 2 );
104
105 // posts
106 add_action( 'deleted_post', array( __CLASS__, 'post' ), 10, 2 );
107 add_action( 'trashed_post', array( __CLASS__, 'post' ), 10, 2 );
108 add_action( 'untrashed_post', array( __CLASS__, 'post' ), 10, 2 );
109 add_action( 'save_post', array( __CLASS__, 'post' ), 10, 3 );
110 // save_post covers add_action( 'transition_post_status', array( __CLASS__, 'post' ), 10, 3 );
111
112 // users
113 add_action( 'wp_update_user', array( __CLASS__, 'user' ), 10, 3 );
114 add_action( 'add_user_role', array( __CLASS__, 'user' ), 10, 2 );
115 add_action( 'set_user_role', array( __CLASS__, 'user' ), 10, 3 );
116 add_action( 'remove_user_role', array( __CLASS__, 'user' ), 10, 2 );
117 add_action( 'granted_super_admin', array( __CLASS__, 'user' ), 10 );
118 add_action( 'revoked_super_admin', array( __CLASS__, 'user' ), 10 );
119 add_action( 'profile_update', array( __CLASS__, 'user' ), 10, 3 );
120
121 // terms
122 // created_term is covered by saved_term (they always fire in sequence)
123 add_action( 'delete_term', array( __CLASS__, 'term' ), 10, 5 );
124 add_action( 'saved_term', array( __CLASS__, 'term' ), 10, 5 );
125 add_action( 'set_object_terms', array( __CLASS__, 'term' ), 10, 6 );
126 add_action( 'deleted_term_relationships', array( __CLASS__, 'term' ), 10, 3 );
127
128 // actions that affect relationship between user and group
129 add_action( 'groups_created_user_group', array( __CLASS__, 'all' ), 10, 2 );
130 add_action( 'groups_updated_user_group', array( __CLASS__, 'all' ), 10, 2 );
131 add_action( 'groups_deleted_user_group', array( __CLASS__, 'all' ), 10, 2 );
132
133 // actions that affect relationship between capability and group
134 add_action( 'groups_created_group_capability', array( __CLASS__, 'all' ), 10, 2 );
135 add_action( 'groups_updated_group_capability', array( __CLASS__, 'all' ), 10, 2 );
136 add_action( 'groups_deleted_group_capability', array( __CLASS__, 'all' ), 10, 2 );
137
138 // actions that affect relationship between user and capability
139 add_action( 'groups_created_user_capability', array( __CLASS__, 'all' ), 10, 2 );
140 add_action( 'groups_updated_user_capability', array( __CLASS__, 'all' ), 10, 2 );
141 add_action( 'groups_deleted_user_capability', array( __CLASS__, 'all' ), 10, 2 );
142
143 // general options updated
144 add_action( 'groups_updated_option', array( __CLASS__, 'all' ), 10, 2 );
145 add_action( 'groups_deleted_option', array( __CLASS__, 'all' ) );
146 add_action( 'groups_flushed_options', array( __CLASS__, 'all' ), 10, 0 );
147
148 add_action( 'shutdown', array( __CLASS__, 'shutdown' ) );
149 }
150
151 /**
152 * Comment groups.
153 *
154 * @return string[]
155 */
156 private static function get_comment_groups() {
157 /**
158 * Filter comment groups.
159 *
160 * @param string[] $groups
161 *
162 * @return string[]
163 */
164 return apply_filters( 'groups_cache_robot_comment_groups', self::$comment_groups );
165 }
166
167 /**
168 * Post groups.
169 *
170 * @return string[]
171 */
172 private static function get_post_groups() {
173 /**
174 * Filter post groups.
175 *
176 * @param string[] $groups
177 *
178 * @return string[]
179 */
180 return apply_filters( 'groups_cache_robot_post_groups', self::$post_groups );
181 }
182
183 /**
184 * Term groups.
185 *
186 * @return string[]
187 */
188 private static function get_term_groups() {
189 /**
190 * Filter term groups.
191 *
192 * @param string[] $groups
193 *
194 * @return string[]
195 */
196 return apply_filters( 'groups_cache_robot_term_groups', self::$term_groups );
197 }
198
199 /**
200 * User groups.
201 *
202 * @return string[]
203 */
204 private static function get_user_groups() {
205 /**
206 * Filter user groups.
207 *
208 * @param string[] $groups
209 *
210 * @return string[]
211 */
212 return apply_filters( 'groups_cache_robot_user_groups', self::$user_groups );
213 }
214
215 /**
216 * Join array elements as set.
217 *
218 * @param array $a
219 * @param array $b
220 *
221 * @return array
222 */
223 public static function join( $a, $b ) {
224 return array_unique( array_merge( $a, $b ) );
225 }
226
227 /**
228 * Schedule comment groups to flush.
229 *
230 * @param mixed ...$args
231 */
232 public static function comment( ...$args ) {
233
234 $apply = false;
235
236 $action = current_action();
237 if ( $action !== false ) {
238 switch ( $action ) {
239 case 'deleted_comment':
240 case 'trashed_comment':
241 case 'untrashed_comment':
242 case 'spammed_comment':
243 case 'unspammed_comment':
244 $apply = self::apply_comment( $args[1] ?? null );
245 break;
246 case 'wp_insert_comment':
247 $apply = self::apply_comment( $args[1] ?? null );
248 if ( $apply ) {
249 $comment = $args[1] ?? null;
250 if ( $comment instanceof WP_Comment ) {
251 if ( !$comment->comment_approved ) {
252 $apply = false;
253 }
254 }
255 }
256 break;
257 case 'transition_comment_status':
258 $apply = self::apply_comment( $args[2] ?? null );
259 break;
260 case 'edit_comment':
261 $apply = self::apply_comment( $args[0] ?? null );
262 break;
263 }
264 }
265
266 /**
267 * Add comment groups to flush?
268 *
269 * @param boolean $apply
270 * @param string $action
271 * @param array|Traversable $args
272 *
273 * @return boolean
274 */
275 $apply = apply_filters( 'groups_cache_robot_flush_comment', true, current_action(), $args );
276 if ( $apply ) {
277 self::$flush_groups = self::join( self::$flush_groups, self::get_comment_groups() );
278 if ( self::$debug ) {
279 Groups_Log::log(
280 sprintf(
281 'Cache flush+ [comment] [%s] %s',
282 current_action() ?? 'no action',
283 json_encode( self::$flush_groups )
284 )
285 );
286 }
287 }
288 }
289
290 /**
291 * Apply to comment.
292 *
293 * @param WP_Comment|int $comment
294 *
295 * @return boolean
296 */
297 private static function apply_comment( $comment ) {
298 $apply = false;
299 if ( is_numeric( $comment ) ) {
300 $comment = WP_Comment::get_instance( $comment );
301 }
302 if ( $comment instanceof WP_Comment ) {
303 $post_type = get_post_type( $comment->comment_post_ID );
304 if ( $post_type ) {
305 $apply = Groups_Post_Access::handles_post_type( $post_type );
306 }
307 }
308 return $apply;
309 }
310
311 /**
312 * Schedule post groups to flush.
313 *
314 * @param mixed ...$args
315 */
316 public static function post( ...$args ) {
317
318 $apply = false;
319 $post_type = null;
320
321 $action = current_action();
322 if ( $action !== false ) {
323 switch ( $action ) {
324 case 'save_post':
325 $post = $args[1] ?? null;
326 if ( $post instanceof WP_Post ) {
327 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE || wp_is_post_revision( $post ) || wp_is_post_autosave( $post ) || $post->post_status === 'auto-draft' ) {
328 } else {
329 if ( Groups_Post_Access::handles_post_type( $post->post_type ) ) {
330 $apply = true;
331 $post_type = $post->post_type;
332 }
333 }
334 }
335 break;
336 case 'deleted_post':
337 $post = $args[1] ?? null;
338 if ( $post instanceof WP_Post ) {
339 if ( Groups_Post_Access::handles_post_type( $post->post_type ) ) {
340 $apply = true;
341 $post_type = $post->post_type;
342 }
343 }
344 break;
345 case 'trashed_post':
346 case 'untrashed_post':
347 $post_type = get_post_type( $args[0] ?? -1 );
348 if ( is_string( $post_type ) ) {
349 if ( Groups_Post_Access::handles_post_type( $post_type ) ) {
350 $apply = true;
351 }
352 }
353 break;
354 }
355 }
356
357 /**
358 * Add post groups to flush?
359 *
360 * @param boolean $apply
361 * @param string $action
362 * @param array|Traversable $args
363 *
364 * @return boolean
365 */
366 $apply = apply_filters( 'groups_cache_robot_flush_post', $apply, current_action(), $args );
367 if ( $apply ) {
368 self::$flush_groups = self::join( self::$flush_groups, self::get_post_groups() );
369 if ( $post_type !== null ) {
370 self::$flush_groups[] = Groups_Post_Access::get_post_type_cache_group( $post_type );
371 if ( self::$debug ) {
372 Groups_Log::log(
373 sprintf(
374 'Cache flush+ [post] [%s] %s',
375 current_action() ?? 'no action',
376 json_encode( self::$flush_groups )
377 )
378 );
379 }
380 }
381 }
382 }
383
384 /**
385 * Schedule user groups to flush.
386 *
387 * @param mixed ...$args
388 */
389 public static function user( ...$args ) {
390 /**
391 * Add user groups to flush?
392 *
393 * @param boolean $apply
394 * @param string $action
395 * @param array|Traversable $args
396 *
397 * @return boolean
398 */
399 $apply = apply_filters( 'groups_cache_robot_flush_user', true, current_action(), $args );
400 if ( $apply ) {
401 self::$flush_groups = self::join( self::$flush_groups, self::get_user_groups() );
402 if ( self::$debug ) {
403 Groups_Log::log(
404 sprintf(
405 'Cache flush+ [user] [%s] %s',
406 current_action() ?? 'no action',
407 json_encode( self::$flush_groups )
408 )
409 );
410 }
411 }
412 }
413
414 /**
415 * Schedule term groups to flush.
416 *
417 * @param mixed ...$args
418 */
419 public static function term( ...$args ) {
420
421 $apply = false;
422
423 $action = current_action();
424 if ( $action !== false ) {
425 switch ( $action ) {
426 case 'delete_term':
427 $apply = self::apply_taxonomy( $args[2] ?? '' );
428 break;
429 case 'saved_term':
430 $apply = self::apply_taxonomy( $args[2] ?? '' );
431 break;
432 case 'set_object_terms':
433 if ( self::apply_taxonomy( $args[3] ?? '' ) ) {
434 $post_id = $args[0] ?? null;
435 if ( $post_id !== null ) {
436 $post_status = get_post_status( $post_id );
437 if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE || wp_is_post_revision( $post_id ) || wp_is_post_autosave( $post_id ) || $post_status === 'auto-draft' ) {
438 } else {
439 $apply = true;
440 }
441 }
442 }
443 break;
444 case 'deleted_term_relationships':
445 $apply = self::apply_taxonomy( $args[2] ?? '' );
446 break;
447 }
448 }
449
450 /**
451 * Add term groups to flush?
452 *
453 * @param boolean $apply
454 * @param string $action
455 * @param array|Traversable $args
456 *
457 * @return boolean
458 */
459 $apply = apply_filters( 'groups_cache_robot_flush_term', $apply, current_action(), $args );
460 if ( $apply ) {
461 self::$flush_groups = self::join( self::$flush_groups, self::get_term_groups() );
462 if ( self::$debug ) {
463 Groups_Log::log(
464 sprintf(
465 'Cache flush+ [term] [%s] %s',
466 current_action() ?? 'no action',
467 json_encode( self::$flush_groups )
468 )
469 );
470 }
471 }
472 }
473
474 /**
475 * Apply to taxonomy.
476 *
477 * @param string $taxonomy
478 *
479 * @return boolean
480 */
481 private static function apply_taxonomy( $taxonomy ) {
482 $apply = false;
483 $taxonomy = get_taxonomy( $taxonomy ?? '' ); // @phpstan-ignore nullCoalesce.variable
484 if ( $taxonomy instanceof WP_Taxonomy ) {
485 $post_types = $taxonomy->object_type ?? array();
486 foreach ( $post_types as $post_type ) {
487 if ( Groups_Post_Access::handles_post_type( $post_type ) ) {
488 $apply = true;
489 break;
490 }
491 }
492 }
493 return $apply;
494 }
495
496 /**
497 * Schedule all groups to flush.
498 */
499 public static function all( ...$args ) {
500 /**
501 * Add all groups to flush?
502 *
503 * @param boolean $apply
504 * @param string $action
505 * @param array|Traversable $args
506 *
507 * @return boolean
508 */
509 $apply = apply_filters( 'groups_cache_robot_flush_all', true, current_action(), $args );
510 if ( $apply ) {
511 self::$flush_groups = self::join( self::$flush_groups, self::get_comment_groups() );
512 self::$flush_groups = self::join( self::$flush_groups, self::get_post_groups() );
513 self::$flush_groups = self::join( self::$flush_groups, self::get_user_groups() );
514 self::$flush_groups = self::join( self::$flush_groups, self::get_term_groups() );
515
516 $post_types = Groups_Post_Access::get_handles_post_types();
517 foreach ( $post_types as $post_type => $handles ) {
518 if ( $handles ) {
519 self::$flush_groups[] = Groups_Post_Access::get_post_type_cache_group( $post_type );
520 if ( self::$debug ) {
521 Groups_Log::log(
522 sprintf(
523 'Cache flush+ [all] [%s] %s',
524 current_action() ?? 'no action',
525 json_encode( self::$flush_groups )
526 )
527 );
528 }
529 }
530 }
531 }
532 }
533
534 /**
535 * Flush scheduled groups on shutdown.
536 */
537 public static function shutdown() {
538 self::flush();
539 }
540
541 /**
542 * Flush scheduled groups immediately.
543 *
544 * @since 4.3.0
545 */
546 public static function flush() {
547 /**
548 * Filter groups to flush.
549 *
550 * @param string[] $groups
551 *
552 * @return string[]
553 */
554 self::$flush_groups = apply_filters( 'groups_cache_robot_flush_groups', self::$flush_groups );
555 if ( is_array( self::$flush_groups ) && count( self::$flush_groups ) > 0 ) {
556 if (
557 function_exists( 'wp_cache_supports' ) &&
558 wp_cache_supports( 'flush_group' )
559 ) {
560 foreach( self::$flush_groups as $group ) {
561 if ( is_string( $group ) ) {
562 $flushed = wp_cache_flush_group( $group );
563 if ( self::$debug ) {
564 Groups_Log::log(
565 sprintf(
566 'Cache flush [%4s] [%s]',
567 $flushed ? 'ok' : 'fail',
568 json_encode( $group )
569 )
570 );
571 }
572 }
573 }
574 } else {
575 if ( function_exists( 'wp_cache_flush' ) ) {
576 $flushed = wp_cache_flush();
577 if ( self::$debug ) {
578 Groups_Log::log(
579 sprintf(
580 'Cache flush [%4s]',
581 $flushed ? 'ok' : 'fail'
582 )
583 );
584 }
585 }
586 }
587 self::$flush_groups = array();
588 }
589 }
590 }
591
592 Groups_Cache_Robot::init();
593