admin_loader = $admin_loader ?? new Simple_Admin_Asset_Loader(); $this->frontend_loader = $frontend_loader ?? new Frontend_Asset_Loader(); $this->asset_optimizer = $asset_optimizer; $this->cache_manager = $cache_manager; $this->setup_configuration(); } /** * Initializes all asset loading hooks */ public function init(): void { add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_assets' ) ); add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_frontend_assets' ) ); // Only add lazy loading hooks if enabled. if ( $this->lazy_loading_enabled ) { add_action( 'wp_footer', array( $this, 'enqueue_lazy_assets' ), 20 ); add_action( 'admin_footer', array( $this, 'enqueue_lazy_admin_assets' ), 20 ); } // Cache management hooks (only if user can manage options). if ( current_user_can( 'manage_options' ) ) { add_action( 'wp_ajax_accessibility_audio_tts_clear_asset_cache', array( $this, 'handle_clear_cache_request' ) ); } // Asset optimization hooks (defer to avoid early instantiation). add_action( 'init', array( $this, 'setup_optimization_hooks' ), 20 ); } /** * Setup optimization hooks after init. */ public function setup_optimization_hooks(): void { if ( $this->minification_enabled && $this->get_asset_optimizer() ) { add_filter( 'accessibility_audio_tts_asset_content', array( $this->get_asset_optimizer(), 'minify_asset' ), 10, 2 ); } } /** * Handles admin asset enqueuing with optimizations. * * @param string $hook Current admin page hook. */ public function enqueue_admin_assets( $hook ): void { try { // Get critical admin assets first. $critical_assets = $this->get_critical_admin_assets( (string) $hook ); foreach ( $critical_assets as $asset ) { $this->enqueue_optimized_asset( $asset ); } // Queue non-critical assets for lazy loading. if ( $this->lazy_loading_enabled ) { $lazy_assets = $this->get_lazy_admin_assets( (string) $hook ); $this->queue_lazy_assets( $lazy_assets ); } } catch ( \Throwable $e ) { // Log error but don't break the site. if ( function_exists( 'accessibility_audio_tts_debug_log' ) ) { accessibility_audio_tts_debug_log( 'Asset Manager error in admin assets: ' . $e->getMessage() ); } } // Always call original loader for compatibility. $this->admin_loader->enqueue_admin_assets( $hook ); } /** * Handles frontend asset enqueuing with optimizations */ public function enqueue_frontend_assets(): void { try { // Get critical frontend assets first. $critical_assets = $this->get_critical_frontend_assets(); foreach ( $critical_assets as $asset ) { $this->enqueue_optimized_asset( $asset ); } // Queue non-critical assets for lazy loading. if ( $this->lazy_loading_enabled ) { $lazy_assets = $this->get_lazy_frontend_assets(); $this->queue_lazy_assets( $lazy_assets ); } } catch ( \Throwable $e ) { // Log error but don't break the site. if ( function_exists( 'accessibility_audio_tts_debug_log' ) ) { accessibility_audio_tts_debug_log( 'Asset Manager error in frontend assets: ' . $e->getMessage() ); } } // Always fallback to original loader for compatibility. $this->frontend_loader->enqueue_frontend_assets(); } /** * Enqueue lazy-loaded assets in footer */ public function enqueue_lazy_assets(): void { if ( ! $this->lazy_loading_enabled || empty( $this->lazy_loaded_assets ) ) { return; } foreach ( $this->lazy_loaded_assets as $asset ) { if ( 'frontend' === $asset['context'] ) { $this->enqueue_optimized_asset( $asset ); } } } /** * Enqueue lazy-loaded admin assets in admin footer */ public function enqueue_lazy_admin_assets(): void { if ( ! $this->lazy_loading_enabled || empty( $this->lazy_loaded_assets ) ) { return; } foreach ( $this->lazy_loaded_assets as $asset ) { if ( 'admin' === $asset['context'] ) { $this->enqueue_optimized_asset( $asset ); } } } /** * Enqueue asset with optimizations. * * @param array $asset Asset configuration. */ private function enqueue_optimized_asset( array $asset ): void { $handle = $asset['handle']; $src = $asset['src']; $deps = $asset['deps'] ?? array(); $version = $asset['version'] ?? ACCESSIBILITY_AUDIO_TTS_VERSION; $type = $asset['type']; // Type: script or style. // Apply cache busting. if ( $this->cache_busting_enabled && $this->get_cache_manager() ) { $version = $this->get_cache_manager()->get_cache_busted_version( $src, $version ); } // Get optimized asset URL. $optimized_src = $this->get_optimized_asset_url( $src, $type ); // Enqueue the asset. if ( 'script' === $type ) { wp_enqueue_script( $handle, $optimized_src, $deps, $version, $asset['in_footer'] ?? true ); // Add localization if provided. if ( ! empty( $asset['localize'] ) ) { wp_localize_script( $handle, $asset['localize']['object'], $asset['localize']['data'] ); } } else { wp_enqueue_style( $handle, $optimized_src, $deps, $version, $asset['media'] ?? 'all' ); } } /** * Get optimized asset URL. * * @param string $src Original asset URL. * @param string $type Asset type (script/style). * @return string Optimized asset URL. */ private function get_optimized_asset_url( string $src, string $type ): string { if ( ! $this->minification_enabled || ! $this->get_asset_optimizer() ) { return $src; } // Check if minified version exists. $minified_src = $this->get_asset_optimizer()->get_minified_url( $src, $type ); if ( $minified_src && $this->asset_exists( $minified_src ) ) { return $minified_src; } // Generate minified version if needed. if ( $this->should_minify_asset( $src ) ) { return $this->get_asset_optimizer()->create_minified_version( $src, $type ); } return $src; } /** * Queue assets for lazy loading. * * @param array $assets Assets to queue. */ private function queue_lazy_assets( array $assets ): void { $this->lazy_loaded_assets = array_merge( $this->lazy_loaded_assets, $assets ); } /** * Get critical admin assets for immediate loading. * * @param string $hook Admin page hook. * @return array Critical assets. */ private function get_critical_admin_assets( string $hook ): array { $critical_assets = array(); // AAT admin pages. if ( false !== strpos( $hook, 'accessibility-audio-tts' ) ) { $critical_assets[] = array( 'handle' => 'accessibility-audio-tts-audio-admin-critical', 'src' => ACCESSIBILITY_AUDIO_TTS_ASSETS_URL . 'admin/admin-compiled.min.css', 'type' => 'style', 'deps' => array(), 'version' => accessibility_audio_tts_get_asset_version( 'assets/admin/admin-compiled.min.css' ), ); } return $critical_assets; } /** * Get lazy-loaded admin assets. * * @param string $hook Admin page hook. * @return array Lazy assets. */ private function get_lazy_admin_assets( string $hook ): array { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found -- Parameter reserved for future use. // No lazy admin assets are required. return array(); } /** * Get critical frontend assets. * * @return array Critical assets. */ private function get_critical_frontend_assets(): array { return array( array( 'handle' => 'accessibility-audio-tts-audio-player-critical', 'src' => ACCESSIBILITY_AUDIO_TTS_PLUGIN_URL . 'assets/public/player-critical.min.css', 'type' => 'style', 'deps' => array(), 'version' => ACCESSIBILITY_AUDIO_TTS_VERSION, ), ); } /** * Get lazy-loaded frontend assets. * * @return array Lazy assets. */ private function get_lazy_frontend_assets(): array { return array( array( 'handle' => 'accessibility-audio-tts-player-core', 'src' => ACCESSIBILITY_AUDIO_TTS_PLUGIN_URL . 'assets/public/player/player-core.min.js', 'type' => 'script', 'deps' => array( 'jquery' ), 'context' => 'frontend', 'in_footer' => true, ), ); } /** * Check if asset file exists. * * @param string $url Asset URL. * @return bool True if asset exists. */ private function asset_exists( string $url ): bool { // Convert URL to file path. $file_path = str_replace( ACCESSIBILITY_AUDIO_TTS_PLUGIN_URL, ACCESSIBILITY_AUDIO_TTS_PLUGIN_DIR, $url ); return file_exists( $file_path ); } /** * Check if asset should be minified. * * @param string $src Asset source URL. * @return bool True if should minify. */ private function should_minify_asset( string $src ): bool { // Don't minify already minified files. if ( false !== strpos( $src, '.min.' ) ) { return false; } // Don't minify external assets. if ( false === strpos( $src, ACCESSIBILITY_AUDIO_TTS_PLUGIN_URL ) ) { return false; } return true; } /** * Get asset optimizer instance (lazy loading) * * @return Asset_Optimizer|null */ private function get_asset_optimizer(): ?Asset_Optimizer { if ( null === $this->asset_optimizer ) { // Try to load the class if it doesn't exist. if ( ! class_exists( __NAMESPACE__ . '\\Asset_Optimizer' ) ) { $optimizer_file = __DIR__ . '/class-asset-optimizer.php'; if ( file_exists( $optimizer_file ) ) { require_once $optimizer_file; } } if ( class_exists( __NAMESPACE__ . '\\Asset_Optimizer' ) ) { $this->asset_optimizer = new Asset_Optimizer(); } } return $this->asset_optimizer; } /** * Get cache manager instance (lazy loading) * * @return Asset_Cache_Manager|null */ private function get_cache_manager(): ?Asset_Cache_Manager { if ( null === $this->cache_manager ) { // Try to load the class if it doesn't exist. if ( ! class_exists( __NAMESPACE__ . '\\Asset_Cache_Manager' ) ) { $cache_manager_file = __DIR__ . '/class-asset-cache-manager.php'; if ( file_exists( $cache_manager_file ) ) { require_once $cache_manager_file; } } if ( class_exists( __NAMESPACE__ . '\\Asset_Cache_Manager' ) ) { $this->cache_manager = new Asset_Cache_Manager(); } } return $this->cache_manager; } /** * Setup configuration from options */ private function setup_configuration(): void { $options = get_option( 'accessibility_audio_tts_asset_settings', array() ); $this->lazy_loading_enabled = $options['lazy_loading'] ?? true; $this->minification_enabled = $options['minification'] ?? true; $this->cache_busting_enabled = $options['cache_busting'] ?? true; } /** * Handle cache clear request */ public function handle_clear_cache_request(): void { try { if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => __( 'Insufficient permissions', 'accessibility-audio-tts-text-to-speech-for-articles' ) ) ); return; } $nonce_val = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : ''; if ( ! wp_verify_nonce( $nonce_val, 'accessibility_audio_tts_clear_cache' ) ) { wp_send_json_error( array( 'message' => __( 'Invalid nonce', 'accessibility-audio-tts-text-to-speech-for-articles' ) ) ); return; } $cleared = array(); if ( $this->get_cache_manager() ) { $this->get_cache_manager()->clear_all_cache(); $cleared[] = 'cache'; } if ( $this->get_asset_optimizer() ) { $this->get_asset_optimizer()->clear_minified_cache(); $cleared[] = 'minified assets'; } $message = empty( $cleared ) ? __( 'No cache to clear', 'accessibility-audio-tts-text-to-speech-for-articles' ) /* translators: auto */ : sprintf( __( 'Cleared: %s', 'accessibility-audio-tts-text-to-speech-for-articles' ), implode( ', ', $cleared ) ); wp_send_json_success( array( 'message' => $message ) ); } catch ( \Throwable $e ) { wp_send_json_error( array( 'message' => __( 'Error clearing cache', 'accessibility-audio-tts-text-to-speech-for-articles' ), 'error' => $e->getMessage(), ) ); } } /** * Enable/disable lazy loading. * * @param bool $enabled Whether to enable lazy loading. */ public function set_lazy_loading_enabled( bool $enabled ): void { $this->lazy_loading_enabled = $enabled; $this->update_asset_settings(); } /** * Enable/disable minification. * * @param bool $enabled Whether to enable minification. */ public function set_minification_enabled( bool $enabled ): void { $this->minification_enabled = $enabled; $this->update_asset_settings(); } /** * Enable/disable cache busting. * * @param bool $enabled Whether to enable cache busting. */ public function set_cache_busting_enabled( bool $enabled ): void { $this->cache_busting_enabled = $enabled; $this->update_asset_settings(); } /** * Update asset settings in database */ private function update_asset_settings(): void { $settings = array( 'lazy_loading' => $this->lazy_loading_enabled, 'minification' => $this->minification_enabled, 'cache_busting' => $this->cache_busting_enabled, ); update_option( 'accessibility_audio_tts_asset_settings', $settings ); } /** * Get asset performance statistics. * * @return array Performance stats. */ public function get_performance_stats(): array { $stats = array( 'lazy_loading_enabled' => $this->lazy_loading_enabled, 'minification_enabled' => $this->minification_enabled, 'cache_busting_enabled' => $this->cache_busting_enabled, 'lazy_loaded_count' => count( $this->lazy_loaded_assets ), ); if ( $this->get_cache_manager() ) { $stats['cache_stats'] = $this->get_cache_manager()->get_cache_stats(); } if ( $this->get_asset_optimizer() ) { $stats['optimization_stats'] = $this->get_asset_optimizer()->get_optimization_stats(); } return $stats; } }