PluginProbe
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance / 4.5.5
WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance v4.5.5
4.7.0 4.6.1 4.6.0 4.5.5 4.5.4 4.5.3 4.5.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.5 3.2.6 3.2.7 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.7.0 3.7.1 All 111 releases
wp-optimize / cache / class-wpo-cache-rules.php

class-wpo-cache-rules.php in WP-Optimize – Cache, Compress images, Minify & Clean database to boost page speed & performance 4.5.5, at cache/class-wpo-cache-rules.php

465 lines 17.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if (!defined('ABSPATH')) die('No direct access allowed');
4
5 /**
6 * Page caching rules and exceptions
7 */
8
9 require_once dirname(__FILE__) . '/file-based-page-cache-functions.php';
10
11 if (!class_exists('WPO_Cache_Rules')) :
12
13 class WPO_Cache_Rules {
14
15 /**
16 * Cache config object
17 *
18 * @var mixed
19 */
20 public $config;
21
22 /**
23 * Instance of this class
24 *
25 * @var WPO_Cache_Rules | null
26 */
27 public static $instance;
28
29 public function __construct() {
30 $this->config = WPO_Cache_Config::instance()->get();
31 $this->setup_hooks();
32 }
33
34 /**
35 * Setup hooks/filters
36 */
37 public function setup_hooks() {
38 add_action('save_post', array($this, 'purge_post_on_update'), 10, 1);
39 add_action('save_post', array($this, 'purge_archive_pages_on_post_update'), 10, 1);
40 add_action('wp_trash_post', array($this, 'purge_post_on_update'), 10, 1);
41 add_action('comment_post', array($this, 'purge_post_on_comment'), 10, 3);
42 add_action('wp_set_comment_status', array($this, 'purge_post_on_comment_status_change'), 10, 1);
43 add_action('edit_terms', array($this, 'purge_related_elements_on_term_updated'), 10, 2);
44 add_action('set_object_terms', array($this, 'purge_related_elements_on_post_terms_change'), 10, 6);
45 add_action('wpo_cache_config_updated', array($this, 'cache_config_updated'), 10, 1);
46 add_action('wp_insert_comment', array($this, 'comment_inserted'), 10, 2);
47 add_action('import_start', array($this, 'remove_wp_insert_comment'));
48
49 add_action('update_option_page_on_front', array($this, 'purge_cache_on_homepage_change'));
50 add_action('update_option_page_for_posts', array($this, 'purge_cache_on_blog_page_change'), 10, 2);
51 add_action('update_option_show_avatars', array($this, 'purge_cache_on_avatars_change'), 10, 2);
52
53 add_action('woocommerce_variation_set_stock', array($this, 'purge_product_page'), 10, 1);
54 add_action('woocommerce_product_set_stock', array($this, 'purge_product_page'), 10, 1);
55
56 /**
57 * List of hooks for which when executed, the cache will be purged
58 *
59 * @param array $actions The actions
60 */
61 $actions = array(
62 'after_switch_theme',
63 'wp_update_nav_menu',
64 'customize_save_after',
65 array('wp_ajax_save-widget', 0),
66 array('wp_ajax_update-widget', 0),
67 'autoptimize_action_cachepurged',
68 'upgrader_overwrote_package',
69 'wpo_active_plugin_or_theme_updated',
70 'fusion_cache_reset_after',
71 'update_option_permalink_structure',
72 'update_option_posts_per_page',
73 'wpml_st_add_string_translation',
74 );
75 $purge_on_action = apply_filters('wpo_purge_cache_hooks', $actions);
76 foreach ($purge_on_action as $action) {
77 if (is_array($action)) {
78 add_action($action[0], array($this, 'purge_cache'), $action[1]);
79 } else {
80 add_action($action, array($this, 'purge_cache'));
81 }
82 }
83 }
84
85 /**
86 * Purge post cache when there is a new approved comment
87 *
88 * @param int $comment_id Comment ID.
89 * @param int|string $approved Comment approved status. can be 0, 1 or 'spam'.
90 * @param array $commentdata Comment data array. Always sent be WP core, but a plugin was found that does not send it - https://wordpress.org/support/topic/critical-problems-with-version-3-0-10/
91 */
92 public function purge_post_on_comment($comment_id, $approved, $commentdata = array()) {
93 if (1 !== $approved) {
94 return;
95 }
96
97 if (!empty($this->config['enable_page_caching']) && !empty($commentdata['comment_post_ID'])) {
98 $post_id = $commentdata['comment_post_ID'];
99
100 WPO_Page_Cache::delete_single_post_cache($post_id);
101 WPO_Page_Cache::delete_comments_feed();
102 WPO_Page_Cache::instance()->file_log("Cache for URL: {{URL}} has been purged, triggered by action: " . current_filter(), $post_id);
103 }
104 }
105
106 /**
107 * Every time a comment's status changes, purge its parent posts cache
108 *
109 * @param int $comment_id Comment ID.
110 */
111 public function purge_post_on_comment_status_change($comment_id) {
112 if (!empty($this->config['enable_page_caching'])) {
113 $comment = get_comment($comment_id);
114 if (is_object($comment) && !empty($comment->comment_post_ID)) {
115 WPO_Page_Cache::delete_single_post_cache($comment->comment_post_ID);
116 WPO_Page_Cache::delete_comments_feed();
117 WPO_Page_Cache::instance()->file_log("Cache for URL: {{URL}} has been purged, triggered by action: " . current_filter(), $comment->comment_post_ID);
118 }
119 }
120 }
121
122 /**
123 * Action when a comment is inserted
124 *
125 * @param integer $comment_id - The comment ID
126 * @param boolean|WP_Comment $comment - The comment object (from WP 4.4)
127 * @return void
128 */
129 public function comment_inserted($comment_id, $comment = false) {
130 if ($comment && is_a($comment, 'WP_Comment')) {
131 /**
132 * Filters whether to add a cookie when a comment is posted, in order to exclude the page from caching.
133 * Regular comments have the property comment_type set to '' or 'comment'. So by default, only add the cookie in those cases.
134 *
135 * @param boolean $add_cookie
136 * @param WP_Comment $comment
137 * @return boolean
138 */
139 $add_cookie = apply_filters('wpo_add_commented_post_cookie', '' === $comment->comment_type || 'comment' === $comment->comment_type, $comment);
140 if (!$add_cookie) return;
141
142 $url = get_permalink($comment->comment_post_ID);
143 $url_info = wp_parse_url($url);
144 setcookie('wpo_commented_post', 1, time() + WEEK_IN_SECONDS, $url_info['path'] ?? '/');
145 }
146 }
147
148 /**
149 * Comment posted cookie is not needed for imports. So remove the action
150 */
151 public function remove_wp_insert_comment() {
152 remove_action('wp_insert_comment', array($this, 'comment_inserted'), 10);
153 }
154
155 /**
156 * Automatically purge all file based page cache on post changes
157 * We want the whole cache purged here as different parts
158 * of the site could potentially change on post updates
159 *
160 * @param int $post_id - WP post id
161 */
162 public function purge_post_on_update($post_id) {
163 $post_type = get_post_type($post_id);
164 $post_type_object = get_post_type_object($post_type);
165
166 if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || 'revision' === $post_type || null === $post_type_object || !$post_type_object->public) {
167 return;
168 }
169 $post_status = get_post_status($post_id);
170 if ('publish' !== $post_status) {
171 return;
172 }
173
174 /**
175 * Purge the whole cache if set to true, only the edited post otherwise. Default is false.
176 *
177 * @param boolean $purge_all_cache The default filter value
178 * @param integer $post_id The saved post ID
179 */
180 if (apply_filters('wpo_purge_all_cache_on_update', false, $post_id)) {
181 $this->purge_cache();
182 } else {
183 if (apply_filters('wpo_delete_cached_homepage_on_post_update', true, $post_id)) WPO_Page_Cache::delete_homepage_cache();
184 WPO_Page_Cache::delete_feed_cache();
185 WPO_Page_Cache::delete_single_post_cache($post_id);
186 WPO_Page_Cache::delete_post_feed_cache($post_id);
187 WPO_Page_Cache::instance()->file_log("Cache for URL: {{URL}} has been purged, triggered by action: " . current_filter(), $post_id);
188 }
189 }
190
191 /**
192 * Purge archive pages on post update.
193 *
194 * @param integer $post_id
195 */
196 public function purge_archive_pages_on_post_update($post_id) {
197 $post_type = get_post_type($post_id);
198
199 if (false === $post_type) return;
200
201 if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || 'revision' === $post_type) {
202 return;
203 }
204
205 $post_obj = get_post_type_object($post_type);
206
207 if (null === $post_obj) return;
208
209 $post_status = get_post_status($post_id);
210 if ('publish' !== $post_status) {
211 return;
212 }
213
214 if ('post' === $post_type) {
215 // delete blog page cache
216 $blog_post_id = get_option('page_for_posts');
217 if ($blog_post_id) {
218 WPO_Page_Cache::delete_cache_by_url(get_permalink($blog_post_id), true);
219 WPO_Page_Cache::instance()->file_log("Cache for blog post has been purged due to updates to post with Title: {{title}} and URL: {{URL}}, triggered by action: " . current_filter(), $post_id);
220 }
221
222 // delete next and previous posts cache.
223 $globals_post = $GLOBALS['post'] ?? false;
224 $GLOBALS['post'] = get_post($post_id);
225 $previous_post = function_exists('get_previous_post') ? get_previous_post() : false;
226 $next_post = function_exists('get_next_post') ? get_next_post() : false;
227 if ($globals_post) $GLOBALS['post'] = $globals_post;
228
229 if ($previous_post) {
230 WPO_Page_Cache::delete_cache_by_url(get_permalink($previous_post), true);
231 WPO_Page_Cache::instance()->file_log("Cache for previous post (with URL: {{URL}}) adjacent to post with id: " . $post_id . " has been purged, triggered by action: " . current_filter(), $previous_post->ID);
232 }
233 if ($next_post) {
234 WPO_Page_Cache::delete_cache_by_url(get_permalink($next_post), true);
235 WPO_Page_Cache::instance()->file_log("Cache for next post (with URL: {{URL}}) adjacent to post with id: " . $post_id . " has been purged, triggered by action: " . current_filter(), $next_post->ID);
236 }
237
238 // delete all archive pages for post.
239 $post_date = get_post_time('Y-m-j', false, $post_id);
240 list($year, $month, $day) = $post_date;
241
242 $archive_links = array(
243 get_year_link($year),
244 get_month_link($year, $month),
245 get_day_link($year, $month, $day),
246 );
247
248 foreach ($archive_links as $link) {
249 WPO_Page_Cache::delete_cache_by_url($link, true);
250 }
251 WPO_Page_Cache::instance()->file_log("Cache for all archives page associated with post_type: " . $post_type . " and Title: {{title}} have been purged, triggered by action: " . current_filter(), $post_id);
252 }
253 if ($post_obj->has_archive) {
254 // delete archive page for custom post type.
255 WPO_Page_Cache::delete_cache_by_url(get_post_type_archive_link($post_type), true);
256 WPO_Page_Cache::instance()->file_log("Cache for archive page associated with post_type: " . $post_type . " and Title: {{title}} has been purged, triggered by action: " . current_filter(), $post_id);
257 }
258 if (post_type_supports($post_type, 'author')) {
259 $author_id = get_post_field('post_author', $post_id);
260 $post_author = get_user_by('id', $author_id);
261 if ($author_id && $post_author) {
262 $author_url = get_author_posts_url($author_id);
263 if (!empty($author_url)) {
264 WPO_Page_Cache::delete_cache_by_url($author_url, true);
265 WPO_Page_Cache::instance()->file_log("Cache for author page URL: " . $author_url . " associated with post_type: " . $post_type . " and Title: {{title}} has been purged, triggered by action: " . current_filter(), $post_id);
266 }
267 }
268 }
269 }
270
271 /**
272 * We use it with edit_terms action filter to purge cached elements related
273 * to updated term when term updated.
274 *
275 * @param int $term_id Term taxonomy ID.
276 * @param string $taxonomy Taxonomy slug.
277 */
278 public function purge_related_elements_on_term_updated($term_id, $taxonomy) {
279 if ('nav_menu' === $taxonomy) return;
280
281 // purge cached page for term.
282 $term = get_term($term_id, $taxonomy, ARRAY_A);
283 if (is_array($term)) {
284 $term_permalink = get_term_link($term['term_id']);
285 if (!is_wp_error($term_permalink)) {
286 WPO_Page_Cache::delete_cache_by_url($term_permalink, true);
287 WPO_Page_Cache::instance()->file_log("Cache for term page with URL: " . $term_permalink . " have been purged, triggered by action: " . current_filter());
288 }
289 }
290
291 // get posts which belongs to updated term.
292 $posts = get_posts(array(
293 'numberposts' => -1,
294 'post_type' => 'any',
295 'fields' => 'ids',
296 'tax_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query -- because we can't use `get_objects_in_term` for `OR` relationships
297 'relation' => 'OR',
298 array(
299 'taxonomy' => $taxonomy,
300 'field' => 'term_id',
301 'terms' => $term_id,
302 )
303 ),
304 ));
305
306 if (!empty($posts)) {
307 foreach ($posts as $post_id) {
308 WPO_Page_Cache::delete_single_post_cache($post_id);
309 }
310 $term_permalink = get_term_link($term_id);
311 WPO_Page_Cache::instance()->file_log("Cache for associated posts for term with URL: "
312 . $term_permalink. " have been purged, triggered by action: " . current_filter());
313 }
314 }
315
316 /**
317 * Triggered by set_object_terms action. Used to clear all the terms archives a post belongs to or belonged to before being saved.
318 *
319 * @param int $object_id Object ID.
320 * @param array $terms An array of object terms.
321 * @param array $tt_ids An array of term taxonomy IDs.
322 * @param string $taxonomy Taxonomy slug.
323 * @param bool $append Whether to append new terms to the old terms.
324 * @param array $old_tt_ids Old array of term taxonomy IDs.
325 */
326 public function purge_related_elements_on_post_terms_change($object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids) {
327
328 $post_type = get_post_type($object_id);
329
330 if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || 'revision' === $post_type || 'product_type' === $taxonomy || 'action-group' === $taxonomy) {
331 return;
332 }
333
334 /**
335 * Adds a way to exit the purge of terms permalink using the provided parameters.
336 *
337 * @param bool $purge The value filtered, whether to purge the related elements or not
338 * @param int $object_id Object ID.
339 * @param array $terms An array of object terms.
340 * @param array $tt_ids An array of term taxonomy IDs.
341 * @param string $taxonomy Taxonomy slug.
342 * @param bool $append Whether to append new terms to the old terms.
343 * @param array $old_tt_ids Old array of term taxonomy IDs.
344 * @default true
345 * @return boolean
346 */
347 if (!apply_filters('wpo_cache_purge_related_elements_on_post_terms_change', true, $object_id, $terms, $tt_ids, $taxonomy, $append, $old_tt_ids)) return;
348
349 // get all affected terms.
350 $affected_terms_ids = array_unique(array_merge($tt_ids, $old_tt_ids));
351
352 if (!empty($affected_terms_ids)) {
353 // walk through all changed terms and purge cached pages for them.
354 $is_cache_purged = false;
355 foreach ($affected_terms_ids as $tt_id) {
356 $term = get_term($tt_id, $taxonomy, ARRAY_A);
357 if (!is_array($term)) continue;
358
359 $term_permalink = get_term_link($term['term_id']);
360 if (!is_wp_error($term_permalink)) {
361 $url = wp_parse_url($term_permalink);
362 // Check if the permalink contains a valid path, to avoid deleting the whole cache.
363 if (!isset($url['path']) || '/' === $url['path']) return;
364 WPO_Page_Cache::delete_cache_by_url($term_permalink, true);
365 $is_cache_purged = true;
366 }
367 }
368 if ($is_cache_purged) WPO_Page_Cache::instance()->file_log("Cache for multiple term taxonomy have been purged due to post terms update, triggered by action: " . current_filter());
369 }
370 }
371
372 /**
373 * Purge product page upon stock update
374 */
375 public function purge_product_page($product_with_stock) {
376 if (!empty($product_with_stock->get_id())) {
377 WPO_Page_Cache::delete_single_post_cache($product_with_stock->get_id());
378 WPO_Page_Cache::instance()->file_log("Cache for URL: {{URL}} has been purged, triggered by action: " . current_filter(), $product_with_stock->get_id());
379 }
380 }
381
382 /**
383 * Purges relevant caches when the "Homepage" option is changed.
384 *
385 * This method is also triggered when the "Homepage displays" option is changed
386 * from a static page to latest posts. In this scenario, the "Homepage" option value
387 * becomes zero. Since the cache for the front-page is already purged here, there's no need
388 * to purge the cache using the`update_option_show_on_front` hook.
389 *
390 * @param string $old_value The old value of the "Homepage" option.
391 */
392 public function purge_cache_on_homepage_change($old_value) {
393 if ($old_value) {
394 WPO_Page_Cache::delete_cache_by_url(get_permalink($old_value));
395 }
396 WPO_Page_Cache::delete_homepage_cache();
397 WPO_Page_Cache::instance()->file_log("Cache for homepage has been purged due to change in the Homepage displays options, triggered by action: " . current_filter());
398 }
399
400 /**
401 * Purges relevant caches when the "Posts page" option is changed.
402 *
403 * @param string $old_value The old value of the "Posts page" option.
404 * @param string $value The new value of the "Posts page" option.
405 */
406 public function purge_cache_on_blog_page_change($old_value, $value) {
407 if ($old_value) {
408 WPO_Page_Cache::delete_cache_by_url(get_permalink($old_value));
409 }
410 if ($value) {
411 WPO_Page_Cache::delete_cache_by_url(get_permalink($value));
412 }
413 WPO_Page_Cache::instance()->file_log("Cache for homepage has been purged due to changes in the Posts page options, triggered by action: " . current_filter());
414 }
415
416 /**
417 * Purges cache if the avatars option is changed
418 *
419 * @param boolean $old_value
420 * @param boolean $value
421 */
422 public function purge_cache_on_avatars_change($old_value, $value) {
423 if ($old_value !== $value) {
424 $this->purge_cache();
425 }
426 }
427
428 /**
429 * Clears the cache.
430 */
431 public function purge_cache() {
432 if (!empty($this->config['enable_page_caching'])) {
433 wpo_cache_flush();
434 WPO_Page_Cache::instance()->file_log("Full Cache Purge triggered by action: " . current_filter());
435 }
436 }
437
438 /**
439 * Triggered by wpo_cache_config_updated.
440 *
441 * @param array $config
442 */
443 public function cache_config_updated($config) {
444 // delete front page form cache if defined in the settings
445 if (is_array($config['cache_exception_urls']) && in_array('/', $config['cache_exception_urls'])) {
446 WPO_Page_Cache::delete_cache_by_url(home_url());
447 WPO_Page_Cache::instance()->file_log("Cache for homepage has been purged due to changes in the cache configurations, triggered by action: " . current_filter());
448 }
449 }
450
451 /**
452 * Returns an instance of the current class, creates one if it doesn't exist
453 *
454 * @return self
455 */
456 public static function instance() {
457 if (empty(self::$instance)) {
458 self::$instance = new self();
459 }
460 return self::$instance;
461 }
462 }
463
464 endif;
465