From b43cb22dc1fa33dec512a1ff1232256e67678ebf Mon Sep 17 00:00:00 2001 From: FrankZamora Date: Thu, 27 Nov 2025 14:05:34 -0600 Subject: [PATCH] feat(youtube-facade): Phase 2.4 complete - YouTube Facade for PageSpeed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Replace YouTube iframes with lightweight facade (thumbnail + play button) - Load real iframe only on user click - Reduces TBT by ~2000ms - Works with mu-plugin allow-unfiltered-html.php - Filter priority 101 (after RCP) šŸ¤– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../Services/YoutubeFacadeContentFilter.php | 29 ++----------------- .../Ui/YoutubeFacadeRenderer.php | 2 -- .../Wordpress/YoutubeFacadeHooksRegistrar.php | 5 ---- functions.php | 18 ------------ 4 files changed, 3 insertions(+), 51 deletions(-) diff --git a/Public/YoutubeFacade/Infrastructure/Services/YoutubeFacadeContentFilter.php b/Public/YoutubeFacade/Infrastructure/Services/YoutubeFacadeContentFilter.php index d2eea249..badd8b3b 100644 --- a/Public/YoutubeFacade/Infrastructure/Services/YoutubeFacadeContentFilter.php +++ b/Public/YoutubeFacade/Infrastructure/Services/YoutubeFacadeContentFilter.php @@ -32,42 +32,19 @@ final class YoutubeFacadeContentFilter */ public function filter(string $content): string { - // Temporary debug - file_put_contents('/tmp/yt-debug.log', date('H:i:s') . " filter called\n", FILE_APPEND); - - // Check if content has YouTube embeds at all (quick check) + // Quick check: skip if no YouTube embeds if (strpos($content, 'youtube.com/embed/') === false && strpos($content, 'youtube-nocookie.com/embed/') === false) { - file_put_contents('/tmp/yt-debug.log', date('H:i:s') . " no youtube found\n", FILE_APPEND); return $content; } - file_put_contents('/tmp/yt-debug.log', date('H:i:s') . " youtube FOUND\n", FILE_APPEND); // Pattern to match YouTube iframes // Handles: youtube.com/embed/ and youtube-nocookie.com/embed/ - // More flexible: allows any attributes in any order, whitespace variations $pattern = '/]*src=["\']https?:\/\/(?:www\.)?(?:youtube\.com|youtube-nocookie\.com)\/embed\/([a-zA-Z0-9_-]+)[^"\']*["\'][^>]*>\s*<\/iframe>/is'; - // Debug: test pattern - $matchCount = preg_match_all($pattern, $content, $testMatches); - file_put_contents('/tmp/yt-debug.log', date('H:i:s') . " Pattern matches: " . $matchCount . " videos: " . implode(',', $testMatches[1] ?? []) . "\n", FILE_APPEND); - $result = preg_replace_callback($pattern, function ($matches) { - $videoId = $matches[1]; - file_put_contents('/tmp/yt-debug.log', date('H:i:s') . " Replacing video: " . $videoId . "\n", FILE_APPEND); - return $this->renderer->render($videoId); + return $this->renderer->render($matches[1]); }, $content); - // Return original content if regex failed - if ($result === null) { - file_put_contents('/tmp/yt-debug.log', date('H:i:s') . " preg_replace FAILED (null)\n", FILE_APPEND); - return $content; - } - - // Debug: verify facades in result - $facadeCount = substr_count($result, 'data-video-id'); - $iframeCount = substr_count($result, 'youtube.com/embed'); - file_put_contents('/tmp/yt-debug.log', date('H:i:s') . " RESULT: {$facadeCount} facades, {$iframeCount} iframes remaining\n", FILE_APPEND); - - return $result; + return $result ?? $content; } } diff --git a/Public/YoutubeFacade/Infrastructure/Ui/YoutubeFacadeRenderer.php b/Public/YoutubeFacade/Infrastructure/Ui/YoutubeFacadeRenderer.php index 95fb9c8e..7860df54 100644 --- a/Public/YoutubeFacade/Infrastructure/Ui/YoutubeFacadeRenderer.php +++ b/Public/YoutubeFacade/Infrastructure/Ui/YoutubeFacadeRenderer.php @@ -50,8 +50,6 @@ final class YoutubeFacadeRenderer HTML; - file_put_contents('/tmp/yt-debug.log', date('H:i:s') . " Renderer output length: " . strlen($html) . " chars\n", FILE_APPEND); - file_put_contents('/tmp/yt-debug.log', date('H:i:s') . " Renderer output: " . substr($html, 0, 100) . "...\n", FILE_APPEND); return $html; } } diff --git a/Public/YoutubeFacade/Infrastructure/Wordpress/YoutubeFacadeHooksRegistrar.php b/Public/YoutubeFacade/Infrastructure/Wordpress/YoutubeFacadeHooksRegistrar.php index 35b2761e..949cfda9 100644 --- a/Public/YoutubeFacade/Infrastructure/Wordpress/YoutubeFacadeHooksRegistrar.php +++ b/Public/YoutubeFacade/Infrastructure/Wordpress/YoutubeFacadeHooksRegistrar.php @@ -31,15 +31,10 @@ final class YoutubeFacadeHooksRegistrar */ public function register(): void { - // Debug: Log that registration is happening - file_put_contents('/tmp/yt-debug.log', date('H:i:s') . " HooksRegistrar::register() called\n", FILE_APPEND); - // Filter post content to replace YouTube iframes with facades // Priority 101 = after rcp_filter_restricted_content (100) add_filter('the_content', [$this->contentFilter, 'filter'], 101); - file_put_contents('/tmp/yt-debug.log', date('H:i:s') . " the_content filter registered\n", FILE_APPEND); - // Enqueue facade assets add_action('wp_enqueue_scripts', [$this, 'enqueueAssets'], 15); } diff --git a/functions.php b/functions.php index 7b15ad8a..d81e9d2b 100644 --- a/functions.php +++ b/functions.php @@ -94,11 +94,8 @@ use ROITheme\Admin\Infrastructure\Api\WordPress\AdminMenuRegistrar; use ROITheme\Admin\Infrastructure\Services\AdminAssetEnqueuer; try { - file_put_contents('/tmp/yt-debug.log', date('H:i:s') . " [1] Try block started\n", FILE_APPEND); - // Obtener Use Case para cargar configuraciones $getComponentSettingsUseCase = $container?->getGetComponentSettingsUseCase(); - file_put_contents('/tmp/yt-debug.log', date('H:i:s') . " [2] getComponentSettingsUseCase OK\n", FILE_APPEND); // Crear MenuItem con configuración del panel $menuItem = new MenuItem( @@ -124,8 +121,6 @@ try { $adminAssetEnqueuer = new AdminAssetEnqueuer(get_template_directory_uri()); $adminAssetEnqueuer->register(); - file_put_contents('/tmp/yt-debug.log', date('H:i:s') . " [3] Admin panel registered\n", FILE_APPEND); - // Obtener Use Case para guardar configuraciones $saveComponentSettingsUseCase = $container?->getSaveComponentSettingsUseCase(); @@ -153,8 +148,6 @@ try { ); $newsletterAjaxHandler->register(); - file_put_contents('/tmp/yt-debug.log', date('H:i:s') . " [4] Newsletter handler registered\n", FILE_APPEND); - // Crear y registrar el inyector de Theme Settings (GA, Custom CSS/JS) $themeSettingsRenderer = new \ROITheme\Public\ThemeSettings\Infrastructure\Ui\ThemeSettingsRenderer(); $themeSettingsInjector = new \ROITheme\Public\ThemeSettings\Infrastructure\Services\ThemeSettingsInjector( @@ -163,26 +156,16 @@ try { ); $themeSettingsInjector->register(); - file_put_contents('/tmp/yt-debug.log', date('H:i:s') . " [5] ThemeSettings registered\n", FILE_APPEND); - // === YOUTUBE FACADE (PageSpeed Optimization Phase 2.4) === - file_put_contents('/tmp/yt-debug.log', date('H:i:s') . " [6] About to create YoutubeFacade classes\n", FILE_APPEND); // Lazy-load YouTube iframes to reduce TBT by ~2000ms $youtubeFacadeRenderer = new \ROITheme\Public\YoutubeFacade\Infrastructure\Ui\YoutubeFacadeRenderer(); - file_put_contents('/tmp/yt-debug.log', date('H:i:s') . " [7] YoutubeFacadeRenderer created\n", FILE_APPEND); - $youtubeFacadeFilter = new \ROITheme\Public\YoutubeFacade\Infrastructure\Services\YoutubeFacadeContentFilter( $youtubeFacadeRenderer ); - file_put_contents('/tmp/yt-debug.log', date('H:i:s') . " [8] YoutubeFacadeContentFilter created\n", FILE_APPEND); - $youtubeFacadeHooksRegistrar = new \ROITheme\Public\YoutubeFacade\Infrastructure\Wordpress\YoutubeFacadeHooksRegistrar( $youtubeFacadeFilter ); - file_put_contents('/tmp/yt-debug.log', date('H:i:s') . " [9] YoutubeFacadeHooksRegistrar created\n", FILE_APPEND); - $youtubeFacadeHooksRegistrar->register(); - file_put_contents('/tmp/yt-debug.log', date('H:i:s') . " [10] YoutubeFacade registered successfully\n", FILE_APPEND); // Log en modo debug if (defined('WP_DEBUG') && WP_DEBUG) { @@ -191,7 +174,6 @@ try { } catch (\Throwable $e) { // Manejar errores de inicialización del panel - file_put_contents('/tmp/yt-debug.log', date('H:i:s') . " [CATCH] Exception: " . $e->getMessage() . " in " . $e->getFile() . ":" . $e->getLine() . "\n", FILE_APPEND); if (defined('WP_DEBUG') && WP_DEBUG) { error_log('ROI Theme: Failed to initialize Admin Panel: ' . $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine()); }