hook_suffixes[] = $main_hook; $pages = array( 'wpsco-dashboard' => array( __( 'Dashboard', 'speednest' ), array( $this, 'render_dashboard' ) ), 'wpsco-cache' => array( __( 'Cache Control', 'speednest' ), array( $this, 'render_cache' ) ), 'wpsco-css' => array( __( 'CSS Optimization', 'speednest' ), array( $this, 'render_css' ) ), 'wpsco-javascript' => array( __( 'JS Optimization', 'speednest' ), array( $this, 'render_javascript' ) ), 'wpsco-html' => array( __( 'HTML Optimization', 'speednest' ), array( $this, 'render_html' ) ), 'wpsco-images' => array( __( 'Image Optimization', 'speednest' ), array( $this, 'render_images' ) ), 'wpsco-fonts' => array( __( 'Font Optimization', 'speednest' ), array( $this, 'render_fonts' ) ), 'wpsco-database' => array( __( 'Database Cleaner', 'speednest' ), array( $this, 'render_database' ) ), 'wpsco-wordpress' => array( __( 'WP Tweaks', 'speednest' ), array( $this, 'render_wordpress' ) ), 'wpsco-woocommerce' => array( __( 'WooCommerce', 'speednest' ), array( $this, 'render_woocommerce' ) ), 'wpsco-cloudflare' => array( __( 'Cloudflare & CDN', 'speednest' ), array( $this, 'render_cloudflare' ) ), 'wpsco-diagnostics' => array( __( 'Diagnostics', 'speednest' ), array( $this, 'render_diagnostics' ) ), 'wpsco-tools' => array( __( 'Tools & Logs', 'speednest' ), array( $this, 'render_tools' ) ), 'wpsco-settings' => array( __( 'Settings', 'speednest' ), array( $this, 'render_settings' ) ), ); foreach ( $pages as $slug => $data ) { $hook = add_submenu_page( 'wpsco-dashboard', $data[0] . ' ‹ ' . __( 'SpeedNest', 'speednest' ), $data[0], $cap, $slug, $data[1] ); $this->hook_suffixes[] = $hook; } } /** * Enqueue admin assets only on plugin pages. * * @param string $hook Current admin page hook. */ public function enqueue_assets( $hook ) { if ( strpos( $hook, 'wpsco' ) === false && ! in_array( $hook, $this->hook_suffixes, true ) ) { return; } $ver = WPSCO_VERSION . '.' . time(); wp_enqueue_style( 'wpsco-admin-css', WPSCO_PLUGIN_URL . 'assets/css/admin.css', array( 'dashicons' ), $ver ); wp_enqueue_script( 'wpsco-admin-js', WPSCO_PLUGIN_URL . 'assets/js/admin.js', array( 'jquery' ), $ver, true ); wp_localize_script( 'wpsco-admin-js', 'wpsco_admin', array( 'ajax_url' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'wpsco_admin_nonce' ), 'strings' => array( 'purging' => __( 'Purging caches across all layers...', 'speednest' ), 'purge_success' => __( 'Cache purged successfully.', 'speednest' ), 'purge_partial' => __( 'Partial cache purge completed.', 'speednest' ), 'optimizing' => __( 'Applying safe optimization settings...', 'speednest' ), 'optimize_done' => __( 'Safe optimization configured and caches cleared!', 'speednest' ), 'confirm_nuclear' => __( 'Are you sure you want to run a Nuclear Purge? This clears all cached HTML, CSS, JS, images, fonts, transients, object cache, and resets OPcache.', 'speednest' ), 'confirm_clean' => __( 'Are you sure you want to clean selected database items? WooCommerce orders and users are always protected.', 'speednest' ), 'confirm_reset' => __( 'Are you sure you want to reset all plugin settings to factory defaults?', 'speednest' ), 'testing' => __( 'Testing connection...', 'speednest' ), 'running_diag' => __( 'Analyzing performance metrics...', 'speednest' ), ), ) ); } /** * Render global conflict & emergency notices. */ public function render_admin_notices() { if ( ! wpsco_current_user_can() ) { return; } $screen = get_current_screen(); if ( ! $screen || strpos( $screen->id, 'wpsco' ) === false ) { return; } // Cache action success message. // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only notice message from redirect. if ( isset( $_GET['wpsco_msg'] ) && ! empty( $_GET['wpsco_msg'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only notice message from redirect. $wpsco_msg = sanitize_text_field( wp_unslash( $_GET['wpsco_msg'] ) ); ?>

detect_all(); $dismissed = (array) wpsco_get_setting( 'dismissed_conflicts', array() ); if ( ! empty( $conflicts ) ) { foreach ( $conflicts as $plugin_file => $conflict ) { if ( in_array( $plugin_file, $dismissed, true ) ) { continue; } ?>

' . esc_html( $conflict['name'] ) . '' ); ?>

purge_all(); $msg = __( 'All caches cleared successfully.', 'speednest' ); } elseif ( 'purge_everything' === $action ) { $purger->purge_everything(); $msg = __( 'Nuclear cache purge completed across all layers.', 'speednest' ); } elseif ( 'clear_html' === $action ) { $purger->purge_html_cache(); $msg = __( 'HTML page cache cleared.', 'speednest' ); } elseif ( 'clear_css' === $action ) { $purger->purge_css_cache(); $msg = __( 'CSS cache cleared.', 'speednest' ); } elseif ( 'clear_js' === $action ) { $purger->purge_js_cache(); $msg = __( 'JS cache cleared.', 'speednest' ); } elseif ( 'clear_object' === $action ) { $purger->purge_object_cache(); $msg = __( 'Object cache flushed.', 'speednest' ); } elseif ( 'reset_opcache' === $action ) { $purger->purge_opcache(); $msg = __( 'PHP OPcache reset.', 'speednest' ); } $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : 'wpsco-dashboard'; wp_safe_redirect( add_query_arg( array( 'page' => $page, 'wpsco_msg' => rawurlencode( $msg ) ), admin_url( 'admin.php' ) ) ); exit; } /** * AJAX: Clear Cache. */ public function ajax_clear_cache() { check_ajax_referer( 'wpsco_admin_nonce' ); WPSCO_Security::enforce_capability(); $layer = isset( $_POST['layer'] ) ? sanitize_text_field( wp_unslash( $_POST['layer'] ) ) : 'all'; $purger = new WPSCO_Cache_Purger(); if ( 'css' === $layer ) { $result = array( 'css' => $purger->purge_css_cache() ); } elseif ( 'js' === $layer ) { $result = array( 'js' => $purger->purge_js_cache() ); } elseif ( 'html' === $layer ) { $result = array( 'html' => $purger->purge_html_cache() ); } elseif ( 'object' === $layer ) { $result = array( 'object' => $purger->purge_object_cache() ); } elseif ( 'opcache' === $layer ) { $result = array( 'opcache' => $purger->purge_opcache() ); } else { $result = $purger->purge_all(); } $new_size_bytes = wpsco_get_dir_size( wpsco_get_cache_dir() ); $new_size_text = wpsco_format_size( $new_size_bytes ); $new_version = substr( wpsco_get_cache_version(), 0, 12 ) . '...'; wp_send_json_success( array( 'results' => $result, 'new_size_text' => $new_size_text, 'new_version' => $new_version, 'message' => __( 'Cache purge operation executed.', 'speednest' ), ) ); } /** * AJAX: Purge Everything Possible (Nuclear Purge). */ public function ajax_purge_everything() { check_ajax_referer( 'wpsco_admin_nonce' ); WPSCO_Security::enforce_capability(); $purger = new WPSCO_Cache_Purger(); $results = $purger->purge_everything(); $new_size_bytes = wpsco_get_dir_size( wpsco_get_cache_dir() ); $new_size_text = wpsco_format_size( $new_size_bytes ); $new_version = substr( wpsco_get_cache_version(), 0, 12 ) . '...'; wp_send_json_success( array( 'results' => $results, 'new_size_text' => $new_size_text, 'new_version' => $new_version, 'message' => __( 'Nuclear cache purge completed across all layers.', 'speednest' ), ) ); } /** * AJAX: One-Click Safe Optimization. */ public function ajax_safe_optimize() { check_ajax_referer( 'wpsco_admin_nonce' ); WPSCO_Security::enforce_capability(); WPSCO_Settings::apply_one_click_safe_optimization(); $purger = new WPSCO_Cache_Purger(); $results = $purger->purge_all(); wp_send_json_success( array( 'message' => __( 'Safe optimization activated! Caches cleared.', 'speednest' ), 'results' => $results, ) ); } /** * AJAX: Deactivate Conflicting Plugin safely. */ public function ajax_deactivate_conflict() { check_ajax_referer( 'wpsco_admin_nonce' ); WPSCO_Security::enforce_capability(); $plugin_file = isset( $_POST['plugin'] ) ? sanitize_text_field( wp_unslash( $_POST['plugin'] ) ) : ''; $detector = new WPSCO_Conflict_Detector(); $result = $detector->deactivate_conflicting_plugin( $plugin_file ); if ( is_wp_error( $result ) ) { wp_send_json_error( array( 'message' => $result->get_error_message() ) ); } wp_send_json_success( array( 'message' => __( 'Conflicting plugin deactivated safely. Data and settings were preserved.', 'speednest' ), ) ); } /** * AJAX: Dismiss conflict notice. */ public function ajax_dismiss_conflict() { check_ajax_referer( 'wpsco_admin_nonce' ); WPSCO_Security::enforce_capability(); $plugin_file = isset( $_POST['plugin'] ) ? sanitize_text_field( wp_unslash( $_POST['plugin'] ) ) : ''; if ( ! empty( $plugin_file ) ) { $dismissed = (array) wpsco_get_setting( 'dismissed_conflicts', array() ); $dismissed[] = $plugin_file; wpsco_update_setting( 'dismissed_conflicts', array_unique( $dismissed ) ); } wp_send_json_success(); } /** * AJAX: Run Local Diagnostics. */ public function ajax_run_diagnostics() { check_ajax_referer( 'wpsco_admin_nonce' ); WPSCO_Security::enforce_capability(); $diag = WPSCO_Diagnostics::run_local_diagnostics(); wp_send_json_success( array( 'diagnostics' => $diag ) ); } /** * AJAX: Run dual Google PageSpeed & GTmetrix speed audit. */ public function ajax_run_speed_test() { check_ajax_referer( 'wpsco_admin_nonce' ); WPSCO_Security::enforce_capability(); $strategy = isset( $_POST['strategy'] ) && 'desktop' === $_POST['strategy'] ? 'desktop' : 'mobile'; $audit = WPSCO_Diagnostics::run_speed_audit( $strategy, true ); if ( is_wp_error( $audit ) ) { wp_send_json_error( array( 'message' => $audit->get_error_message() ) ); } wp_send_json_success( array( 'audit' => $audit, 'psi' => $audit, ) ); } /** * AJAX: Run Google PageSpeed Insights scan (legacy alias). */ public function ajax_run_pagespeed() { $this->ajax_run_speed_test(); } /** * AJAX: Save Google PageSpeed API key from dashboard. */ public function ajax_save_api_key() { check_ajax_referer( 'wpsco_admin_nonce' ); WPSCO_Security::enforce_capability(); $api_key = isset( $_POST['api_key'] ) ? sanitize_text_field( wp_unslash( $_POST['api_key'] ) ) : ''; $settings = wpsco_get_setting(); $settings['pagespeed_api_key'] = $api_key; update_option( 'wpsco_settings', $settings ); delete_transient( 'wpsco_speed_audit_mobile_' . md5( home_url() ) ); delete_transient( 'wpsco_speed_audit_desktop_' . md5( home_url() ) ); delete_option( 'wpsco_speed_scores' ); wp_send_json_success( array( 'message' => __( 'API key saved successfully.', 'speednest' ) ) ); } /** * AJAX: Clean Database items. */ public function ajax_clean_database() { check_ajax_referer( 'wpsco_admin_nonce' ); WPSCO_Security::enforce_capability(); $type = isset( $_POST['type'] ) ? sanitize_text_field( wp_unslash( $_POST['type'] ) ) : ''; $cleaner = new WPSCO_Database_Cleaner(); $count = 0; if ( 'revisions' === $type ) { $count = $cleaner->clean_post_revisions(); } elseif ( 'drafts' === $type ) { $count = $cleaner->clean_auto_drafts(); } elseif ( 'trash' === $type ) { $count = $cleaner->clean_trash_posts(); } elseif ( 'spam' === $type ) { $count = $cleaner->clean_spam_comments(); } elseif ( 'transients' === $type ) { $count = $cleaner->clean_expired_transients(); } /* translators: %d: Number of cleaned items */ $cleaned_message = sprintf( __( 'Cleaned %d item(s).', 'speednest' ), $count ); wp_send_json_success( array( 'count' => $count, 'message' => $cleaned_message, ) ); } /** * AJAX: Test Cloudflare credentials. */ public function ajax_test_cloudflare() { check_ajax_referer( 'wpsco_admin_nonce' ); WPSCO_Security::enforce_capability(); $cf = new WPSCO_Cloudflare(); $result = $cf->test_connection(); if ( 'connected' === $result['status'] ) { wp_send_json_success( $result ); } else { wp_send_json_error( $result ); } } /** * AJAX: Emergency disable toggle. */ public function ajax_emergency_toggle() { check_ajax_referer( 'wpsco_admin_nonce' ); WPSCO_Security::enforce_capability(); $current = (bool) wpsco_get_setting( 'emergency_disable', false ); $new_val = ! $current; wpsco_update_setting( 'emergency_disable', $new_val ); // Purge caches immediately. $purger = new WPSCO_Cache_Purger(); $purger->purge_all(); wp_send_json_success( array( 'disabled' => $new_val, 'message' => $new_val ? __( 'Emergency Safe Mode activated. All frontend optimizations disabled.', 'speednest' ) : __( 'Optimizations re-enabled.', 'speednest' ), ) ); } /** * AJAX: Reset settings to default. */ public function ajax_reset_settings() { check_ajax_referer( 'wpsco_admin_nonce' ); WPSCO_Security::enforce_capability(); WPSCO_Settings::reset_to_defaults(); wp_send_json_success( array( 'message' => __( 'All plugin settings reset to defaults and caches purged.', 'speednest' ), ) ); } /** * AJAX: Lossless / High Quality Bulk Image Compression. * Compresses images in batches, reducing KB while strictly preserving original dimensions and quality. */ public function ajax_compress_images() { check_ajax_referer( 'wpsco_admin_nonce' ); WPSCO_Security::enforce_capability(); $offset = isset( $_POST['offset'] ) ? max( 0, intval( $_POST['offset'] ) ) : 0; $batch_size = 5; $quality = (int) wpsco_get_setting( 'image_quality', 82 ); // Query image attachments. $query_args = array( 'post_type' => 'attachment', 'post_mime_type' => array( 'image/jpeg', 'image/png', 'image/webp' ), 'post_status' => 'inherit', 'posts_per_page' => $batch_size, 'offset' => $offset, 'fields' => 'ids', 'orderby' => 'ID', 'order' => 'ASC', ); $attachments = get_posts( $query_args ); $total_count = wp_count_attachments(); $total_images = 0; foreach ( array( 'image/jpeg', 'image/png', 'image/webp' ) as $m ) { if ( isset( $total_count->$m ) ) { $total_images += $total_count->$m; } } $processed = 0; $compressed = 0; $bytes_saved = 0; require_once WPSCO_PLUGIN_DIR . 'includes/class-image-optimizer.php'; foreach ( $attachments as $att_id ) { $file = get_attached_file( $att_id ); $meta = wp_get_attachment_metadata( $att_id ); $processed++; if ( $file && file_exists( $file ) ) { $res = WPSCO_Image_Optimizer::compress_image_file( $file, $quality ); if ( ! empty( $res['success'] ) ) { $compressed++; $bytes_saved += $res['saved']; } // Compress sub-sizes. if ( ! empty( $meta['sizes'] ) && is_array( $meta['sizes'] ) ) { $dir = dirname( $file ); foreach ( $meta['sizes'] as $s_info ) { if ( ! empty( $s_info['file'] ) ) { $sub_file = $dir . '/' . $s_info['file']; if ( file_exists( $sub_file ) ) { $sub_res = WPSCO_Image_Optimizer::compress_image_file( $sub_file, $quality ); if ( ! empty( $sub_res['success'] ) ) { $bytes_saved += $sub_res['saved']; } } } } } } } $new_offset = $offset + count( $attachments ); $is_done = empty( $attachments ) || $new_offset >= $total_images; $percent = $total_images > 0 ? min( 100, round( ( $new_offset / $total_images ) * 100 ) ) : 100; wp_send_json_success( array( 'done' => $is_done, 'offset' => $new_offset, 'total' => $total_images, 'percent' => $percent, 'processed' => $processed, 'compressed' => $compressed, 'bytes_saved' => $bytes_saved, 'message' => sprintf( /* translators: 1: Processed count, 2: Total count, 3: Formatted size saved */ __( 'Processed %1$d of %2$d images. Saved %3$s.', 'speednest' ), $new_offset, $total_images, size_format( $bytes_saved, 2 ) ), ) ); } /** * Render view helpers. */ public function render_dashboard() { $this->load_view( 'dashboard' ); } public function render_cache() { $this->load_view( 'cache' ); } public function render_css() { $this->load_view( 'css' ); } public function render_javascript() { $this->load_view( 'javascript' ); } public function render_html() { $this->load_view( 'html' ); } public function render_images() { $this->load_view( 'images' ); } public function render_fonts() { $this->load_view( 'fonts' ); } public function render_database() { $this->load_view( 'database' ); } public function render_wordpress() { $this->load_view( 'wordpress' ); } public function render_woocommerce() { $this->load_view( 'woocommerce' ); } public function render_cloudflare() { $this->load_view( 'cloudflare' ); } public function render_diagnostics() { $this->load_view( 'diagnostics' ); } public function render_tools() { $this->load_view( 'tools' ); } public function render_settings() { $this->load_view( 'settings' ); } /** * Helper to load view files. * * @param string $view_name View file name without extension. */ private function load_view( $view_name ) { $view_file = WPSCO_PLUGIN_DIR . 'admin/' . $view_name . '.php'; if ( file_exists( $view_file ) ) { require $view_file; } else { /* translators: %s: View file name */ echo '

' . esc_html( sprintf( __( 'View file %s.php not found.', 'speednest' ), $view_name ) ) . '

'; } } /** * Filter admin footer text on plugin screens. * * @param string $text Original footer text. * @return string */ public function filter_admin_footer( $text ) { $screen = get_current_screen(); if ( $screen && strpos( $screen->id, 'wpsco' ) !== false ) { return sprintf( /* translators: 1: Heart icon, 2: Code Buddy link, 3: Website link */ __( 'Made with %1$s from %2$s (%3$s)', 'speednest' ), '♥', 'Code Buddy\'s', 'codebuddys.in' ); } return $text; } }