The output buffer in adsense-delay.php was causing conflicts with
zlib compression buffer, resulting in ads being generated but not
appearing in final HTML.
Root cause: Multiple output buffers (zlib + adsense-delay) were
nested improperly, causing ob_end_flush() failures and content loss.
Solution: Disable the output buffer since AdsensePlacementRenderer
already generates scripts with type="text/plain" data-adsense-push.
The buffer was redundant and only needed for external AdSense sources.
Debug logs confirmed:
- Filter generates ads correctly (598+601 chars)
- Content exists after filter (54765 chars)
- But ads missing in final HTML (0 roi-ad-slot found)
- ob_end_flush() errors in debug.log
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Change roi_delay_adsense_scripts() to read from 'adsense-placement' component
- Change roi_add_adsense_init_script() to use same settings source
- Use 'forms.delay_enabled' field path instead of 'visibility.is_enabled'
- Add clarifying comments about output buffer purpose
The 'adsense-delay' component was never created in the database, causing
the delay functions to always use default values. Now properly reads
from the existing 'adsense-placement' component settings.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changed AdSense injection filter from priority 100 to 150 to ensure
it runs AFTER restrict-content-pro's rcp_filter_restricted_content
filter which also uses priority 100.
This should fix ads not appearing in post content.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Additional debug info:
- Log post_id and URL to identify which post is being processed
- Log first 200 chars of postTopHtml to verify content
- Log final content length
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added error_log statements to roi_inject_content_ads() to trace:
- Function entry point
- Conditions failing (is_single, in_the_loop, is_main_query)
- Container null check
- Settings loaded status
- Post exclusion check
- Rendered slot lengths
- Any exceptions with full trace
This will help identify why ads are not appearing on production
despite all database settings being correctly configured.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The $container variable was being assigned inside a try-catch block
without being declared as global first, making it unavailable to
Inc/adsense-placement.php functions. This caused AdSense slots to
not be injected into the content.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- CSS Personalizado card on left column (10 rows textarea)
- JavaScript Personalizado card on right column (Header + Footer)
- Improved visual organization with separate alerts per card
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Remove Analytics and AdSense tabs from theme-settings component
- Add Analytics group to adsense-placement component
- Add roi_enqueue_analytics_script() for GA4/UA support
- Clean up ThemeSettings to only handle custom code (CSS/JS)
- Update FormBuilders and FieldMappers accordingly
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Generates HTML files for visual comparison before/after
correction. Creates comparison_report.html for review.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Robust HTML list structure correction using PHP DOM parser.
Three modes: scan (detect), test (preview), fix (apply).
Properly moves nested lists inside parent <li> elements.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Demonstrates proposed regex replacement pattern without
applying changes. For validation before mass update.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Phase 4.4 Accessibility: Script to scan database for posts
with invalid list structures (<ul> containing non-<li> children).
Read-only analysis, no modifications.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Phase 4.4 Accessibility fixes:
- ContactFormRenderer: Change h6 info-labels to span (WhatsApp, Email, Location)
- RelatedPostRenderer: Change h5 card-title to span (semantic hierarchy)
- top-notification-bar schema: Change link_url default from # to /suscripcion-vip
(identical links must have same destination)
Fixes: "Headings not in sequential order" and "Identical links have different purposes"
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changed button_text_color from #FF8600 to #0E2337 (navy-dark)
- Orange on white had only 2.9:1 contrast ratio
- Navy-dark on white provides 12.6:1 contrast ratio (WCAG AAA)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Phase 4.4 PageSpeed Accessibility fixes:
- cta-box-sidebar: title/description colors from white to navy-dark (#0E2337)
- contact-form: info_value_color from #D5D8DA to #495057, button text to navy-dark
- cta-lets-talk: text_color from white to navy-dark
- css-tablas-apu: .c3 column color from #6c757d to #495057 (7.0:1 ratio)
All changes ensure minimum 4.5:1 contrast ratio for normal text (WCAG AA).
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Phase 4.4 Accessibility:
- Change white text to navy-dark on orange table headers (ratio 4.8:1)
- Fix subtotal rows in APU tables: orange text to navy for better contrast
- Affects styles 2, 5, 7, 10 in generic tables
- Fixes PageSpeed accessibility warnings
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Agregar preload de Poppins regular (400) y semibold (600)
- Agregar fallback font con size-adjust para minimizar layout shift
- Actualizar font stack con 'Poppins Fallback'
Impacto esperado: CLS 0.133 → ~0.05-0.08
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add enable_page_level_ads: false to prevent Google from
automatically inserting ads in unwanted locations
- This prevents ads from appearing inside table cells and
other inappropriate places
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Registra filtro the_content para inyectar anuncios (post-top, post-bottom, content)
- Corrige CSS del contenedor .roi-ad-slot con width:100% para evitar availableWidth=0
- Usa ContentAdInjector para insertar ads dentro del contenido
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Changed condition from is_single() to is_singular() to ensure
YouTube facade assets load on all singular content types.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- 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 <noreply@anthropic.com>
- Replace YouTube iframes with lightweight facade (thumbnail + play button)
- Load real iframe only on user click
- Reduces TBT by ~2000ms
- Uses youtube-nocookie.com for privacy-enhanced mode
- Made regex more flexible to handle various attribute orders
- Added quick check before regex processing
- Added null check for preg_replace_callback result
- Supports both single and double quotes in src attribute
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
PageSpeed Optimization to reduce TBT by ~2000ms:
- Add YoutubeFacade module following Clean Architecture
- Replace YouTube iframes with thumbnail + play button
- Load real iframe only on user click (lazy-load)
- Reduces initial page blocking time significantly
Files added:
- Public/YoutubeFacade/Infrastructure/Wordpress/YoutubeFacadeHooksRegistrar.php
- Public/YoutubeFacade/Infrastructure/Services/YoutubeFacadeContentFilter.php
- Public/YoutubeFacade/Infrastructure/Ui/YoutubeFacadeRenderer.php
- Public/YoutubeFacade/Infrastructure/Ui/Assets/Css/youtube-facade.css
- Public/YoutubeFacade/Infrastructure/Ui/Assets/Js/youtube-facade.js
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add roi_output_hero_critical_css() function to inject CSS in <head>
- CSS now loads BEFORE hero HTML renders, preventing CLS
- Update min_height from 120px to 260px to match actual content height
- Update title_min_height from 3rem to 3.5rem
- Add responsive breakpoints for mobile (200px min-height)
This fixes CLS in Lighthouse Lab tests (was 0.265, now should be ~0.01)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Cambiar '/schemas' a '/Schemas' en MigrationCommand.php
- Permite que wp roi-theme sync_component funcione en servidores Linux
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Leer campos min_height, title_min_height, badge_min_height del schema
- Aplicar min-height a .hero-section (120px)
- Aplicar min-height a .hero-section__title (3rem)
- Aplicar min-height a .hero-section__badge (32px)
Fase 1 del plan de optimización PageSpeed (99-pagespeed-optimization-plan.md)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
PROBLEMA:
- El modal de contacto no se mostraba en producción (Linux)
- Funcionaba en local (Windows) porque filesystem es case-insensitive
- Carpeta: `WordPress` (con P mayúscula)
- Namespaces: `Wordpress` (con p minúscula)
SOLUCION:
- Corregir todos los namespaces de `Wordpress` a `WordPress`
- También corregir paths incorrectos `ROITheme\Component\...` a `ROITheme\Shared\...`
ARCHIVOS CORREGIDOS (14):
- functions.php
- Admin/Infrastructure/Api/WordPress/AdminMenuRegistrar.php
- Admin/Shared/Infrastructure/Api/WordPress/AdminAjaxHandler.php
- Public/ContactForm/Infrastructure/Api/WordPress/ContactFormAjaxHandler.php
- Public/Footer/Infrastructure/Api/WordPress/NewsletterAjaxHandler.php
- Shared/Infrastructure/Api/WordPress/AjaxController.php
- Shared/Infrastructure/Api/WordPress/MigrationCommand.php
- Shared/Infrastructure/Di/DIContainer.php
- Shared/Infrastructure/Persistence/WordPress/WordPressComponentRepository.php
- Shared/Infrastructure/Persistence/WordPress/WordPressComponentSettingsRepository.php
- Shared/Infrastructure/Persistence/WordPress/WordPressDefaultsRepository.php
- Shared/Infrastructure/Services/CleanupService.php
- Shared/Infrastructure/Services/SchemaSyncService.php
- Shared/Infrastructure/Services/WordPressValidationService.php
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>