PluginProbe
Themify Builder / trunk
Themify Builder vtrunk
7.8.1 7.8.0 7.7.9 7.7.8 7.7.7 7.7.6 7.7.5 7.7.4 7.7.3 7.7.2 trunk 7.6.0 7.6.1 7.6.2 7.6.3 7.6.4 7.6.5 7.6.6 7.6.7 7.6.8 7.6.9 7.7.0 7.7.1
themify-builder / themify / cache / class-themify-cache.php

class-themify-cache.php in Themify Builder trunk, at themify/cache/class-themify-cache.php

1,043 lines 47.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 defined('ABSPATH') || exit;
4 if (!class_exists('TFCache',false)) {
5 if (!class_exists('Themify_Filesystem',false) && defined('TF_CACHE_FW')) {
6 require_once dirname(TF_CACHE_FW) . '/class-themify-filesystem.php';
7 }
8
9 /**
10 * Class to work with post cache
11 *
12 * @package default
13 */
14 class TFCache {
15
16 const SEP = DIRECTORY_SEPARATOR;
17
18 private static $cache_dir = null;
19 public static $stopCache = false;
20 private static $error = false;
21
22 /**
23 * Start Caching
24 *
25 * @param string $tag
26 * @param integer $post_id
27 * @param array $args
28 * @param integer $time
29 *
30 * return boolean
31 */
32 public static function start_cache($tag, $post_id = false, array $args = array(), $time = false) {//backward compatibility for addons
33 return true;
34 }
35
36 public static function end_cache() {//backward compatibility for addons
37 }
38
39 /**
40 * remove cache after some updates
41 */
42 public static function remove_cache($item_id = 'blog', $type = false, $blog_id = false) {
43 static $queue = array();
44 if (isset($queue['all'])) {
45 return true;
46 }
47 if ($item_id === 'all') {
48 $queue['all'] = true;
49 $dir = self::get_cache_main_dir();
50 if (!Themify_Filesystem::is_dir($dir)) {
51 return true;
52 }
53 return Themify_Filesystem::delete($dir);
54 }
55 $cache_dir = self::get_cache_blog_dir($blog_id);
56 if (!isset($queue['blog']) && Themify_Filesystem::is_dir($cache_dir)) {
57 if ($item_id === 'blog') {
58 $queue['blog'] = true;
59 return Themify_Filesystem::delete($cache_dir);
60 } else {
61 if ($type === false) {
62 $the_post = wp_is_post_revision($item_id);
63 if ($the_post) {
64 $item_id = $the_post;
65 }
66 $post = get_post($item_id);
67 if (empty($post)) {
68 return true;
69 }
70 $type = $post->post_type;
71 $post = null;
72 }
73 if (empty($type)) {
74 return self::remove_cache();
75 }
76 $k = $type . $item_id;
77 if (!isset($queue[$k])) {
78 $queue[$k] = true;
79 $find = array(' post-' . $item_id);
80 $item_id = (int) $item_id;
81 $find[] = get_post_type($item_id) === 'page' ? ' page-id-' . $item_id : ' postid-' . $item_id; //if there is any html associated with updated post
82 if ($type === 'comment' || $type === 'term' || $type === 'category') {
83 $find[] = $type . '-' . $item_id;
84 if ($type !== 'comment') {
85 $find[] = $type === 'category' ? get_category_link($item_id) : get_term_link($item_id);
86 $temp = get_term($item_id);
87 $find[] = 'term-' . $temp->slug;
88 $temp = null;
89 }
90 }
91 @set_time_limit(0);
92 $type = $item_id = null;
93 if (!self::clear_recursive($cache_dir, $find)) {
94 return self::remove_cache();
95 }
96 }
97 }
98 }
99 return true;
100 }
101
102 private static function clear_recursive($cache_dir, array $find) {
103 $dirHandle = opendir($cache_dir);
104 if (empty($dirHandle)) {
105 return false;
106 }
107 while ($f = readdir($dirHandle)) {
108 if ($f !== '.' && $f !== '..') {
109 $item = rtrim($cache_dir, self::SEP) . self::SEP . $f;
110 if (Themify_Filesystem::is_dir($item)) {
111 self::clear_recursive($item, $find);
112 } elseif (strpos($item, '.html', 5) !== false && strpos($item, '.html.gz', 5) === false && Themify_Filesystem::is_file($item)) {
113 $content = file_get_contents($item, FALSE, NULL, 2000);
114 if (!empty($content)) {
115 foreach ($find as $v) {
116 if (strpos($content, $v, 10) !== false) {
117 Themify_Filesystem::delete($item, 'f');
118 Themify_Filesystem::delete($item . '.gz', 'f');
119 break;
120 }
121 }
122 }
123 $content = null;
124 }
125 }
126 }
127 closedir($dirHandle);
128 $dirHandle = null;
129 return true;
130 }
131
132 /**
133 * init hooks to update cache
134 */
135 public static function hooks() {
136 add_action('save_post', array(__CLASS__, 'save'), 100, 3);
137 add_action('deleted_post', array(__CLASS__, 'save'), 100, 1);
138 add_action('comment_post', array(__CLASS__, 'comment_update'), 100, 2);
139 add_action('deleted_comment', array(__CLASS__, 'comment_update'), 100, 2);
140 add_action('wp_update_nav_menu', array(__CLASS__, 'menu_update'), 100);
141 add_action('wp_update_nav_menu_item', array(__CLASS__, 'menu_update'), 100);
142 add_action('activated_plugin', array(__CLASS__, 'plugin_active_deactive'), 100, 2);
143 add_action('deactivated_plugin', array(__CLASS__, 'plugin_active_deactive'), 100, 2);
144 add_action('admin_footer', array(__CLASS__, 'admin_check'));
145 add_action('wp_ajax_themify_write_config', array(__CLASS__, 'ajax_write_wp_cache'));
146 add_action('customize_save_after', array(__CLASS__, 'customizer'));
147 add_action('switch_theme', array(__CLASS__, 'disable_cache'), 5);
148
149 add_action('edit_term', array(__CLASS__, 'edit_term'), 100, 3);
150 add_action('delete_term_taxonomy', array(__CLASS__, 'edit_term'), 100, 1);
151
152 add_action('check_ajax_referer', array(__CLASS__, 'widget_update'), 100, 2); //for widgets order,there is no hook
153
154
155 $metas = array('post', 'comment', 'term', 'user');
156 foreach ($metas as $m) {
157 if ($m !== 'term' && $m !== 'user') {
158 add_action('added_' . $m . '_meta', array(__CLASS__, 'meta_update'), 100, 4);
159 }
160 add_action('updated_' . $m . '_meta', array(__CLASS__, 'meta_update'), 100, 4);
161 add_action('deleted_' . $m . '_meta', array(__CLASS__, 'meta_update'), 100, 4);
162 }
163 if (is_user_logged_in()) {
164 add_action('admin_bar_menu', array(__CLASS__, 'cache_menu'), 100);
165 if (isset($_GET['tf-cache']) && ($_GET['tf-cache'] === '2' || $_GET['tf-cache'] === '4')) {
166 add_action('init', array(__CLASS__, 'check_clear'), 1);
167 }
168 }
169 add_action('upgrader_process_complete', array(__CLASS__, 'themify_updated'), 10, 2);
170 }
171
172 /**
173 * comment update
174 */
175 public static function comment_update($comment_ID, $comment_approved) {
176 $comment = get_comment($comment_ID);
177 if (!empty($comment)) {
178 self::remove_cache($comment->comment_post_ID, 'comment');
179 }
180 }
181
182 /**
183 * plugin activatiion/deactivation
184 */
185 public static function plugin_active_deactive($plugin, $network_wide) {
186 $type = $network_wide ? 'all' : 'blog';
187 self::remove_cache($type);
188 }
189
190 /**
191 * menu update
192 */
193 public static function menu_update($_menu_id) {
194 themify_clear_menu_cache();
195 remove_action('wp_update_nav_menu', array(__CLASS__, 'menu_update'), 100);
196 remove_action('wp_update_nav_menu_item', array(__CLASS__, 'menu_update'), 100);
197 self::remove_cache();
198 }
199
200 public static function customizer($manager) {
201 if (!empty($manager)) {
202 $post_id = $manager->changeset_post_id();
203 if (!empty($post_id)) {
204 self::remove_cache($post_id);
205 }
206 }
207 }
208
209 public static function edit_term($term, $tt_id = null, $taxonomy = null) {
210 if (empty($taxonomy)) {
211 $temp = get_term($term);
212 $taxonomy = $temp->taxonomy;
213 $temp = null;
214 }
215 $type = $taxonomy === 'category' ? 'category' : 'term';
216 self::remove_cache($term, $type);
217 }
218
219 /**
220 * meta update
221 */
222 public static function meta_update($meta_id, $post_id, $meta_key, $meta_value) {
223 if (!empty($post_id)) {
224 $actions = explode('_', current_action());
225 self::remove_cache($post_id, $actions[1]);
226 }
227 }
228
229 public static function widget_update($action, $result) {
230 if ($result !== false && $action === 'save-sidebar-widgets') {
231 self::remove_cache();
232 }
233 }
234
235 public static function save($post_id, $post = false, $update = true) {
236 if ($update || current_action() === 'deleted_post') {
237 self::remove_cache($post_id);
238 } elseif (!is_object($post) || $post->post_status !== 'auto-draft') {
239 self::remove_cache();
240 }
241 }
242
243 public static function get_current_url():string {
244 if (empty($_SERVER['REQUEST_URI']) || empty($_SERVER['HTTP_HOST'])) {
245 return '';
246 }
247 $protocol = is_ssl() ? 'https://' : 'http://';
248 return $protocol . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
249 }
250
251 /**
252 * will be called in advanced-cache.php before wp full core load,a lot of functions from wp api and FW functions are't available in in this function be carefull!
253 */
254 public static function run() {
255 if (self::$stopCache === true) {
256 return;
257 }
258 if (!function_exists('wp_get_nocache_headers')) {
259 add_action('init', array(__CLASS__, 'run'), 0);
260 return;
261 }
262 self::$cache_dir = self::get_cache_main_dir();
263 if (Themify_Filesystem::mkdir(self::$cache_dir)) {
264 $isMulti = is_multisite();
265 if ($isMulti !== false) {
266 self::$cache_dir = self::get_cache_blog_dir();
267 }
268 if ($isMulti === false || Themify_Filesystem::mkdir(self::$cache_dir, true)) {
269 if (defined('TF_CACHE_RULES') && TF_CACHE_RULES) {
270 $ignore = explode('|TF|', TF_CACHE_RULES);
271 if (!empty($ignore) && !empty($_SERVER['HTTP_HOST'])) {
272 $request = $_SERVER['REQUEST_URI'];
273 $server = is_ssl() ? 'https://' : 'http://';
274 $server .= $_SERVER['HTTP_HOST'];
275 $del = '~';
276 foreach ($ignore as $r) {
277 $r = str_replace($server, '', $r);
278 $p = $del . $r . $del;
279 if (preg_match($p, $request)) {
280 self::$cache_dir = null;
281 return;
282 }
283 }
284 $request = $server = $ignore = null;
285 }
286 }
287 $dir = null;
288 self::$cache_dir = self::get_current_cache('', true).'.html';
289 if (Themify_Filesystem::is_file(self::$cache_dir)) {
290 $ftime = filemtime(self::$cache_dir);
291 $expire = defined('TF_CACHE_TIME') && TF_CACHE_TIME ? (TF_CACHE_TIME * 60) : WEEK_IN_SECONDS;
292 $liveTime = $expire + $ftime;
293 if ($liveTime > time()) {
294 global $wp;
295 $headers = apply_filters('wp_headers', wp_get_nocache_headers(), $wp);
296
297 if (!isset($headers['Cache-Control'])) {
298 $headers['Content-Type'] = 'no-cache, must-revalidate, max-age=0';
299 }
300 if (!isset($headers['Content-Type'])) {
301 $headers['Content-Type'] = 'text/html;charset=UTF-8';
302 }
303 // header('Content-Length: '.filesize(self::$cache_dir));//temprorary disable,because when cd of cloudfare is enabled it will return compress brottil size
304 $headers['Last-Modified'] = gmdate('D, d M Y H:i:s', $ftime) . ' GMT';
305 $headers['Expires'] = gmdate('D, d M Y H:i:s', $liveTime) . 'GMT';
306 if (Themify_Filesystem::is_file(self::$cache_dir)) {//maybe another proccess has already removed it?
307 $type = false; //self::get_available_gzip();temprorary disable gzip caching,because bug of cloudfare
308 if ($type !== false && Themify_Filesystem::is_file(self::$cache_dir . '.gz')) {
309 $type = key($type);
310 if (isset($_SERVER['HTTP_ACCEPT_ENCODING']) && strpos($_SERVER['HTTP_ACCEPT_ENCODING'], $type) !== false) {
311 self::$cache_dir .= '.gz';
312 $headers['Content-Encoding'] = $type;
313 }
314 }
315 foreach ($headers as $name => $field_value) {
316 header("{$name}: {$field_value}");
317 }
318 do_action_ref_array('send_headers', array(&$wp));
319 readfile(self::$cache_dir);
320 die;
321 }
322 } else {
323 Themify_Filesystem::delete(self::$cache_dir, 'f');
324 Themify_Filesystem::delete(self::$cache_dir . '.gz', 'f');
325 }
326 }
327 add_action('template_redirect', array(__CLASS__, 'template_include'), -9999999);
328 } else {
329 self::$cache_dir = null;
330 }
331 } else {
332 self::$cache_dir = null;
333 }
334 }
335
336 public static function get_current_cache(string $request = '',bool $create_dir = false):string {
337 if ($request === '') {
338 $request = self::get_current_url();
339 }
340 return self::get_cache_folder($request, $create_dir) . md5($request);
341 }
342
343 /**
344 * Initiate cache, just before page renders on frontend
345 *
346 * Hooked to "template_redirect"[0]
347 */
348 public static function template_include() {
349 if (!themify_is_dev_mode()) {
350 self::cache_start();
351 }
352 }
353
354 private static function cache_start() {
355 global $post;
356 if (self::$stopCache === true || (isset($post, $post->post_password) && $post->post_password !== '') || is_user_logged_in() || is_admin() || self::$cache_dir === null || is_404() || is_search() || themify_is_ajax() || post_password_required() || is_trackback() || is_robots() || is_preview() || is_customize_preview() || themify_is_login_page() || (themify_is_woocommerce_active() && (is_checkout() || is_cart() || is_account_page()))) {
357 return;
358 }
359 if (defined('TF_CACHE_IGNORE') && TF_CACHE_IGNORE) {
360 $ignore = explode(',', trim(TF_CACHE_IGNORE));
361 if (!empty($ignore)) {
362 foreach ($ignore as $f) {
363 if (($f === 'is_shop' && themify_is_shop()) || ($f !== 'is_shop' && is_callable($f) && call_user_func($f))) {
364 return;
365 }
366 }
367 }
368 $ignore = null;
369 }
370 if (false !== self::get_cache_plugins()) {
371 self::disable_cache();
372 return;
373 }
374 define('TF_CACHE', true);
375 self::$error = true;
376 ob_start(array(__CLASS__, 'getBuffer'));
377 add_action('wp_footer', array(__CLASS__, 'body_end'), 9999999);
378 }
379
380 public static function getBuffer(?string $html=''):string {
381 if (!$html) {
382 $html = ob_get_contents();
383 }
384 if (self::$error === false && !empty($html)) {
385 $html = preg_replace(array(
386 '/<!--(.|\S)*?-->/s',
387 '/\>[^\S ]{2,}/s', // remove whitespaces after tags
388 '/[^\S ]{2,}\</s', // remove whitespaces before tags
389 '/([\t ])+/s', //shorten multiple whitespace sequences; keep new-line characters because they matter in JS!!!
390 '/\>[\r\n\t ]{2,}\</s', //remove empty lines (between HTML tags); cannot remove just any line-end characters because in inline JS they can matter!
391 ), array('', '>', '<', ' ', '><'), $html);
392 if (self::$stopCache === false) {
393 $dir = rtrim(dirname(self::$cache_dir), self::SEP) . self::SEP;
394 if (Themify_Filesystem::mkdir($dir, true) && !is_file(self::$cache_dir)) {
395 //tmp file need because file_put_contents isn't atomic(another process can read not ready file),locking file(LOCK_EX) is slow and not work always,that is why we are using rename(it is atomic)
396 if (file_put_contents(self::$cache_dir . 'tmp', '<!--THEMIFY CACHE-->' . $html) && Themify_Filesystem::rename(self::$cache_dir . 'tmp', self::$cache_dir) !== false) {
397 if (false && themify_get_server() !== 'litespeed' && themify_check('setting-cache_gzip', true)) {
398 $func = self::get_available_gzip();
399 if ($func !== false) {
400 $func = current($func);
401 $html = call_user_func($func['f'], $html, $func['l']);
402 $func = null;
403 if (!empty($html)) {
404 file_put_contents(self::$cache_dir . '.gz', '<!--THEMIFY CACHE-->' . $html, LOCK_EX);
405 }
406 }
407 }
408 } else {
409 Themify_Filesystem::delete(self::$cache_dir . 'tmp', 'f');
410 }
411 }
412 }
413 }
414 return $html;
415 }
416
417 public static function body_end():void {
418 add_action('shutdown', array(__CLASS__, 'cache_end'), 0);
419 }
420
421 public static function cache_end():void {
422 self::$error = false;
423 ob_end_flush();
424 }
425
426 public static function get_available_gzip() {
427 if (function_exists('brotli_compress') && ((isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on') || (isset($_SERVER['SERVER_PORT']) && (int) $_SERVER['SERVER_PORT'] === 443))) {
428 return array('br' => array('f' => 'brotli_compress', 'l' => 10));
429 }
430 if (function_exists('gzdeflate')) {
431 return array('deflate' => array('f' => 'gzdeflate', 'l' => 8));
432 }
433 if (function_exists('gzcompress')) {
434 return array('deflate' => array('f' => 'gzcompress', 'l' => 8));
435 }
436 if (function_exists('gzencode')) {
437 return array('gzip' => array('f' => 'gzencode', 'l' => 8));
438 }
439 return false;
440 }
441
442 public static function create_config(array $data) {
443 $cache_dir = self::get_wp_content_dir();
444 if (Themify_Filesystem::is_writable($cache_dir)) {
445 if (!empty($data['setting-cache-html']) && false === self::get_cache_plugins()) {
446 $fw_dir = THEMIFY_DIR . self::SEP . 'cache' . self::SEP;
447 $fw_config = $fw_dir . 'config.php';
448 $cache_config = self::get_cache_config_file();
449 $msg = sprintf(__('Can`t copy %s to %s. Please check permission or do manually it.', 'themify'), $fw_config, $cache_config);
450 if (Themify_Filesystem::is_file($cache_config)) {
451 include_once $cache_config;
452 }
453 $rules = '';
454 if (!empty($data['setting-cache-rule'])) {
455 $rules = explode(PHP_EOL, $data['setting-cache-rule']);
456 foreach ($rules as $i => $r) {
457 $rules[$i] = trim(str_replace(array('"', "'"), '', $r));
458 if (empty($rules[$i])) {
459 unset($rules[$i]);
460 }
461 }
462 $rules = !empty($rules) ? implode('|TF|', $rules) : '';
463 }
464 $config = array(
465 '#TF_CACHE_FW#' => trailingslashit($fw_dir),
466 '#TF_CACHE_TIME#' => !empty($data['setting-cache-live']) ? ((int) $data['setting-cache-live']) : WEEK_IN_SECONDS,
467 '#TF_CACHE_RULES#' => $rules,
468 '#TF_CACHE_IGNORE#' => ''
469 );
470 $rules = null;
471 $ignores = array();
472 foreach ($data as $k => $v) {
473 if (strpos($k, 'setting-cache-ignore_') === 0 && !empty($v)) {
474 $ignores[] = $v;
475 }
476 }
477 if (!empty($ignores)) {
478 $config['#TF_CACHE_IGNORE#'] = implode(',', $ignores);
479 }
480 $ignores = $data = null;
481 $hasUpdate = (!defined('TF_CACHE_FW') || TF_CACHE_FW !== $config['#TF_CACHE_FW#']) || (!defined('TF_CACHE_RULES') || $config['#TF_CACHE_RULES#'] !== TF_CACHE_RULES) || (!defined('TF_CACHE_IGNORE') || $config['#TF_CACHE_IGNORE#'] !== TF_CACHE_IGNORE) || (!defined('TF_CACHE_TIME') || $config['#TF_CACHE_TIME#'] != TF_CACHE_TIME);
482 if ($hasUpdate === true) {
483 if (!copy($fw_config, $cache_config)) {
484 self::disable_cache();
485 return $msg;
486 }
487 $content = Themify_Filesystem::get_contents($cache_config);
488 if (empty($content)) {
489 self::disable_cache();
490 return $msg;
491 }
492 if (!file_put_contents($cache_config, str_replace(array_keys($config), $config, $content), LOCK_EX)) {
493 self::disable_cache();
494 return false;
495 }
496 $content = null;
497 }
498 $copy = true;
499 if (Themify_Filesystem::is_file($cache_dir . 'advanced-cache.php')) {
500 $content = Themify_Filesystem::get_contents($cache_dir . 'advanced-cache.php');
501 $copy = empty($content) || strpos($content, 'class-themify-cache.php', 10) === false;
502 if ($copy === false && md5($content) !== md5_file($fw_dir . 'advanced-cache.php')) {
503 $copy = true;
504 }
505 }
506 if ($copy === true && !copy($fw_dir . 'advanced-cache.php', $cache_dir . 'advanced-cache.php')) {
507 Themify_Filesystem::delete($cache_config, 'f');
508 self::disable_cache();
509 return sprintf(__('Can`t copy %s to %s. Please check permission or do manually it.', 'themify'), $fw_dir . 'advanced-cache.php', $cache_dir . 'advanced-cache.php');
510 }
511 return self::write_wp_config();
512 } else {
513 self::disable_cache();
514 return __('Themify Cache can not be enabled due to another cache plugin is activated.', 'themify');
515 }
516 } else {
517 self::disable_cache();
518 return sprintf(__('Folder %s isn`t writable.Please check permission to allow write cache.', 'themify'), $cache_dir);
519 }
520 }
521
522 public static function get_wp_content_dir():string {
523 return rtrim(WP_CONTENT_DIR, self::SEP) . self::SEP;
524 }
525
526 public static function get_cache_main_dir():string {
527 return self::get_wp_content_dir() . 'tf_cache' . self::SEP;
528 }
529
530 public static function get_cache_blog_dir($blog_id = false):string {
531 $dir = self::get_cache_main_dir();
532 if (is_multisite()) {
533 if ($blog_id === false) {
534 static $bid = null;
535 if ($bid === null) {
536 $bid = get_current_blog_id();
537 }
538 $dir .= $bid . self::SEP;
539 } else {
540 $dir .= $blog_id . self::SEP;
541 }
542 }
543 return $dir;
544 }
545
546 public static function get_cache_folder(string $request,bool $create = false):string {
547 $dir = explode('?', $request);
548 $dir = $dir[0];
549 if ($dir !== '/') {
550 $dir = trim($dir, '/');
551 //group the files in directory by the pre last slash(e.g /blog/slug return blog,2014/06/09/slug return 2014/06/09/)
552 if (is_multisite()) {
553 $domain = apply_filters('site_url', get_option('siteurl'), '', null, null);
554 } else {
555 $domain = parse_url($dir);
556 $domain = isset($domain['host']) ? $domain['host'] : '';
557 }
558 $scheme = is_ssl() ? 'https' : 'http';
559 $domain = str_replace(array('https:', 'http:'), '', trim($domain));
560 $domain = $scheme . '://' . trim(ltrim($domain, '//'));
561 $domain = trim(strtr($dir, array($domain => '')), '/');
562 if ($domain === '') {
563 $dir = '/';
564 } elseif (strpos($domain, '/') !== false) {
565 $domain = explode('/', $domain);
566 array_pop($domain);
567 $dir = implode('/', $domain);
568 } else {
569 $dir = $domain;
570 }
571 $domain = null;
572 }
573 $blog_dir = self::get_cache_blog_dir() . md5($dir);
574 if ($create === true) {
575 Themify_Filesystem::mkdir($blog_dir, true);
576 }
577 return $blog_dir . self::SEP;
578 }
579
580 public static function admin_check() {
581 if (false !== self::get_cache_plugins()) {
582 self::disable_cache();
583 }
584 }
585
586 public static function disable_cache() {
587 $cache_dir = self::get_wp_content_dir();
588 $config_f = self::get_cache_config_file();
589 Themify_Filesystem::delete($config_f, 'f');
590 if (!is_multisite()) {
591 $config_f = $cache_dir . 'advanced-cache.php';
592 if (Themify_Filesystem::is_file($config_f)) {
593 $content = Themify_Filesystem::get_contents($config_f);
594 $remove = !empty($content) && strpos($content, 'class-themify-cache.php', 10) !== false;
595 } else {
596 $remove = true;
597 }
598 if ($remove === true) {//only when advanced-cache.php belongs to us or file doesn't exist try to disable WP_CACHE
599 if (WP_CACHE) {
600 $wp_config = ABSPATH . 'wp-config.php';
601 if (Themify_Filesystem::is_writable($wp_config)) {
602 $content = Themify_Filesystem::get_contents($wp_config);
603 if (!empty($content)) {
604 $content = str_replace(array(self::get_replace_str(), "define('WP_CACHE',true);"), '', $content);
605 if (strpos($content, 'Themify Cache', 2) !== false) {//try again
606 $content = preg_replace('/define/', self::get_replace_str() . PHP_EOL . PHP_EOL . 'define', $content, 1);
607 }
608 if (!file_put_contents($wp_config, $content, LOCK_EX)) {
609 $remove = false;
610 }
611 }
612 } else {
613 $remove = false; //otherwise will give error file doesn't exist,it's safe to keep it
614 }
615 }
616 if ($remove === true) {
617 Themify_Filesystem::delete($config_f, 'f');
618 }
619 }
620 }
621 }
622
623 private static function get_replace_str():string {
624 $replace = '/* Themify Cache Start */' . PHP_EOL;
625 $replace .= "define('WP_CACHE',true);";
626 $replace .= PHP_EOL . '/* Themify Cache End */';
627 return $replace;
628 }
629
630 public static function ajax_write_wp_cache() {
631 check_ajax_referer('tf_nonce', 'nonce');
632 if ( ! current_user_can( 'manage_options' ) ) {
633 die;
634 }
635
636 if (!empty($_POST['data'])) {
637 $data = themify_normalize_save_data($_POST['data']);
638 $msg = self::create_config($data);
639 if ($msg === true) {
640 die(json_encode(array('remove_after' => 1)));
641 }
642 die(json_encode(array('error' => $msg)));
643 }
644 die;
645 }
646
647 public static function write_wp_config() {
648 $cache_dir = self::get_wp_content_dir();
649 if (!WP_CACHE) {
650 $wp_config = ABSPATH . 'wp-config.php';
651 if (Themify_Filesystem::is_writable($wp_config)) {
652 if (Themify_Filesystem::is_file(self::get_cache_config_file()) && Themify_Filesystem::is_file($cache_dir . 'advanced-cache.php')) {
653 $content = Themify_Filesystem::get_contents($wp_config);
654 $str = self::get_replace_str();
655 if (!empty($content) && strpos($content, $str, 3) === false) {
656 $content = preg_replace('/define/', $str . PHP_EOL . PHP_EOL . 'define', $content, 1);
657 if (file_put_contents($wp_config, $content, LOCK_EX)) {
658 return true;
659 }
660 }
661 }
662 } else {
663 return sprintf(__('File %s is`t writable. Please add %s %s.', 'themify'), $wp_config, "define('WP_CACHE',true)", $wp_config);
664 }
665 } elseif (!Themify_Filesystem::is_file(self::get_cache_config_file())) {
666 self::disable_cache();
667 return false;
668 }
669 return true;
670 }
671
672 public static function get_cache_config_file():string {
673 $fname = 'site';
674 if (is_multisite()) {
675 $fname .= '-' . get_current_blog_id();
676 }
677 $fname .= '.php';
678 $dir = self::get_wp_content_dir() . 'tf_cache_config';
679 Themify_Filesystem::mkdir($dir, true,0755);
680 return $dir . self::SEP . $fname;
681 }
682
683 public static function cache_menu($wp_admin_bar) {
684 if (!current_user_can('manage_options')) {
685 return;
686 }
687 $link = remove_query_arg(['tf-cache','nonce'], self::get_current_url());
688 $isDevmode = themify_is_dev_mode();
689 $args = array(
690 array(
691 'id' => 'tf_clear_cache',
692 'title' => __('Themify Cache', 'themify')
693 )
694 );
695
696 $hasCache = false;
697 $nonce= wp_create_nonce('tf_cache');
698 $cache_plugins = false !== self::get_cache_plugins();
699 $hasCache = WP_CACHE && $cache_plugins === false && Themify_Filesystem::is_file(self::get_cache_config_file());
700 if ($isDevmode === true) {
701 $args[0]['id'] = 'tf_dev_mode';
702 $args[0]['title'] = '<span class="tf_admin_bar_tooltip">' . __('Warning: Dev Mode is enabled (Themify cache, menu cache, concate cache and .gz are disabled). Only enable this for development purposes.', 'themify') . '</span>' . esc_html__('Dev Mode', 'themify');
703 $args[0]['meta'] = array('class' => 'tf_admin_bar_alert');
704 $args[] = array(
705 'id' => 'tf_disable_dev',
706 'parent' => $args[0]['id'],
707 'href' => add_query_arg(array('tf-cache' => 4,'nonce'=>$nonce), $link),
708 'title' => __('Disable Dev Mode', 'themify')
709 );
710 } else {
711 if (isset($_GET['tf-cache'],$_GET['nonce']) && wp_verify_nonce($_GET['nonce'],'tf_cache')) {
712 $cache_type = (int) $_GET['tf-cache'];
713 if ($cache_type === 3) {
714 themify_clear_menu_cache();
715 }
716 elseif ($cache_type === 1) {
717 add_filter('themify_concate_css', '__return_false');
718 if ($hasCache === true) {
719 $link = self::get_current_cache($link);
720 Themify_Filesystem::delete($link . '_safari.html', 'f');
721 Themify_Filesystem::delete($link . '_safari.html.gz', 'f');
722 $link .= '.html';
723 Themify_Filesystem::delete($link, 'f');
724 $link .= '.gz';
725 Themify_Filesystem::delete($link, 'f');
726 }
727 themify_clear_menu_cache();
728 }
729 }
730 $args[] = array(
731 'id' => 'tf_clear_html',
732 'parent' => 'tf_clear_cache',
733 'href' => add_query_arg(array('tf-cache' => 1,'nonce'=>$nonce), $link),
734 'title' => $hasCache === true ? __('Purge Page Cache', 'themify') : __('Regenerate Page CSS', 'themify')
735 );
736 $args[] = array(
737 'id' => 'tf_clear_all',
738 'parent' => 'tf_clear_cache',
739 'href' => add_query_arg(array('tf-cache' => 2,'nonce'=>$nonce), $link),
740 'title' => $hasCache === true ? __('Purge All Cache', 'themify') : __('Regenerate All CSS', 'themify')
741 );
742 if ($hasCache === false && $cache_plugins === false && !themify_check('setting-cache-menu', true)) {
743 $args[] = array(
744 'id' => 'tf_clear_menu',
745 'parent' => 'tf_clear_cache',
746 'href' => add_query_arg(array('tf-cache' => 3,'nonce'=>$nonce), $link),
747 'title' => __('Clear Menu Cache', 'themify')
748 );
749 }
750 }
751 $cache_plugins = null;
752 foreach ($args as $arg) {
753 $wp_admin_bar->add_node($arg);
754 }
755 }
756
757 public static function check_clear() {
758 if (isset($_GET['nonce']) && wp_verify_nonce($_GET['nonce'],'tf_cache') && current_user_can('manage_options')) {
759 if ($_GET['tf-cache'] === '2') {
760 if ( class_exists( 'Themify_Builder_Stylesheet', false ) ) {
761 Themify_Builder_Stylesheet::regenerate_css_files( '' );
762 }
763 Themify_Enqueue_Assets::clearConcateCss();
764 themify_clear_menu_cache();
765 } else {
766 $tmp = themify_get_data();
767 unset($tmp['setting-dev-mode']);
768 themify_set_data($tmp);
769 }
770 $link = remove_query_arg(['tf-cache','nonce'], self::get_current_url());
771 if ( wp_safe_redirect( $link ) ) {
772 exit;
773 }
774 }
775 }
776
777 public static function clear_3rd_plugins_cache($post_id = 0) {
778 $cache_plugins = self::get_cache_plugins('others');
779 if (false === $cache_plugins) {
780 return;
781 }
782 $post_id = (int) $post_id <= 0 ? 0 : (int) $post_id;
783 // Sometimes we need to clear all caches ex. when Pro template or Layout Part is edited
784 if ($post_id > 0) {
785 $type = get_post_type($post_id);
786 $post_id = in_array( $type, [ 'tbuilder_layout_part', 'tbp_template', 'tglobal_style' ], true ) ? 0 : $post_id;
787 }
788 foreach ($cache_plugins as $k => $v) {
789 switch ($k) {
790 case 'SC':
791 if ($post_id > 0) {
792 wp_cache_post_change($post_id);
793 } else {
794 wp_cache_clear_cache();
795 }
796 break;
797 case 'W3TC':
798 if ($post_id > 0) {
799 w3tc_flush_post($post_id);
800 } else {
801 w3tc_flush_all();
802 }
803 break;
804 case 'WPFC':
805 if ($post_id > 0) {
806 wpfc_clear_post_cache_by_id($post_id);
807 } else {
808 wpfc_clear_all_cache(true);
809 }
810 break;
811 case 'AO':
812 if (0 === $post_id) {
813 autoptimizeCache::clearall();
814 }
815 break;
816 case 'WPO':
817 if ($post_id > 0) {
818 WPO_Page_Cache::delete_single_post_cache($post_id);
819 } else {
820 WP_Optimize()->get_page_cache()->purge();
821 }
822 break;
823 case 'LSCWP':
824 if ($post_id > 0) {
825 do_action('litespeed_purge_post', $post_id);
826 } else {
827 do_action('litespeed_purge_all');
828 }
829 break;
830 case 'WPHB':
831 if ($post_id > 0) {
832 do_action('wphb_clear_page_cache', $post_id);
833 } else {
834 do_action('wphb_clear_page_cache');
835 }
836 break;
837 case 'CLFL':
838 // Cloudflare use this hook to purge the cache
839 if (0 === $post_id) {
840 do_action('autoptimize_action_cachepurged');
841 }
842 break;
843 case 'SGO':
844 $post_id = $post_id > 0 ? get_permalink($post_id) : false;
845 if ($post_id !== false) {
846 sg_cachepress_purge_cache($post_id);
847 } else {
848 sg_cachepress_purge_cache();
849 }
850 break;
851 case 'Breeze':
852 if ($post_id === 0) {
853 do_action('breeze_clear_all_cache');
854 }
855 break;
856 case 'ROCKET':
857 if ($post_id > 0) {
858 rocket_clean_post($post_id);
859 } else {
860 rocket_clean_domain();
861 }
862 break;
863 case 'Comet':
864 if ($post_id > 0) {
865 comet_cache::clearPost($post_id);
866 } else {
867 comet_cache::clear();
868 }
869 break;
870 case 'CE':
871 if ($post_id > 0) {
872 do_action('cache_enabler_clear_page_cache_by_post', $post_id);
873 } else {
874 do_action('cache_enabler_clear_site_cache');
875 }
876 break;
877 case 'WpeC':
878 if (method_exists('WpeCommon', 'purge_memcached')) {
879 WpeCommon::purge_memcached($post_id);
880 }
881 if (method_exists('WpeCommon', 'clear_maxcdn_cache')) {
882 WpeCommon::clear_maxcdn_cache($post_id);
883 }
884 if (method_exists('WpeCommon', 'purge_varnish_cache')) {
885 WpeCommon::purge_varnish_cache($post_id);
886 }
887 break;
888 case 'Cachify':
889 if ($post_id > 0) {
890 do_action('cachify_remove_post_cache', $post_id);
891 } else {
892 do_action('cachify_flush_cache');
893 }
894 break;
895 case 'RP':
896 if ($post_id > 0) {
897 rapidcache_clear_post_cache($post_id);
898 } else {
899 rapidcache_clear_cache();
900 }
901 break;
902 case 'SWPC':
903 if ($post_id > 0) {
904 Swift_Performance_Cache::clear_post_cache($post_id);
905 } else {
906 Swift_Performance_Cache::clear_all_cache();
907 }
908 break;
909 case 'NGXC':
910 if ($post_id === 0) {
911 $nginx_cache = new NginxCache();
912 $nginx_cache->purge_zone_once();
913 }
914 break;
915 }
916 }
917 }
918
919 public static function get_cache_plugins($slug = 'others') {
920 static $items = null;
921 if ($items === null) {
922 $items = array();
923 //W3 Total Cache plugin
924 if (function_exists('w3tc_flush_post') && function_exists('w3tc_flush_all')) {
925 $items['W3TC'] = true;
926 }
927 //WP Super Cache
928 if (function_exists('wp_cache_clear_cache') && function_exists('wp_cache_post_change')) {
929 $items['SC'] = true;
930 }
931 //Fastest Cache
932 if (function_exists('wpfc_clear_post_cache_by_id') && function_exists('wpfc_clear_all_cache')) {
933 $items['WPFC'] = true;
934 }
935 //WP Rocket
936 if (function_exists('rocket_clean_domain') && function_exists('rocket_clean_post')) {
937 $items['ROCKET'] = true;
938 }
939 //wp-cloudflare-page-cache
940 if (class_exists('SW_CLOUDFLARE_PAGECACHE',false)) {
941 $items['SWCFPC'] = true;
942 }
943 //WP-Optimiz
944 if (method_exists('WP_Optimize', 'get_page_cache') && WP_Optimize()->get_page_cache()->is_enabled()) {
945 $items['WPO'] = true;
946 }
947 //LiteSpeed Cache
948 if (defined('LSCWP_CONTENT_DIR')) {
949 $items['LSCWP'] = true;
950 }
951
952 //Comet Cache
953 if (method_exists('comet_cache', 'clear') && method_exists('comet_cache', 'clearPost')) {
954 $items['Comet'] = true;
955 }
956 //Cache Enabler
957 if (class_exists('Cache_Enabler',false)) {
958 $items['CE'] = true;
959 }
960 //Breeze
961 if (class_exists('Breeze_Admin',false)) {
962 $items['Breeze'] = true;
963 }
964 //Hummingbird
965 if (defined('WPHB_DIR_PATH')) {
966 $items['WPHB'] = true;
967 }
968 //WP Speed of Light
969 if (defined('WPSOL_PLUGIN_URL')) {
970 $items['WPSOL'] = true;
971 }
972 //Auto optimize
973 if (method_exists('autoptimizeCache', 'clearall')) {
974 $items['AO'] = true;
975 }
976 //Cloudflare
977 // https://wordpress.org/plugins/cloudflare/
978 if (defined('CLOUDFLARE_PLUGIN_DIR')) {
979 $items['CLFL'] = true;
980 }
981 //SG optimizer
982 if (function_exists('sg_cachepress_purge_cache')) {
983 $items['SGO'] = true;
984 }
985 //Cachify
986 if (defined('CACHIFY_FILE')) {
987 $items['Cachify'] = true;
988 }
989 //WPEngine Cache
990 if (class_exists('WpeCommon',false)) {
991 $items['WpeC'] = true;
992 }
993 //Rapid Cache
994 if (function_exists('rapidcache_clear_post_cache') && function_exists('rapidcache_clear_cache')) {
995 $items['RP'] = true;
996 }
997
998 //Swift Cache
999 if (class_exists('Swift_Performance_Cache',false)) {
1000 $items['SWPC'] = true;
1001 }
1002 //NginxCache Cache
1003 if (class_exists('NginxCache',false)) {
1004 $items['NGXC'] = true;
1005 }
1006 }
1007 if ($slug === 'others') {
1008 unset($items['themify']);
1009 return empty($items) ? false : $items;
1010 }
1011 //themify cache
1012 if (defined('TF_CACHE') && TF_CACHE) {
1013 $items['themify'] = true;
1014 }
1015 if ($slug === 'any') {
1016 return !empty($items);
1017 }
1018 if ($slug === 'all') {
1019 return $items;
1020 }
1021 return isset($items[$slug]);
1022 }
1023
1024 public static function themify_updated($upgrader_object, $options) {
1025 if ($options['action'] === 'update') {
1026 if ($options['type'] === 'plugin' && defined('THEMIFY_BUILDER_SLUG')) {
1027 if (isset($options['plugins'])) {
1028 foreach ($options['plugins'] as $each_plugin) {
1029 if ($each_plugin === THEMIFY_BUILDER_SLUG) {
1030 self::clear_3rd_plugins_cache();
1031 break;
1032 }
1033 }
1034 }
1035 } elseif ($options['type'] === 'theme' && function_exists('themify_is_themify_theme') && themify_is_themify_theme()) {
1036 self::clear_3rd_plugins_cache();
1037 }
1038 }
1039 }
1040 }
1041
1042 add_action('after_setup_theme', array('TFCache', 'hooks'));
1043 }