PluginProbe
Translate and Go multilingual – Automatic AI translation – wpLingua / trunk
Translate and Go multilingual – Automatic AI translation – wpLingua vtrunk
2.16.5 2.16.4 2.16.3 2.16.2 2.16.1 2.16.0 2.15.2 2.15.1 2.15.0 2.14.3 2.14.2 2.14.1 2.14.0 2.13.1 2.13.0 2.12.3 2.12.2 2.12.1 trunk 1.0.3 1.0.4 1.0.5 1.1.0 1.1.1 1.2.0 All 110 releases
wplingua / inc / cache.php

cache.php in Translate and Go multilingual – Automatic AI translation – wpLingua trunk, at inc/cache.php

527 lines 13.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 // If this file is called directly, abort.
4 if ( ! defined( 'WPINC' ) ) {
5 die;
6 }
7
8
9 // ------------------------------------------------------------------------
10 // Manage cache on "init" hoot
11 // ------------------------------------------------------------------------
12
13 /**
14 * Do not cache page for connected editor
15 *
16 * @return void
17 */
18 function wplng_init_manage_cache() {
19 if ( current_user_can( 'edit_posts' ) ) {
20 wplng_do_not_cache_page();
21 }
22 }
23
24
25 // ------------------------------------------------------------------------
26 // Global cache functions
27 // ------------------------------------------------------------------------
28
29 /**
30 * Prevent the current page from being cached
31 *
32 * Sets HTTP no-cache headers and defines constants used by popular
33 * WordPress caching plugins to bypass caching for the current request.
34 *
35 * @return void
36 */
37 function wplng_do_not_cache_page() {
38
39 // Set HTTP no-cache header
40 nocache_headers();
41
42 // DONOTCACHEPAGE - Standard WordPress
43 // - WP Super Cache
44 // - W3 Total Cache
45 // - WP Rocket
46 if ( ! defined( 'DONOTCACHEPAGE' ) ) {
47 define( 'DONOTCACHEPAGE', true );
48 }
49
50 // LiteSpeed Cache
51 if ( ! defined( 'LSCACHE_NO_CACHE' ) ) {
52 define( 'LSCACHE_NO_CACHE', true );
53 }
54
55 // Comet Cache
56 if ( ! defined( 'COMET_CACHE_ALLOWED' ) ) {
57 define( 'COMET_CACHE_ALLOWED', false );
58 }
59
60 // Cache Enabler
61 if ( ! defined( 'CE_CACHE_BYPASS' ) ) {
62 define( 'CE_CACHE_BYPASS', true );
63 }
64
65 // WP Fastest Cache
66 if ( ! defined( 'WPFC_NO_CACHE' ) ) {
67 define( 'WPFC_NO_CACHE', true );
68 }
69
70 // Breeze (Cloudways)
71 if ( ! defined( 'DONOTCACHEDB' ) ) {
72 define( 'DONOTCACHEDB', true );
73 }
74
75 // Object cache
76 if ( ! defined( 'DONOTCACHEOBJECT' ) ) {
77 define( 'DONOTCACHEOBJECT', true );
78 }
79 }
80
81
82 /**
83 * Clear all website caches
84 *
85 * Flushes the WordPress object cache and triggers cache clearing
86 * for all detected caching plugins and services.
87 *
88 * @return void
89 */
90 function wplng_clear_website_cache() {
91
92 // WordPress Cache
93 wp_cache_flush();
94
95 // LiteSpeed Cache
96 if ( has_action( 'litespeed_purge_all' ) ) {
97 do_action( 'litespeed_purge_all' );
98 }
99
100 // WP Super Cache
101 if ( function_exists( 'wp_cache_clear_cache' ) ) {
102 wp_cache_clear_cache();
103 }
104
105 // W3 Total Cache
106 if ( function_exists( 'w3tc_flush_all' ) ) {
107 w3tc_flush_all();
108 }
109
110 // WP Fastest Cache
111 if ( function_exists( 'wpfc_clear_all_cache' ) ) {
112 wpfc_clear_all_cache();
113 }
114
115 // WP Rocket
116 if ( function_exists( 'rocket_clean_domain' ) ) {
117 if ( did_action( 'wp_rocket_loaded' ) ) {
118 rocket_clean_domain();
119 } else {
120 add_action( 'wp_rocket_loaded', 'rocket_clean_domain' );
121 }
122 }
123
124 // Autoptimize
125 if ( class_exists( 'autoptimizeCache' )
126 && method_exists( 'autoptimizeCache', 'clearall' )
127 ) {
128 autoptimizeCache::clearall();
129 }
130
131 // Comet Cache
132 if ( class_exists( 'comet_cache' )
133 && method_exists( 'comet_cache', 'clear' )
134 ) {
135 comet_cache::clear();
136 }
137
138 // Hummingbird
139 if ( has_action( 'wphb_clear_page_cache' ) ) {
140 do_action( 'wphb_clear_page_cache' );
141 }
142
143 // SG Optimizer (SiteGround)
144 if ( function_exists( 'sg_cachepress_purge_cache' ) ) {
145 sg_cachepress_purge_cache();
146 }
147
148 // Breeze (Cloudways)
149 if ( has_action( 'breeze_clear_all_cache' ) ) {
150 do_action( 'breeze_clear_all_cache' );
151 }
152
153 // Cache Enabler
154 if ( class_exists( 'Cache_Enabler' )
155 && method_exists( 'Cache_Enabler', 'clear_total_cache' )
156 ) {
157 Cache_Enabler::clear_total_cache();
158 }
159
160 // Swift Performance
161 if ( class_exists( 'Swift_Performance_Cache' )
162 && method_exists( 'Swift_Performance_Cache', 'clear_all_cache' )
163 ) {
164 Swift_Performance_Cache::clear_all_cache();
165 }
166
167 // Nginx Helper
168 if ( has_action( 'rt_nginx_helper_purge_all' ) ) {
169 do_action( 'rt_nginx_helper_purge_all' );
170 }
171
172 // WP-Optimize
173 if ( class_exists( 'WP_Optimize' )
174 && function_exists( 'wpo_cache_flush' )
175 ) {
176 wpo_cache_flush();
177 }
178
179 // Kinsta Cache
180 if ( class_exists( 'Kinsta\Cache' )
181 && wp_get_environment_type() === 'production'
182 ) {
183 wp_remote_get(
184 home_url( '/?kinsta-clear-cache-all' ),
185 array( 'blocking' => false )
186 );
187 }
188
189 // Cloudflare
190 if ( has_action( 'cloudflare_purge_everything' ) ) {
191 do_action( 'cloudflare_purge_everything' );
192 }
193 }
194
195
196 // ------------------------------------------------------------------------
197 // Translations cache functions
198 // ------------------------------------------------------------------------
199
200 /**
201 * Clear cached translations
202 *
203 * Deletes the translations transient and clears the website cache.
204 *
205 * @return void
206 */
207 function wplng_clear_translations_cache() {
208 delete_option( 'wplng_cached_translations' );
209 wplng_clear_website_cache();
210 }
211
212
213 /**
214 * Clear cached translations when a translation post is trashed or untrashed
215 *
216 * @param int $post_id The ID of the post being trashed or untrashed.
217 * @return void
218 */
219 function wplng_clear_translations_cache_trash_untrash( $post_id ) {
220
221 if ( 'wplng_translation' !== get_post_type( $post_id ) ) {
222 return;
223 }
224
225 wplng_clear_translations_cache();
226 }
227
228
229 // ------------------------------------------------------------------------
230 // Slug cache functions
231 // ------------------------------------------------------------------------
232
233 /**
234 * Clear cached slugs
235 *
236 * Deletes the slugs option and clears the website cache.
237 *
238 * @return void
239 */
240 function wplng_clear_slugs_cache() {
241 delete_option( 'wplng_cached_slugs' );
242 wplng_clear_website_cache();
243 }
244
245
246 /**
247 * Clear cached slugs when a slug post is trashed or untrashed
248 *
249 * @param int $post_id The ID of the post being trashed or untrashed.
250 * @return void
251 */
252 function wplng_clear_slugs_cache_trash_untrash( $post_id ) {
253
254 if ( 'wplng_slug' !== get_post_type( $post_id ) ) {
255 return;
256 }
257
258 wplng_clear_slugs_cache();
259 }
260
261 // ------------------------------------------------------------------------
262 // wpLingua file cache functions
263 // ------------------------------------------------------------------------
264
265 /**
266 * Write data to a cache file in the wpLingua cache directory.
267 *
268 * Creates the cache directory structure and protection files if needed,
269 * then writes the provided data to the specified file.
270 *
271 * @param string $file_name Relative path to the cache file (from WPLNG_CACHE_DIR).
272 * @param string $data Data to write to the file.
273 * @return int|false Number of bytes written, or false on failure.
274 */
275 function wplng_put_cache_file( $file_name, $data ) {
276
277 // Security: prevent path traversal
278 if ( wplng_str_contains( $file_name, '..' ) ) {
279 return false;
280 }
281
282 // Create main wpLingua cache folder if not exist
283 if ( ! is_dir( WPLNG_CACHE_DIR ) ) {
284 if ( ! wp_mkdir_p( WPLNG_CACHE_DIR ) ) {
285 return false;
286 }
287 }
288
289 // Create minimal protections in main folder (only once per request)
290 static $main_protection_checked = false;
291
292 if ( ! $main_protection_checked ) {
293
294 // Create .htaccess if not exists
295 if ( ! file_exists( WPLNG_CACHE_DIR . '/.htaccess' ) ) {
296
297 $htaccess = '##############################' . PHP_EOL;
298 $htaccess .= '# File generated by wpLingua #' . PHP_EOL;
299 $htaccess .= '##############################' . PHP_EOL;
300 $htaccess .= PHP_EOL;
301 $htaccess .= '# Disable files listing' . PHP_EOL;
302 $htaccess .= 'Options -Indexes' . PHP_EOL;
303 $htaccess .= PHP_EOL;
304 $htaccess .= '# Deny all HTTP access to this directory' . PHP_EOL;
305 $htaccess .= '<IfModule mod_authz_core.c>' . PHP_EOL;
306 $htaccess .= ' Require all denied' . PHP_EOL;
307 $htaccess .= '</IfModule>' . PHP_EOL;
308 $htaccess .= PHP_EOL;
309 $htaccess .= '<IfModule !mod_authz_core.c>' . PHP_EOL;
310 $htaccess .= ' Deny from all' . PHP_EOL;
311 $htaccess .= '</IfModule>' . PHP_EOL;
312
313 file_put_contents( WPLNG_CACHE_DIR . '/.htaccess', $htaccess );
314 }
315
316 // Create an empty index.html file in main folder
317 wplng_create_cache_index_html( WPLNG_CACHE_DIR );
318
319 $main_protection_checked = true;
320 }
321
322 // Create the subfolder if needed
323 $dir = dirname( WPLNG_CACHE_DIR . $file_name );
324 if ( ! is_dir( $dir ) ) {
325 if ( ! wp_mkdir_p( $dir ) ) {
326 return false;
327 }
328 }
329
330 // Create index.html in all directories between main path and target directory
331 wplng_create_cache_index_html_recursive( $dir );
332
333 // Write the cache file
334 return file_put_contents( WPLNG_CACHE_DIR . $file_name, $data );
335 }
336
337
338 /**
339 * Create an empty index.html file in the specified directory.
340 *
341 * @param string $dir_path Absolute path to the directory.
342 * @return bool True if file exists or was created, false on failure.
343 */
344 function wplng_create_cache_index_html( $dir_path ) {
345
346 $index_file = rtrim( $dir_path, '/\\' ) . '/index.html';
347
348 if ( file_exists( $index_file ) ) {
349 return true;
350 }
351
352 return file_put_contents( $index_file, '' ) !== false;
353 }
354
355
356 /**
357 * Create index.html files in all directories from WPLNG_CACHE_DIR to the target directory.
358 *
359 * @param string $target_dir Absolute path to the target directory.
360 * @return void
361 */
362 function wplng_create_cache_index_html_recursive( $target_dir ) {
363
364 $target_dir = wp_normalize_path( $target_dir );
365 $base_path = wp_normalize_path( WPLNG_CACHE_DIR );
366
367 // Ensure target is within cache path
368 if ( strpos( $target_dir, $base_path ) !== 0 ) {
369 return;
370 }
371
372 // Get relative path from base
373 $relative_path = substr( $target_dir, strlen( $base_path ) );
374 $relative_path = trim( $relative_path, '/' );
375
376 if ( empty( $relative_path ) ) {
377 return;
378 }
379
380 // Build each subdirectory and create index.html
381 $parts = explode( '/', $relative_path );
382 $current_path = $base_path;
383
384 foreach ( $parts as $part ) {
385 $current_path .= '/' . $part;
386 if ( is_dir( $current_path ) ) {
387 wplng_create_cache_index_html( $current_path );
388 }
389 }
390 }
391
392
393 /**
394 * Read data from a cache file in the wpLingua cache directory.
395 *
396 * @param string $file_name Relative path to the cache file (from WPLNG_CACHE_DIR).
397 * @return string|false File contents, or false if file doesn't exist or isn't readable.
398 */
399 function wplng_get_cache_file( $file_name ) {
400
401 // Security: prevent path traversal
402 if ( wplng_str_contains( $file_name, '..' ) ) {
403 return false;
404 }
405
406 $file_path = WPLNG_CACHE_DIR . $file_name;
407
408 if ( ! is_readable( $file_path ) ) {
409 return false;
410 }
411
412 return file_get_contents( $file_path );
413 }
414
415
416 /**
417 * Clear wpLingua cache folder or a specific file/directory.
418 *
419 * @param string|false $file Relative path to delete, or false to delete entire cache folder.
420 * @return bool True on success, false on failure.
421 */
422 function wplng_clear_folder_cache( $file = false ) {
423
424 if ( $file === false ) {
425 $path = WPLNG_CACHE_DIR;
426 } else {
427 $path = wp_normalize_path( WPLNG_CACHE_DIR . $file );
428
429 // Security: ensure path is within cache directory
430 if ( wplng_str_contains( $file, '..' )
431 || ! wplng_str_starts_with( $path, wp_normalize_path( WPLNG_CACHE_DIR ) )
432 ) {
433 return false;
434 }
435 }
436
437 if ( ! file_exists( $path ) ) {
438 return true;
439 }
440
441 if ( is_file( $path ) ) {
442 return @unlink( $path );
443 }
444
445 return wplng_delete_directory( $path );
446 }
447
448
449 /**
450 * Clear wpLingua cache when WordPress core, plugins, themes or translations are updated.
451 *
452 * Hooked to:
453 * - upgrader_process_complete (core, plugins, themes, translations updates)
454 * - activated_plugin
455 * - deactivated_plugin
456 * - switch_theme
457 *
458 * @param mixed $upgrader_or_plugin WP_Upgrader instance or plugin slug (depends on hook).
459 * @param array $options Array of update data (only for upgrader_process_complete).
460 * @return void
461 */
462 function wplng_clear_cache_on_update( $upgrader_or_plugin = null, $options = array() ) {
463
464 // For upgrader_process_complete hook, check update type
465 if ( ! empty( $options ) && is_array( $options ) ) {
466
467 $type = isset( $options['type'] ) ? $options['type'] : '';
468
469 // Clear cache for core, plugin, theme or translation updates
470 if ( in_array( $type, array( 'core', 'plugin', 'theme', 'translation' ), true ) ) {
471 wplng_clear_folder_cache();
472 }
473
474 return;
475 }
476
477 // For other hooks (activated_plugin, deactivated_plugin, switch_theme)
478 wplng_clear_folder_cache();
479 }
480
481
482 /**
483 * Recursively delete a directory and all its contents.
484 *
485 * Only deletes directories within WPLNG_CACHE_DIR for security.
486 *
487 * @param string $dir_path Absolute path to the directory.
488 * @return bool True on success, false on failure.
489 */
490 function wplng_delete_directory( $dir_path ) {
491
492 $dir_path = wp_normalize_path( $dir_path );
493 $base_path = wp_normalize_path( WPLNG_CACHE_DIR );
494
495 // Security: ensure path is within cache directory
496 if ( strpos( $dir_path, $base_path ) !== 0 ) {
497 return false;
498 }
499
500 if ( ! is_dir( $dir_path ) ) {
501 return false;
502 }
503
504 $items = scandir( $dir_path );
505
506 if ( $items === false ) {
507 return false;
508 }
509
510 foreach ( $items as $item ) {
511
512 if ( $item === '.' || $item === '..' ) {
513 continue;
514 }
515
516 $item_path = $dir_path . '/' . $item;
517
518 if ( is_dir( $item_path ) ) {
519 wplng_delete_directory( $item_path );
520 } else {
521 @unlink( $item_path );
522 }
523 }
524
525 return @rmdir( $dir_path );
526 }
527