| @@ -73,8 +73,26 @@ | ||
| 73 | 73 | return trailingslashit($upload_dir['basedir']); |
| 74 | 74 | } |
| 75 | 75 | |
| 76 | 76 | /** |
| 77 | + * Returns file path relative to the `wp-content` directory | |
| 78 | + * | |
| 79 | + * @param string $path | |
| 80 | + * @return string | |
| 81 | + */ | |
| 82 | + public static function get_wp_relative_path($path): string { | |
| 83 | + $path = wp_normalize_path($path); | |
| 84 | + $content_dir = wp_normalize_path(WP_CONTENT_DIR); | |
| 85 | + | |
| 86 | + $pos = strpos($path, $content_dir); | |
| 87 | + if (false === $pos) { | |
| 88 | + return $path; | |
| 89 | + } | |
| 90 | + | |
| 91 | + return substr($path, strlen($content_dir)+1) ?: ''; | |
| 92 | + } | |
| 93 | + | |
| 94 | + /** | |
| 77 | 95 | * Get the file path |
| 78 | 96 | * |
| 79 | 97 | * @param string $url |
| 80 | 98 | * @return string |
| @@ -79,8 +97,11 @@ | ||
| 79 | 97 | * @param string $url |
| 80 | 98 | * @return string |
| 81 | 99 | */ |
| 82 | 100 | public static function get_file_path($url) { |
| 101 | + $url_without_query = strtok($url, '?'); | |
| 102 | + $url = false === $url_without_query ? $url : $url_without_query; | |
| 103 | + | |
| 83 | 104 | if (is_multisite()) { |
| 84 | 105 | if (function_exists('get_main_site_id')) { |
| 85 | 106 | $site_id = get_main_site_id(); |
| 86 | 107 | } else { |
| @@ -130,10 +151,16 @@ | ||
| 130 | 151 | $dir = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($folder, FilesystemIterator::SKIP_DOTS)); |
| 131 | 152 | |
| 132 | 153 | foreach ($dir as $file) { |
| 133 | 154 | if (!empty($files_to_ignore) && is_array($files_to_ignore) && in_array($file->getFilename(), $files_to_ignore)) continue; |
| 134 | - $size += $file->getSize(); | |
| 135 | - $file_count++; | |
| 155 | + try { | |
| 156 | + if ($file->isFile()) { | |
| 157 | + $size += $file->getSize(); | |
| 158 | + $file_count++; | |
| 159 | + } | |
| 160 | + } catch (RuntimeException $e) { | |
| 161 | + error_log($e->getMessage()); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Catching exception for debugging purpose | |
| 162 | + } | |
| 136 | 163 | } |
| 137 | 164 | } catch (UnexpectedValueException $e) { |
| 138 | 165 | error_log($e->getMessage()); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Catching exception for debugging purpose |
| 139 | 166 | } |
| @@ -215,9 +242,9 @@ | ||
| 215 | 242 | /** |
| 216 | 243 | * Returns simplehtmldom\HtmlDocument object |
| 217 | 244 | * |
| 218 | 245 | * @param string $html_buffer - HTML document as string |
| 219 | - * @return simplehtmldom\HtmlDocument | boolean | |
| 246 | + * @return simplehtmldom\HtmlDocument | false | |
| 220 | 247 | */ |
| 221 | 248 | public static function get_simple_html_dom_object($html_buffer) { |
| 222 | 249 | self::maybe_include_simple_html_dom(); |
| 223 | 250 | return str_get_html($html_buffer, false, false, |
| @@ -380,8 +407,103 @@ | ||
| 380 | 407 | } |
| 381 | 408 | } |
| 382 | 409 | |
| 383 | 410 | return esc_url(add_query_arg($utm_params, $url)); |
| 411 | + } | |
| 412 | + | |
| 413 | + /** | |
| 414 | + * Defines MAX_FILE_SIZE constant if not already defined. | |
| 415 | + * | |
| 416 | + * @return void | |
| 417 | + */ | |
| 418 | + public static function define_maxfile_size_constant() { | |
| 419 | + $maxfile_size = apply_filters('wpo_max_file_size', 600000); | |
| 420 | + $maxfile_size = is_numeric($maxfile_size) && $maxfile_size > 0 ? (int) $maxfile_size : 600000; | |
| 421 | + if (!defined('MAX_FILE_SIZE')) { | |
| 422 | + define('MAX_FILE_SIZE', $maxfile_size); | |
| 423 | + } | |
| 424 | + } | |
| 425 | + | |
| 426 | + /** | |
| 427 | + * Check if the given array contains all key-value pairs of another array. | |
| 428 | + * | |
| 429 | + * @param array $needle The array of key-value pairs to check for. | |
| 430 | + * @param array $haystack The array to check within. | |
| 431 | + * @return bool True if $haystack contains all key-value pairs of $needle, false otherwise. | |
| 432 | + */ | |
| 433 | + public static function array_contains($needle, $haystack): bool { | |
| 434 | + | |
| 435 | + if (!is_array($needle) || !is_array($haystack)) return false; | |
| 436 | + | |
| 437 | + foreach ($needle as $key => $value) { | |
| 438 | + if (!array_key_exists($key, $haystack)) return false; | |
| 439 | + | |
| 440 | + if (is_array($value)) { | |
| 441 | + if (!is_array($haystack[$key])) return false; | |
| 442 | + if (!self::array_contains($value, $haystack[$key])) return false; | |
| 443 | + } elseif ($haystack[$key] != $value) { // Loose comparison is intentional here to allow type juggling, e.g. '1' == 1 since we check sent form data with saved options where types can be different | |
| 444 | + return false; | |
| 445 | + } | |
| 446 | + } | |
| 447 | + | |
| 448 | + return true; | |
| 449 | + } | |
| 450 | + | |
| 451 | + /** | |
| 452 | + * Check if the current user has permission to purge cache. | |
| 453 | + * | |
| 454 | + * @return bool | |
| 455 | + */ | |
| 456 | + public static function current_user_can_purge_cache() { | |
| 457 | + if (WP_Optimize::is_premium()) { | |
| 458 | + return WP_Optimize()->current_user_can() || WP_Optimize_Premium()->can_purge_the_cache(); | |
| 459 | + } else { | |
| 460 | + return WP_Optimize()->current_user_can(); | |
| 461 | + } | |
| 462 | + } | |
| 463 | + | |
| 464 | + /** | |
| 465 | + * Get URL without purge cache-related parameters. | |
| 466 | + * | |
| 467 | + * @return string | |
| 468 | + */ | |
| 469 | + public static function get_url_without_cache_purge_params() { | |
| 470 | + return remove_query_arg(self::get_cache_purge_params()); | |
| 471 | + } | |
| 472 | + | |
| 473 | + /** | |
| 474 | + * Outputs JavaScript to remove cache purge parameters from the URL. | |
| 475 | + * | |
| 476 | + * @return void | |
| 477 | + */ | |
| 478 | + public static function script_to_remove_cache_purge_params_from_url() { | |
| 479 | + printf('<script>document.addEventListener("DOMContentLoaded", function() { var params = %s; var url = new URL(window.location.href); for (var param of params) { url.searchParams.delete(param); } history.replaceState({}, "", url); });</script>', json_encode(self::get_cache_purge_params())); | |
| 480 | + } | |
| 481 | + | |
| 482 | + /** | |
| 483 | + * Returns the list of parameter names used for cache purge actions | |
| 484 | + * | |
| 485 | + * @return array | |
| 486 | + */ | |
| 487 | + private static function get_cache_purge_params() { | |
| 488 | + $original_purge_params = array('_wpo_purge', 'wpo_minify_cache_purged', '_wpo_purge_minify_cache', 'wpo_all_pages_cache_purged', 'wpo_single_page_cache_purged'); | |
| 489 | + $purge_params = apply_filters('wpo_get_cache_purge_params', $original_purge_params); | |
| 490 | + | |
| 491 | + if (!is_array($purge_params)) $purge_params = $original_purge_params; | |
| 492 | + | |
| 493 | + return $purge_params; | |
| 494 | + } | |
| 495 | + | |
| 496 | + /** | |
| 497 | + * Returns a human-readable time difference or "Never" if no timestamp exists. | |
| 498 | + * | |
| 499 | + * @param int|null $timestamp Unix timestamp, or null/0 for "Never". | |
| 500 | + * @return string Human-readable time string. | |
| 501 | + */ | |
| 502 | + public static function human_time_diff_or_never(?int $timestamp = null): string { | |
| 503 | + if (!$timestamp) return __('Never', 'wp-optimize'); | |
| 504 | + /* translators: %s = human-readable time difference */ | |
| 505 | + return sprintf(__('%s ago', 'wp-optimize'), human_time_diff($timestamp, time())); | |
| 384 | 506 | } |
| 385 | 507 | } |
| 386 | 508 | |
| 387 | 509 | endif; |