plugin = $plugin; } /** * Register admin hooks. * * @return void */ public function register() { add_action( 'admin_menu', array( $this, 'menu' ) ); add_action( 'admin_bar_menu', array( $this, 'admin_bar_menu' ), 90 ); add_action( 'admin_enqueue_scripts', array( $this, 'assets' ) ); add_action( 'admin_post_acelora_site_accelerator_save_settings', array( $this, 'save_settings' ) ); add_action( 'admin_post_acelora_site_accelerator_purge_cache', array( $this, 'purge_cache_from_admin_bar' ) ); add_filter( 'plugin_action_links_' . ACELORA_SITE_ACCELERATOR_BASENAME, array( $this, 'plugin_links' ) ); } /** * Add admin menu. * * @return void */ public function menu() { add_menu_page( __( 'Acelora', 'acelora-site-accelerator' ), __( 'Acelora', 'acelora-site-accelerator' ), 'manage_options', 'acelora-site-accelerator', array( $this, 'dashboard' ), 'dashicons-performance', 58 ); $pages = array( 'acelora-cache' => __( 'Cache Engine', 'acelora-site-accelerator' ), 'acelora-assets' => __( 'Assets & CDN', 'acelora-site-accelerator' ), 'acelora-images' => __( 'Images', 'acelora-site-accelerator' ), 'acelora-database' => __( 'Database', 'acelora-site-accelerator' ), 'acelora-logs' => __( 'Logs', 'acelora-site-accelerator' ), 'acelora-settings' => __( 'Automation', 'acelora-site-accelerator' ), ); foreach ( $pages as $slug => $title ) { add_submenu_page( 'acelora-site-accelerator', $title, $title, 'manage_options', $slug, array( $this, 'route' ) ); } } /** * Enqueue admin assets. * * @param string $hook Hook suffix. * @return void */ public function assets( $hook ) { if ( false === strpos( $hook, 'acelora' ) ) { return; } wp_enqueue_style( 'acelora-site-accelerator-admin', ACELORA_SITE_ACCELERATOR_URL . 'assets/css/admin.css', array(), ACELORA_SITE_ACCELERATOR_VERSION ); wp_enqueue_script( 'acelora-site-accelerator-admin', ACELORA_SITE_ACCELERATOR_URL . 'assets/js/admin.js', array( 'jquery' ), ACELORA_SITE_ACCELERATOR_VERSION, true ); wp_localize_script( 'acelora-site-accelerator-admin', 'Acelora', array( 'ajaxUrl' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'acelora_site_accelerator_admin' ), 'i18n' => array( 'running' => __( 'Running...', 'acelora-site-accelerator' ), 'done' => __( 'Done', 'acelora-site-accelerator' ), 'failed' => __( 'Action failed.', 'acelora-site-accelerator' ), ), ) ); } /** * Add plugin settings link. * * @param array $links Links. * @return array */ public function plugin_links( $links ) { array_unshift( $links, '' . esc_html__( 'Dashboard', 'acelora-site-accelerator' ) . '' ); return $links; } /** * Add Acelora shortcuts to the WordPress admin bar. * * @param \WP_Admin_Bar $wp_admin_bar Admin bar instance. * @return void */ public function admin_bar_menu( $wp_admin_bar ) { if ( ! is_admin_bar_showing() || ! current_user_can( 'manage_options' ) ) { return; } $wp_admin_bar->add_node( array( 'id' => 'acelora-site-accelerator', 'title' => esc_html__( 'Acelora', 'acelora-site-accelerator' ), 'href' => admin_url( 'admin.php?page=acelora-site-accelerator' ), 'meta' => array( 'title' => esc_attr__( 'Acelora Site Accelerator', 'acelora-site-accelerator' ), ), ) ); $purge_url = wp_nonce_url( add_query_arg( array( 'action' => 'acelora_site_accelerator_purge_cache', 'redirect_to' => rawurlencode( $this->current_url() ), ), admin_url( 'admin-post.php' ) ), 'acelora_site_accelerator_purge_cache' ); $wp_admin_bar->add_node( array( 'id' => 'acelora-site-accelerator-clear-cache', 'parent' => 'acelora-site-accelerator', 'title' => esc_html__( 'Clear All Cache', 'acelora-site-accelerator' ), 'href' => esc_url( $purge_url ), ) ); } /** * Handle admin bar cache purge requests. * * @return void */ public function purge_cache_from_admin_bar() { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'Insufficient permissions.', 'acelora-site-accelerator' ) ); } check_admin_referer( 'acelora_site_accelerator_purge_cache' ); $deleted = $this->plugin->purge_all_caches(); $redirect = isset( $_GET['redirect_to'] ) ? esc_url_raw( wp_unslash( $_GET['redirect_to'] ) ) : admin_url( 'admin.php?page=acelora-site-accelerator' ); $redirect = wp_validate_redirect( $redirect, admin_url( 'admin.php?page=acelora-site-accelerator' ) ); $this->plugin->logger()->log( 'info', 'Cache cleared from admin bar.', array( 'deleted' => $deleted ) ); if ( 0 === strpos( $redirect, admin_url() ) ) { $redirect = add_query_arg( array( 'acelora_site_accelerator_cache_purged' => absint( $deleted ), '_wpnonce' => wp_create_nonce( 'acelora_site_accelerator_cache_notice' ), ), $redirect ); } wp_safe_redirect( $redirect ); exit; } /** * Dashboard route. * * @return void */ public function dashboard() { $this->render_header( __( 'Performance Dashboard', 'acelora-site-accelerator' ) ); $this->maybe_notice(); $analytics = $this->plugin->module( 'analytics' ); $metrics = $analytics ? $analytics->metrics() : array(); ?>

%
card( __( 'Cache Files', 'acelora-site-accelerator' ), number_format_i18n( $metrics['cache_files'] ?? 0 ), size_format( $metrics['cache_size'] ?? 0 ) ); $this->card( __( 'Optimized Assets', 'acelora-site-accelerator' ), number_format_i18n( $metrics['asset_files'] ?? 0 ), size_format( $metrics['asset_size'] ?? 0 ) ); $this->card( __( 'Images Optimized', 'acelora-site-accelerator' ), number_format_i18n( $metrics['image_stats']['optimized_images'] ?? 0 ), size_format( $metrics['image_stats']['saved_bytes'] ?? 0 ) . ' saved' ); $this->card( __( 'WebP Files', 'acelora-site-accelerator' ), number_format_i18n( $metrics['image_stats']['webp_files'] ?? 0 ), __( 'Generated derivatives', 'acelora-site-accelerator' ) ); ?>

render_footer(); } /** * Route submenu pages. * * @return void */ public function route() { $screen = get_current_screen(); $page = $screen && ! empty( $screen->id ) ? sanitize_key( str_replace( 'acelora_page_', '', $screen->id ) ) : ''; switch ( $page ) { case 'acelora-cache': $this->cache_page(); break; case 'acelora-assets': $this->assets_page(); break; case 'acelora-images': $this->images_page(); break; case 'acelora-database': $this->database_page(); break; case 'acelora-logs': $this->logs_page(); break; case 'acelora-settings': $this->automation_page(); break; default: $this->dashboard(); } } /** * Cache settings page. * * @return void */ private function cache_page() { $this->render_header( __( 'Cache Engine', 'acelora-site-accelerator' ) ); $this->maybe_notice(); $this->settings_form_open(); ?>

checkbox( 'cache.enabled', __( 'Enable cache manager', 'acelora-site-accelerator' ) ); $this->number( 'cache.lifetime', __( 'Cache lifetime seconds', 'acelora-site-accelerator' ), 60 ); $this->checkbox( 'cache.mobile_cache', __( 'Separate mobile cache', 'acelora-site-accelerator' ) ); $this->checkbox( 'cache.logged_in_cache', __( 'Cache logged-in users', 'acelora-site-accelerator' ) ); $this->textarea( 'cache.excluded_urls', __( 'Excluded URLs', 'acelora-site-accelerator' ) ); $this->textarea( 'cache.excluded_cookies', __( 'Excluded cookies', 'acelora-site-accelerator' ) ); $this->textarea( 'cache.excluded_queries', __( 'Excluded query strings', 'acelora-site-accelerator' ) ); $this->textarea( 'cache.excluded_roles', __( 'Excluded roles', 'acelora-site-accelerator' ) ); ?>

checkbox( 'preload.enabled', __( 'Enable scheduled URL warmup', 'acelora-site-accelerator' ) ); $this->number( 'preload.batch_size', __( 'URL warmup batch size', 'acelora-site-accelerator' ), 1 ); $this->textarea( 'preload.sitemap_urls', __( 'Sitemap URLs', 'acelora-site-accelerator' ) ); $this->checkbox( 'browser.enabled', __( 'Enable browser cache headers', 'acelora-site-accelerator' ) ); $this->number( 'browser.max_age', __( 'Static asset max age seconds', 'acelora-site-accelerator' ), 3600 ); $this->checkbox( 'browser.etags', __( 'Enable ETags for static assets', 'acelora-site-accelerator' ) ); ?>
submit(); $this->settings_form_close(); $this->render_footer(); } /** * Asset settings page. * * @return void */ private function assets_page() { $this->render_header( __( 'Assets & CDN', 'acelora-site-accelerator' ) ); $this->maybe_notice(); $this->settings_form_open(); ?>

checkbox( 'css.minify', __( 'Minify inline CSS', 'acelora-site-accelerator' ) ); $this->textarea( 'css.critical_css', __( 'Critical CSS', 'acelora-site-accelerator' ) ); $this->textarea( 'css.exclusions', __( 'CSS exclusions', 'acelora-site-accelerator' ) ); ?>

checkbox( 'js.minify', __( 'Minify inline JavaScript', 'acelora-site-accelerator' ) ); $this->checkbox( 'js.defer', __( 'Defer JavaScript', 'acelora-site-accelerator' ) ); $this->checkbox( 'js.async', __( 'Async JavaScript', 'acelora-site-accelerator' ) ); $this->checkbox( 'js.delay', __( 'Delay JavaScript until interaction', 'acelora-site-accelerator' ) ); $this->textarea( 'js.exclusions', __( 'JavaScript exclusions', 'acelora-site-accelerator' ) ); ?>

checkbox( 'cdn.enabled', __( 'Enable CDN rewriting', 'acelora-site-accelerator' ) ); $this->text( 'cdn.url', __( 'CDN URL', 'acelora-site-accelerator' ), 'https://cdn.example.com' ); $this->textarea( 'cdn.exclusions', __( 'CDN exclusions', 'acelora-site-accelerator' ) ); ?>

checkbox( 'lazy.images', __( 'Lazy-load images', 'acelora-site-accelerator' ) ); $this->checkbox( 'lazy.iframes', __( 'Lazy-load iframes', 'acelora-site-accelerator' ) ); $this->checkbox( 'lazy.videos', __( 'Optimize videos', 'acelora-site-accelerator' ) ); $this->textarea( 'lazy.exclusions', __( 'Lazy-load exclusions', 'acelora-site-accelerator' ) ); $this->checkbox( 'compression.enabled', __( 'Enable compression compatibility headers', 'acelora-site-accelerator' ) ); ?>
submit(); $this->settings_form_close(); $this->render_footer(); } /** * Images page. * * @return void */ private function images_page() { $this->render_header( __( 'Image Optimization', 'acelora-site-accelerator' ) ); $this->maybe_notice(); $images = $this->plugin->module( 'images' ); $stats = $images ? $images->stats() : array(); ?>
card( __( 'Optimized Images', 'acelora-site-accelerator' ), number_format_i18n( $stats['optimized_images'] ?? 0 ), __( 'Attachments processed', 'acelora-site-accelerator' ) ); $this->card( __( 'Storage Saved', 'acelora-site-accelerator' ), size_format( $stats['saved_bytes'] ?? 0 ), __( 'Estimated local savings', 'acelora-site-accelerator' ) ); $this->card( __( 'WebP Generated', 'acelora-site-accelerator' ), number_format_i18n( $stats['webp_files'] ?? 0 ), __( 'Modern image files', 'acelora-site-accelerator' ) ); ?>
settings_form_open(); ?>

checkbox( 'images.optimize_uploads', __( 'Optimize images on upload', 'acelora-site-accelerator' ) ); $this->checkbox( 'images.webp', __( 'Generate and deliver WebP where supported', 'acelora-site-accelerator' ) ); $this->number( 'images.quality', __( 'Compression quality', 'acelora-site-accelerator' ), 40 ); $this->checkbox( 'images.lazy', __( 'Enable image lazy loading', 'acelora-site-accelerator' ) ); ?>
submit(); $this->settings_form_close(); $this->render_footer(); } /** * Database page. * * @return void */ private function database_page() { $this->render_header( __( 'Database Optimization', 'acelora-site-accelerator' ) ); $this->maybe_notice(); ?>

settings_form_open(); ?>

select( 'database.schedule', __( 'Database cleanup schedule', 'acelora-site-accelerator' ), $this->schedule_options() ); ?>
submit(); $this->settings_form_close(); $this->render_footer(); } /** * Logs page. * * @return void */ private function logs_page() { $this->render_header( __( 'Advanced Logs', 'acelora-site-accelerator' ) ); $logs = $this->plugin->logger()->recent( 150 ); ?>

render_footer(); } /** * Automation page. * * @return void */ private function automation_page() { $this->render_header( __( 'Automation Center', 'acelora-site-accelerator' ) ); $this->maybe_notice(); $this->settings_form_open(); ?>

checkbox( 'automation.enabled', __( 'Enable automated optimization', 'acelora-site-accelerator' ) ); $this->select( 'automation.cache_cleanup', __( 'Cache cleanup schedule', 'acelora-site-accelerator' ), $this->schedule_options() ); $this->select( 'automation.preload', __( 'URL warmup schedule', 'acelora-site-accelerator' ), $this->schedule_options() ); $this->select( 'automation.database_optimization', __( 'Database cleanup schedule', 'acelora-site-accelerator' ), $this->schedule_options() ); $this->select( 'automation.one_click', __( 'One-click optimization schedule', 'acelora-site-accelerator' ), $this->schedule_options() ); ?>

select( 'heartbeat.mode', __( 'Heartbeat mode', 'acelora-site-accelerator' ), array( 'reduce' => __( 'Reduce frequency', 'acelora-site-accelerator' ), 'disable' => __( 'Disable by context', 'acelora-site-accelerator' ), ) ); $this->number( 'heartbeat.frequency', __( 'Heartbeat frequency seconds', 'acelora-site-accelerator' ), 15 ); $this->checkbox( 'heartbeat.admin', __( 'Allow heartbeat in admin', 'acelora-site-accelerator' ) ); $this->checkbox( 'heartbeat.frontend', __( 'Allow heartbeat on frontend', 'acelora-site-accelerator' ) ); $this->checkbox( 'heartbeat.editor', __( 'Allow heartbeat in editor', 'acelora-site-accelerator' ) ); $this->checkbox( 'logging.enabled', __( 'Enable advanced logging', 'acelora-site-accelerator' ) ); $this->number( 'logging.retention_days', __( 'Log retention days', 'acelora-site-accelerator' ), 1 ); ?>
submit(); $this->settings_form_close(); $this->render_footer(); } /** * Save settings. * * @return void */ public function save_settings() { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'Insufficient permissions.', 'acelora-site-accelerator' ) ); } check_admin_referer( 'acelora_site_accelerator_save_settings' ); $current = $this->plugin->settings()->all(); $incoming = isset( $_POST['acelora_site_accelerator'] ) && is_array( $_POST['acelora_site_accelerator'] ) ? map_deep( wp_unslash( $_POST['acelora_site_accelerator'] ), 'sanitize_textarea_field' ) : array(); foreach ( $this->checkbox_paths() as $path ) { $this->set_path( $current, $path, 0 ); } $settings = array_replace_recursive( $current, $incoming ); $this->plugin->settings()->save( $settings ); Cron::reschedule_events( $this->plugin->settings() ); $this->plugin->logger()->log( 'info', 'Settings saved from admin.' ); $redirect = wp_get_referer() ? wp_get_referer() : admin_url( 'admin.php?page=acelora-site-accelerator' ); wp_safe_redirect( add_query_arg( array( 'acelora_site_accelerator_saved' => '1', '_wpnonce' => wp_create_nonce( 'acelora_site_accelerator_saved_notice' ), ), esc_url_raw( $redirect ) ) ); exit; } /** * Render header. * * @param string $title Page title. * @return void */ private function render_header( $title ) { ?>

'; } /** * Display saved notice. * * @return void */ private function maybe_notice() { if ( isset( $_GET['acelora_site_accelerator_saved'], $_GET['_wpnonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'acelora_site_accelerator_saved_notice' ) ) { echo '

' . esc_html__( 'Acelora settings saved.', 'acelora-site-accelerator' ) . '

'; } if ( isset( $_GET['acelora_site_accelerator_cache_purged'], $_GET['_wpnonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'acelora_site_accelerator_cache_notice' ) ) { $deleted = absint( $_GET['acelora_site_accelerator_cache_purged'] ); echo '

' . esc_html( sprintf( /* translators: %d: deleted cache files */ __( 'Acelora cache cleared. %d cached files removed.', 'acelora-site-accelerator' ), $deleted ) ) . '

'; } } /** * Resolve the current browser URL. * * @return string */ private function current_url() { $scheme = is_ssl() ? 'https://' : 'http://'; $host = isset( $_SERVER['HTTP_HOST'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_HOST'] ) ) : wp_parse_url( home_url(), PHP_URL_HOST ); $uri = isset( $_SERVER['REQUEST_URI'] ) ? esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '/'; return esc_url_raw( $scheme . $host . $uri ); } /** * Open settings form. * * @return void */ private function settings_form_open() { ?>
'; } /** * Submit button. * * @return void */ private function submit() { echo '

'; } /** * Render a metric card. * * @param string $label Label. * @param string $value Value. * @param string $meta Meta text. * @return void */ private function card( $label, $value, $meta ) { ?>
field_name( $path ); $value = $this->plugin->settings()->get( $path, 0 ); echo ''; } /** * Text field. * * @param string $path Setting path. * @param string $label Label. * @param string $placeholder Placeholder. * @return void */ private function text( $path, $label, $placeholder = '' ) { echo ''; } /** * Number field. * * @param string $path Setting path. * @param string $label Label. * @param int $min Minimum. * @return void */ private function number( $path, $label, $min = 0 ) { echo ''; } /** * Textarea field. * * @param string $path Setting path. * @param string $label Label. * @return void */ private function textarea( $path, $label ) { echo ''; } /** * Select field. * * @param string $path Setting path. * @param string $label Label. * @param array $options Options. * @return void */ private function select( $path, $label, $options ) { $current = $this->plugin->settings()->get( $path, '' ); echo ''; } /** * Convert dot path to input name. * * @param string $path Path. * @return string */ private function field_name( $path ) { $parts = explode( '.', $path ); $name = 'acelora_site_accelerator'; foreach ( $parts as $part ) { $name .= '[' . $part . ']'; } return $name; } /** * Set nested array value by dot path. * * @param array $settings Settings. * @param string $path Dot path. * @param mixed $value Value. * @return void */ private function set_path( &$settings, $path, $value ) { $parts = explode( '.', $path ); $ref = &$settings; foreach ( $parts as $part ) { if ( ! isset( $ref[ $part ] ) || ! is_array( $ref[ $part ] ) ) { $ref[ $part ] = array(); } $ref = &$ref[ $part ]; } $ref = $value; } /** * Checkbox setting paths. * * @return array */ private function checkbox_paths() { return array( 'cache.enabled', 'cache.mobile_cache', 'cache.logged_in_cache', 'preload.enabled', 'browser.enabled', 'browser.etags', 'css.minify', 'js.minify', 'js.defer', 'js.async', 'js.delay', 'images.optimize_uploads', 'images.webp', 'images.lazy', 'lazy.images', 'lazy.iframes', 'lazy.videos', 'cdn.enabled', 'compression.enabled', 'automation.enabled', 'heartbeat.admin', 'heartbeat.frontend', 'heartbeat.editor', 'logging.enabled', ); } /** * Schedule options. * * @return array */ private function schedule_options() { return array( 'hourly' => __( 'Hourly', 'acelora-site-accelerator' ), 'twicedaily' => __( 'Twice Daily', 'acelora-site-accelerator' ), 'daily' => __( 'Daily', 'acelora-site-accelerator' ), 'weekly' => __( 'Weekly', 'acelora-site-accelerator' ), 'monthly' => __( 'Monthly', 'acelora-site-accelerator' ), ); } }