JezK
Edit File: lws-optimize.php
<?php require_once __DIR__ . "/vendor/autoload.php"; use Lws\Classes\LwsOptimize; use Lws\Classes\LwsOptimizeWpCli; use Lws\Classes\RUM\LwsOptimizeRUM; /** * Plugin Name: LWS Optimize - All-in-One Speed Booster & Cache Tools * Plugin URI: https://www.lws.fr/ * Description: Reach better speed and performances with Optimize! Minification, Combination, Media convertion... Everything you need for a better website * Version: 4.1.4 * Author: LWS * Author URI: https://www.lws.fr * Tested up to: 7.0 * Text Domain: lws-optimize * Domain Path: /languages * License: GPL-2.0-or-later * * @link https://www.lws.fr/ * @since 1.0 * @package lws-optimize * */ if (!defined('ABSPATH')) { exit; } // Polyfills of useful PHP8+ functions for PHP < 8 if (!function_exists('str_starts_with')) { function str_starts_with($haystack, $needle) { return strlen($needle) === 0 || strpos($haystack, $needle) === 0; } } if (!function_exists('str_contains')) { function str_contains($haystack, $needle) { return strlen($needle) === 0 || strpos($haystack, $needle) !== false; } } if (!function_exists('str_ends_with')) { function str_ends_with($haystack, $needle) { return strlen($needle) === 0 || substr($haystack, -strlen($needle)) === $needle; } } // https://example.fr/wp-content/plugins/lws-optimize/ if (!defined('LWS_OP_URL')) { define('LWS_OP_URL', plugin_dir_url(__FILE__)); } // ABSPATH/wp-content/plugins/lws-optimize/ if (!defined('LWS_OP_DIR')) { define('LWS_OP_DIR', plugin_dir_path(__FILE__)); } // ABSPATH/wp-content/cache/lwsoptimize/ if (!defined('LWS_OP_UPLOADS')) { define('LWS_OP_UPLOADS', WP_CONTENT_DIR . '/cache/lwsoptimize/'); } // lws-optimize/lws-optimize.php if (!defined('LWS_OP_BASENAME')) { define('LWS_OP_BASENAME', plugin_basename(__FILE__)); } // Path to the object-cache file (for Memcached) if (!defined('LWSOP_OBJECTCACHE_PATH')) { define('LWSOP_OBJECTCACHE_PATH', WP_CONTENT_DIR . '/object-cache.php'); } // Function declarations for hook callbacks function lwsoptimize_activation_callback() { delete_option('lws_optimize_preload_is_ongoing'); LwsOptimizeRUM::create_table(); $optimize_options = get_option('lws_optimize_config_array', []); $GLOBALS['lws_optimize']->lws_optimize_set_cache_htaccess(); $GLOBALS['lws_optimize']->lws_optimize_reset_header_htaccess(); // Deactivate the preloading on plugin activation to prevent issues if (isset($optimize_options['filebased_cache']) && $optimize_options['filebased_cache']['state'] == "true") { // Create the cache directory upfront so a hosting permission issue is caught // (and logged) at activation time instead of surfacing as a silently empty // cache on the first real page view. if (!is_dir(LWS_OP_UPLOADS) && !wp_mkdir_p(LWS_OP_UPLOADS)) { $GLOBALS['lws_optimize']->lwsop_debug_log("LWSOptimize: Could not create cache directory " . LWS_OP_UPLOADS . " on activation"); } if (wp_next_scheduled("lws_optimize_start_filebased_preload")) { wp_unschedule_event(wp_next_scheduled('lws_optimize_start_filebased_preload'), 'lws_optimize_start_filebased_preload'); } $optimize_options['filebased_cache']['preload'] = "false"; $optimize_options['filebased_cache']['preload_done'] = 0; $optimize_options['filebased_cache']['preload_ongoing'] = "true"; update_option('lws_optimize_config_array', $optimize_options); } wp_unschedule_event(wp_next_scheduled('lws_optimize_convert_media_cron'), 'lws_optimize_convert_media_cron'); wp_unschedule_event(wp_next_scheduled('lwsop_revertOptimization'), 'lwsop_revertOptimization'); if (isset($optimize_options['maintenance_db']) && $optimize_options['maintenance_db']['state'] == "true") { if (wp_next_scheduled("lws_optimize_maintenance_db_weekly")) { wp_unschedule_event(wp_next_scheduled('lws_optimize_maintenance_db_weekly'), 'lws_optimize_maintenance_db_weekly'); } wp_schedule_event(time() + 604800, 'weekly', "lws_optimize_maintenance_db_weekly"); } } function lwsoptimize_deactivation_callback() { delete_option('lws_optimize_preload_is_ongoing'); // Deactivate all crons wp_unschedule_event(wp_next_scheduled('lws_optimize_start_filebased_preload'), 'lws_optimize_start_filebased_preload'); wp_unschedule_event(wp_next_scheduled('lws_optimize_convert_media_cron'), 'lws_optimize_convert_media_cron'); wp_unschedule_event(wp_next_scheduled('lws_optimize_maintenance_db_weekly'), 'lws_optimize_maintenance_db_weekly'); wp_unschedule_event(wp_next_scheduled("lwsop_revertOptimization"), "lwsop_revertOptimization"); // Remove the deployed cache-serve script (placed outside /plugins/ to avoid 403s) $deployed_serve = WP_CONTENT_DIR . '/cache/lwsoptimize/lwsop_cache_serve.php'; if (file_exists($deployed_serve)) { wp_delete_file($deployed_serve); } // Remove .htaccess content $htaccess_file = ABSPATH . '/.htaccess'; if (file_exists($htaccess_file) && is_writable($htaccess_file)) { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_is_writable -- runs on (de)activation, before WP_Filesystem credentials would be available $htaccess_content = file_get_contents($htaccess_file); // Remove LWS OPTIMIZE - CACHING section $htaccess_content = preg_replace('/\s*#LWS OPTIMIZE - CACHING.*?#END LWS OPTIMIZE - CACHING\s*/s', "\n", $htaccess_content); // Remove LWS OPTIMIZE - EXPIRE HEADER section $htaccess_content = preg_replace('/\s*#LWS OPTIMIZE - EXPIRE HEADER.*?#END LWS OPTIMIZE - EXPIRE HEADER\s*/s', "\n", $htaccess_content); // Remove LWS OPTIMIZE - GZIP COMPRESSION section $htaccess_content = preg_replace('/\s*#LWS OPTIMIZE - GZIP COMPRESSION.*?#END LWS OPTIMIZE - GZIP COMPRESSION\s*/s', "\n", $htaccess_content); // Write the modified content back to the file // phpcs:ignore PluginCheck.CodeAnalysis.WriteFile.ABSPATHDetected -- rewriting the site root .htaccess (which must live at ABSPATH) to remove this plugin's own rules; wp_upload_dir() does not apply here if (isset($GLOBALS['lws_optimize'])) { $GLOBALS['lws_optimize']->lwsop_atomic_write($htaccess_file, $htaccess_content); } else { file_put_contents($htaccess_file, $htaccess_content); } } } function lwsoptimize_uninstall_callback() { // Remove the cache folder $cache_dir = WP_CONTENT_DIR . '/cache/lwsoptimize/'; $upload_dir = WP_CONTENT_DIR . '/uploads/lwsoptimize/'; WP_Filesystem(); global $wp_filesystem; if (file_exists($cache_dir)) { $wp_filesystem->rmdir($cache_dir, true); } if (file_exists($upload_dir)) { $wp_filesystem->rmdir($upload_dir, true); } // Deactivate all crons wp_unschedule_event(wp_next_scheduled('lws_optimize_start_filebased_preload'), 'lws_optimize_start_filebased_preload'); wp_unschedule_event(wp_next_scheduled('lws_optimize_convert_media_cron'), 'lws_optimize_convert_media_cron'); wp_unschedule_event(wp_next_scheduled('lws_optimize_maintenance_db_weekly'), 'lws_optimize_maintenance_db_weekly'); wp_unschedule_event(wp_next_scheduled("lwsop_revertOptimization"), "lwsop_revertOptimization"); // Remove .htaccess content $htaccess_file = ABSPATH . '/.htaccess'; if (file_exists($htaccess_file) && is_writable($htaccess_file)) { // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_is_writable -- runs on (de)activation, before WP_Filesystem credentials would be available $htaccess_content = file_get_contents($htaccess_file); // Remove LWS OPTIMIZE - CACHING section $htaccess_content = preg_replace('/\s*#LWS OPTIMIZE - CACHING.*?#END LWS OPTIMIZE - CACHING\s*/s', "\n", $htaccess_content); // Remove LWS OPTIMIZE - EXPIRE HEADER section $htaccess_content = preg_replace('/\s*#LWS OPTIMIZE - EXPIRE HEADER.*?#END LWS OPTIMIZE - EXPIRE HEADER\s*/s', "\n", $htaccess_content); // Remove LWS OPTIMIZE - GZIP COMPRESSION section $htaccess_content = preg_replace('/\s*#LWS OPTIMIZE - GZIP COMPRESSION.*?#END LWS OPTIMIZE - GZIP COMPRESSION\s*/s', "\n", $htaccess_content); // Write the modified content back to the file // phpcs:ignore PluginCheck.CodeAnalysis.WriteFile.ABSPATHDetected -- rewriting the site root .htaccess (which must live at ABSPATH) to remove this plugin's own rules; wp_upload_dir() does not apply here if (isset($GLOBALS['lws_optimize'])) { $GLOBALS['lws_optimize']->lwsop_atomic_write($htaccess_file, $htaccess_content); } else { file_put_contents($htaccess_file, $htaccess_content); } } // Remove all options on delete delete_option('lws_optimize_config_array'); delete_option('lws_optimize_preload_is_ongoing'); delete_option('lws_optimize_image_api_key'); delete_option('lws_optimize_cache_statistics'); delete_option('lws_optimize_image_conversion_options'); delete_option('lwsop_plugin_version'); } // Actions to execute when the plugin is activated / deactivated / deleted / upgraded register_activation_hook(__FILE__, 'lwsoptimize_activation_callback'); register_deactivation_hook(__FILE__, 'lwsoptimize_deactivation_callback'); register_uninstall_hook(__FILE__, 'lwsoptimize_uninstall_callback'); add_action('plugins_loaded', function() { $ancienne_version = get_option('lwsop_plugin_version', 0); $nouvelle_version = '3.3.11'; // Remplacez par la version actuelle du plugin. if ($ancienne_version !== $nouvelle_version) { add_option( 'wp_lwsoptimize_post_update', 1); LwsOptimizeRUM::create_table(); // Mettre à jour la version en base. update_option('lwsop_plugin_version', $nouvelle_version); } }); // Manage the "Our plugins" tab, allowing users to install our plugins add_action("wp_ajax_lws_op_downloadPlugin", "wp_ajax_install_plugin"); add_action("wp_ajax_lws_op_activatePlugin", function() { check_ajax_referer('activate_plugin', '_ajax_nonce'); if (!current_user_can('activate_plugins')) { wp_send_json_error(['code' => 'FORBIDDEN'], 403); } if (isset($_POST['ajax_slug'])) { switch (sanitize_textarea_field(wp_unslash($_POST['ajax_slug']))) { case 'lws-hide-login': activate_plugin('lws-hide-login/lws-hide-login.php'); break; case 'lws-tools': activate_plugin('lws-tools/lws-tools.php'); break; case 'lws-affiliation': activate_plugin('lws-affiliation/lws-affiliation.php'); break; case 'lws-cleaner': activate_plugin('lws-cleaner/lws-cleaner.php'); break; default: break; } } }); $lwsoptimize_deactivated = get_option('lws_optimize_deactivate_temporarily', false); if ($lwsoptimize_deactivated) { if (time() > $lwsoptimize_deactivated) { delete_option('lws_optimize_deactivate_temporarily'); } } // PHP-level compression fallback for shared-hosting vhosts where mod_deflate/ // mod_brotli aren't loaded, so the "GZIP/Brotli" toggle isn't a no-op there (see // LwsOptimize::lwsop_check_apache_compression_support()). This must be opened here, // before LwsOptimize's constructor starts the file-cache output buffer below, so it // wraps AROUND that buffer: it only affects the bytes sent to the browser, never // what gets written to the HTML cache. if ( function_exists('ob_gzhandler') // Set by lwsop_check_apache_compression_support(): that probe measures whether // Apache itself compresses, so this fallback must stay out of its way or it would // report "supported" on a server whose compression modules aren't even loaded. && !isset($_SERVER['HTTP_X_LWSOP_COMPRESSION_PROBE']) && !is_admin() && !(defined('DOING_CRON') && DOING_CRON) && !(defined('DOING_AJAX') && DOING_AJAX) && !(defined('REST_REQUEST') && REST_REQUEST) && !(defined('WP_CLI') && WP_CLI) ) { $lwsop_bootstrap_options = get_option('lws_optimize_config_array', []); $lwsop_gzip_enabled = ($lwsop_bootstrap_options['gzip_compression']['state'] ?? 'false') === 'true'; $lwsop_apache_compression_missing = get_option('lwsop_apache_compression_detected', 'true') === 'false'; if ($lwsop_gzip_enabled && $lwsop_apache_compression_missing) { ob_start('ob_gzhandler'); } unset($lwsop_bootstrap_options, $lwsop_gzip_enabled, $lwsop_apache_compression_missing); } $GLOBALS['lws_optimize'] = new LwsOptimize(); // Register WP-CLI commands once the plugin is loaded if (defined('WP_CLI') && WP_CLI) { LwsOptimizeWpCli::register_commands(); }