0 ) { $speedpage_act_services = true; } else { $speedpage_act_services = false; } } define( 'SPEEDPAGE_ACTIVATION_SERVICE', $speedpage_act_services ); } if ( SPEEDPAGE_ACTIVATION_SERVICE ) { require_once plugin_dir_path( __FILE__ ) . 'includes/SpeedPageExcludeJsFromDelay.php'; } const SPEEDPAGE_INCOMPATIBLE_PLUGINS = [ 'w3-total-cache/w3-total-cache.php', 'wp-super-cache/wp-cache.php', 'tenweb-speed-optimizer/tenweb_speed_optimizer.php', 'wp-rocket/wp-rocket.php', 'rocket-footer-js/rocket-footer-js.php', 'autoptimize/autoptimize.php', 'perfmatters/perfmatters.php', 'wp-fastest-cache/wpFastestCache.php', 'wp-optimize/wp-optimize.php', 'wp-asset-clean-up/wpacu.php', 'rocket-lazy-load/rocket-lazy-load.php', 'hummingbird-performance/wp-hummingbird.php', 'wp-hummingbird/wp-hummingbird.php', 'flying-scripts/flying-scripts.php', 'async-javascript/async-javascript.php', 'nitropack/main.php', 'psn-pagespeed-ninja/pagespeedninja.php', 'swift-performance-lite/performance.php', 'swift-performance/performance.php', 'fast-velocity-minify/fvm.php', 'wp-performance-score-booster/wp-performance-score-booster.php', 'ezoic-integration/ezoic-integration.php', 'a3-lazy-load/a3-lazy-load.php', 'page-optimize/page-optimize.php', 'wp-smushit/wp-smush.php', 'performance-lab/load.php', 'airlift/airlift.php', 'flying-press/flying-press.php', ]; require_once SPEEDPAGE_PATH . 'includes/functions.php'; class speedpage { public $cache_dir; public $connect; public $admin_bar; private $speedpage_buffer_level = 0; public $data_js = []; public $speedpage_js_list_excluded = []; public $speedpage_js_list = []; private $exclude_blob_list = [ 'adsbygoogle.js' ]; public function __construct() { add_action( 'wp', [ $this, 'advanced_cache' ], 0 ); if ( ! SPEEDPAGE_GET_QUERY_SPEEDPAGE ) { $this->cache_dir = WP_CONTENT_DIR . '/cache/speedpage/'; add_action( 'wp_body_open', function () { if ( SPEEDPAGE_ACTIVATION_SERVICE ) { echo '
'; for ( $i = 0; $i < 4; $i ++ ) { echo ' '; } echo '
'; } } ); require_once plugin_dir_path( __FILE__ ) . 'includes/connect.php'; require_once plugin_dir_path( __FILE__ ) . 'includes/admin-bar.php'; $this->connect = new SpeedPage_Connect( $this ); $this->admin_bar = new SpeedPage_Admin_Bar( $this ); add_action( 'admin_init', [ $this->connect, 'handle_connection' ] ); add_action( 'rest_api_init', [ $this, 'register_routes' ] ); add_action( 'rest_api_init', [ $this, 'register_routes_cache_page' ] ); add_action( 'rest_api_init', [ $this, 'receive' ] ); add_action( 'admin_enqueue_scripts', [ $this, 'speedp_enqueue_admin_assets' ] ); #link to Settings | Docs add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), [ $this, 'add_plugin_links' ] ); # class admin-bar add_action( 'admin_menu', [ $this->admin_bar, 'admin_menu' ] ); add_action( 'admin_bar_menu', [ $this->admin_bar, 'speedpage_add_admin_bar_button' ], 100 ); add_action( 'admin_init', [ $this->admin_bar, 'register_settings' ] ); if ( is_admin() ) { // Hook sur l'enqueue d'administration de WordPress add_action( 'admin_enqueue_scripts', [ $this, 'speedp_enqueue_dashboard_scripts' ] ); add_action( 'wp_ajax_speedpage_verify_connect', 'speedpage_verify_connect_ajax' ); add_action( 'wp_ajax_speedpage_score_checker', 'speedpage_score_checker_ajax' ); add_action( 'wp_ajax_speedpage_before_score_checker', 'speedpage_before_score_checker_ajax' ); add_action( 'wp_ajax_speedpage_deactivate_plugins', 'speedpage_deactivate_plugin_ajax' ); add_action( 'wp_ajax_speedpage_allow_api_synchro', 'speedpage_allow_api_synchro' ); add_action( 'wp_ajax_speedpage_realtime', 'speedpage_realtime_ajax' ); add_action( 'wp_ajax_speedpage_recive_data_all_pages', 'speedpage_recive_data_all_pages_ajax' ); // add_action( 'wp_ajax_speedpage_realtime_stockage', 'speedpage_realtime_stockage_ajax' ); if ( ! file_exists( $this->cache_dir ) ) { wp_mkdir_p( $this->cache_dir ); } if ( ! file_exists( $this->cache_dir . 'index.php' ) ) { file_put_contents( $this->cache_dir . 'index.php', 'config = require plugin_dir_path( __FILE__ ) . 'includes/config.php'; add_filter( 'style_loader_tag', [ $this, 'filter_style_loader_tag' ], 10, 4 );#css deffer add_action( 'wp_head', [ $this, 'critical_css' ], 0 );#css add_action( 'template_redirect', array( $this, 'start_buffer' ), 0 );#script } } } #inject css to admin public function speedp_enqueue_admin_assets( $hook ) { if ( 'toplevel_page_speedpage_settings_page' !== $hook ) { return; } wp_enqueue_style( 'speedpage-admin-style', SPEEDPAGE_URL . '/assets/css/speedpage.min.css', [], SPEEDPAGE_VERSION ); wp_enqueue_script( 'speedpage-admin', SPEEDPAGE_URL . '/assets/js/speedpage-admin.js', [ 'jquery' ], SPEEDPAGE_VERSION, true ); // Localize AFTER enqueue_script wp_localize_script( 'speedpage-admin', 'SpeedPageData', [ 'ajaxurl' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'speedpage_nonce' ), ] ); } public function add_plugin_links( $links ) { $settings_link = 'Settings'; $docs_link = 'Docs'; array_unshift( $links, $settings_link, $docs_link ); return $links; } public function register_routes_cache_page() { register_rest_route( 'speedpage/v1', '/cache-page', [ 'methods' => 'POST', 'callback' => [ $this, 'save_cache_page' ], 'permission_callback' => [ $this, 'verify_rest_api_credentials' ] ] ); } public function save_cache_page( $request ) { try { $page_id = sanitize_text_field( $request['page_id'] ); $api_key = sanitize_text_field( $request['api_key'] ); $api_secret = sanitize_text_field( $request['api_secret'] ); $html = $request->get_body(); $site_id = get_option( 'speedpage_site_id' ); $site_secret = get_option( 'speedpage_site_secret' ); // 🔐 Vérification API if ( $site_id !== $api_key || $site_secret !== $api_secret ) { throw new Exception( 'Invalid API credentials' ); } $css_dir = $this->cache_dir . 'pages_cache/'; // 📁 Create Folder if ( ! file_exists( $css_dir ) ) { if ( ! wp_mkdir_p( $css_dir ) ) { throw new Exception( 'Unable to create PAGE CACHE directory' ); } } // 🔒 Protection index if ( ! file_exists( $css_dir . 'index.php' ) ) { if ( file_put_contents( $css_dir . 'index.php', ' 'success', ], 200 ); } catch ( Exception $e ) { return new WP_REST_Response( [ 'status' => 'error', 'message' => $e->getMessage(), ], 500 ); } } public function register_routes() { register_rest_route( 'speedpage/v1', '/critical-css', [ 'methods' => 'POST', 'callback' => [ $this, 'save_critical_css' ], 'permission_callback' => [ $this, 'verify_rest_api_credentials' ] ] ); } public function verify_rest_api_credentials( $request ) { if ( current_user_can( 'manage_options' ) ) { return true; } $api_key = sanitize_text_field( $request->get_param( 'api_key' ) ?? '' ); $api_secret = sanitize_text_field( $request->get_param( 'api_secret' ) ?? '' ); $saved_id = get_option( 'speedpage_site_id' ); $saved_secret = get_option( 'speedpage_site_secret' ); if ( empty( $saved_id ) || empty( $saved_secret ) || $api_key !== $saved_id || $api_secret !== $saved_secret ) { return new WP_Error( 'rest_forbidden', __( 'Unauthorized request.', 'speedpage' ), array( 'status' => 403 ) ); } return true; } public function save_critical_css( $request ) { try { // Validate page ID strictly as a positive integer. $raw_page_id = $request->get_param( 'page_id' ); if ( ! is_scalar( $raw_page_id ) || filter_var( (string) $raw_page_id, FILTER_VALIDATE_INT, array( 'options' => array( 'min_range' => 1 ) ) ) === false ) { return new WP_REST_Response( array( 'status' => 'error', 'message' => 'Invalid page ID', ), 400 ); } $page_id = (int) $raw_page_id; $api_key = sanitize_text_field( $request->get_param( 'api_key' ) ); $api_secret = sanitize_text_field( $request->get_param( 'api_secret' ) ); $css = $request->get_body(); $site_id = get_option( 'speedpage_site_id' ); $site_secret = get_option( 'speedpage_site_secret' ); // Verify API credentials. if ( ! is_string( $site_id ) || ! is_string( $site_secret ) || ! hash_equals( $site_id, $api_key ) || ! hash_equals( $site_secret, $api_secret ) ) { return new WP_REST_Response( array( 'status' => 'error', 'message' => 'Invalid API credentials', ), 403 ); } // Ensure the cache directory is configured. if ( empty( $this->cache_dir ) ) { throw new Exception( 'CSS cache directory is not configured' ); } $css_dir = trailingslashit( $this->cache_dir ) . 'css/'; // Create the CSS directory if necessary. if ( ! is_dir( $css_dir ) ) { if ( ! wp_mkdir_p( $css_dir ) ) { throw new Exception( 'Unable to create CSS directory' ); } } // Resolve the canonical CSS directory. $real_css_dir = realpath( $css_dir ); if ( false === $real_css_dir || ! is_dir( $real_css_dir ) ) { throw new Exception( 'Invalid CSS directory' ); } // Create an index file to prevent directory listing. $index_file = trailingslashit( $real_css_dir ) . 'index.php'; if ( ! file_exists( $index_file ) ) { if ( file_put_contents( $index_file, ' 'success', ), 200 ); } catch ( Exception $e ) { return new WP_REST_Response( array( 'status' => 'error', 'message' => $e->getMessage(), ), 500 ); } } public function receive() { register_rest_route( 'speedpage/v1', '/receive', [ 'methods' => 'POST', 'callback' => [ $this, 'receive_data' ], 'permission_callback' => [ $this, 'verify_rest_api_credentials' ] ] ); } public function receive_data( $request ) { $data = $request->get_json_params(); $key = $data['X-API-KEY'] ?? null; $secret = $data['X-API-SECRET'] ?? null; $type = $data['type'] ?? null; if ( get_option( "speedpage_site_id" ) == $key && $secret == get_option( "speedpage_site_secret" ) && $type ) { if ( $type == "score_before" ) { $is_front_page = $data["data"]["is_front_page"]; if ( $is_front_page == 1 ) { $stockage = get_option( 'speedpage_stockage' ); $stockage['front_page']['before'] = $data["data"]["result"]; update_option( "speedpage_stockage", $stockage ); } // else { $stockage = get_option( 'speedpage_stockage' ); $stockage['pages'][ $data["data"]["page_id"] ]['before'] = $data["data"]["result"]; $stockage["subscription_status"] = $data["data"]["subscription_status"]; $stockage["subscription_start"] = $data["data"]["subscription_start"]; $stockage["subscription_expiry"] = $data["data"]["subscription_expiry"]; update_option( "speedpage_stockage", $stockage ); // } wp_send_json_success( $data ); } if ( $type == "score_after" ) { $is_front_page = $data["data"]["is_front_page"]; if ( $is_front_page == 1 ) { $stockage = get_option( 'speedpage_stockage' ); $stockage['front_page']['after'] = $data["data"]["result"]; update_option( "speedpage_stockage", $stockage ); } // else { $stockage = get_option( 'speedpage_stockage' ); $stockage['pages'][ $data["data"]["page_id"] ]['after'] = $data["data"]["result"]; $stockage["subscription_status"] = $data["data"]["subscription_status"]; $stockage["subscription_start"] = $data["data"]["subscription_start"]; $stockage["subscription_expiry"] = $data["data"]["subscription_expiry"]; update_option( "speedpage_stockage", $stockage ); // } wp_send_json_success( $data ); } $stockage['subscription_status'] = isset( $data['subscription_status'] ) ? $data['subscription_status'] : false; $stockage['subscription_start'] = isset( $data['subscription_start'] ) ? $data['subscription_start'] : false; $stockage['subscription_expiry'] = isset( $data['subscription_expiry'] ) ? $data['subscription_expiry'] : false; if ( $type == "all_pages_data" ) { $stockage = get_option( 'speedpage_stockage' ); foreach ( $data["data"] as $page ): if ( $page["score_before"] ) { $stockage['pages'][ $page["page_id"] ]['before'] = json_decode( $page["score_before"], true ); } if ( $page["score_after"] ) { $stockage['pages'][ $page["page_id"] ]['after'] = json_decode( $page["score_after"], true ); } endforeach; update_option( "speedpage_stockage", $stockage ); wp_send_json_success( get_option( 'speedpage_stockage' ) ); } } else { return new WP_Error( 'unauthorized', 'Invalid API key', [ 'status' => 403 ] ); } return new WP_Error( 'error', 'In function receive_data', [ 'status' => 400 ] ); } public function filter_style_loader_tag( $tag, $handle, $href, $media ) { if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) { return $tag; } if ( apply_filters( 'speedpage_defer_styles_disabled', false ) ) { return $tag; } if ( empty( $href ) || stripos( $tag, 'cache_dir . 'css/critical-' . $page_id . '.css'; if ( ! file_exists( $file ) || ! is_readable( $file ) ) { return; } $css = file_get_contents( $file ); if ( false === $css || '' === trim( $css ) ) { return; } /* * Critical CSS is inserted inside a sequence from terminating * the HTML