Commit Graph

407 Commits

Author SHA1 Message Date
FrankZamora
a2dfd10f9e fix(js): implement google official css for unfilled adsense slots
Remove eager loading, revert to Intersection Observer with 600px
rootMargin. Use google css: ins[data-ad-status=unfilled]{display:none}

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 17:29:44 -06:00
FrankZamora
5971f2c971 feat(js): switch to eager loading to eliminate layout shift
Instead of lazy loading slots when they enter the viewport (which
causes layout shift when unfilled slots collapse), now all slots
are activated immediately on page load.

- Slots start collapsed (max-height:0, opacity:0) via CSS
- All slots are activated with 100ms stagger to avoid rate limiting
- Only slots confirmed as 'filled' expand and become visible
- Unfilled slots remain collapsed - zero layout shift

This completely eliminates the CLS issue where content would jump
when ad slots were hidden after entering the viewport.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 17:11:08 -06:00
FrankZamora
a4f63145dd fix(css): collapse ad slots initially to prevent layout shift
- Slots start with max-height:0, opacity:0, margin:0 (no visual space)
- Only expand when AdSense confirms filled status
- Use transition for smooth appearance
- Prevents layout shift when unfilled slots are hidden
- Combined with larger rootMargin (1000px) slots are pre-loaded
  before entering viewport, eliminating visible collapse

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 17:02:29 -06:00
FrankZamora
88103a774b perf(js): use fast polling for fill detection
Replace MutationObserver with 50ms polling strategy.
AdSense sets data-ad-status very quickly after iframe,
but MutationObserver sometimes has delays.

Max polling: 3s (60 attempts * 50ms)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 16:52:06 -06:00
FrankZamora
ffc22a21ea chore: bump version to 1.0.23 for cache busting 2025-12-10 16:44:55 -06:00
FrankZamora
ed45a9c821 fix(js): only use data-ad-status to determine slot fill state
AdSense injects iframe BEFORE setting data-ad-status, so using iframe
presence as fill indicator causes false positives. Slots with unfilled
ads were incorrectly marked as filled because iframe was detected first.

Now only data-ad-status is used for final state determination. If
data-ad-status is not yet set, the MutationObserver continues waiting.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 16:28:57 -06:00
FrankZamora
89a4fc5133 fix(php): use visibility+min-height instead of display:none for lazy slots
IntersectionObserver cannot detect elements with display:none because
they have 0x0 dimensions. Changed CSS approach to use visibility:hidden
with min-height:1px so IO can observe slots entering the viewport.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 16:11:42 -06:00
FrankZamora
449e2e1740 fix(php): use filter_var for proper boolean casting in config 2025-12-10 16:04:35 -06:00
FrankZamora
a2c4f857be fix(php): use wp_add_inline_script for defer compatibility
wp_localize_script doesn't work correctly with WordPress 6.3+
when using strategy => 'defer'. Switch to wp_add_inline_script
with 'before' position to ensure roiAdsenseConfig is defined
before the deferred script executes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 15:57:31 -06:00
FrankZamora
179a83e9cd feat(js): implement intersection observer lazy loading for adsense
- Add per-slot lazy loading with Intersection Observer API
- Implement fill detection via MutationObserver and data-ad-status
- Add configurable rootMargin and fillTimeout from database
- Generate dynamic CSS based on lazy_loading_enabled setting
- Add legacy mode fallback for browsers without IO support
- Include backup of previous implementation (adsense-loader.legacy.js)
- Add OpenSpec documentation with test plan (72 tests verified)

Schema changes:
- Add lazy_loading_enabled (boolean, default: true)
- Add lazy_rootmargin (select: 0-500px, default: 200)
- Add lazy_fill_timeout (select: 3000-10000ms, default: 5000)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 15:48:20 -06:00
FrankZamora
555541b2a0 fix(js): wait for adsbygoogle.js before push scripts
Race condition caused push to execute before library loaded.
Add onload callback to loadAdSenseScripts() function.
2025-12-10 12:44:04 -06:00
FrankZamora
fae4def974 chore(js): enable adsense-loader debug mode temporarily 2025-12-10 12:40:29 -06:00
FrankZamora
8bbbf484bd chore(php): add temporary debug to content ad injector 2025-12-10 12:30:27 -06:00
FrankZamora
50c411408e fix(php): update formbuilder dropdown options for incontent ads
- Extend max ads dropdown from 15 to 25 options
- Add "1 elemento" option to min spacing dropdown
- Fix undefined variable $isLegacy, changed to $isParagraphsOnly

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 12:20:44 -06:00
FrankZamora
d7c9c2a801 feat(schema): expand ad limits and spacing options
- incontent_max_total_ads: add options 16-25
- incontent_min_spacing: add 1 elemento option
2025-12-10 12:14:54 -06:00
FrankZamora
30068ca01e chore(php): remove temporary debug from content ad injector 2025-12-10 12:09:52 -06:00
FrankZamora
959d76fd92 fix(php): rewrite forbidden zones detection with strpos 2025-12-10 11:52:44 -06:00
FrankZamora
04387d46bb fix(php): exclude tables and embeds from ad injection
- Add mapForbiddenZones() for tables, iframes, embeds
- Remove table from scannable elements pattern
- Filter positions inside forbidden zones
- Fixes ads inside table cells and YouTube embeds
2025-12-10 11:44:40 -06:00
FrankZamora
4f1e85fe88 chore(php): remove temporary debug comments from content ad injector 2025-12-10 11:39:36 -06:00
FrankZamora
2cb7363cbb fix(php): support advanced incontent slot names in renderer
The getLocationConfig regex only matched post_content_X but advanced
incontent uses post_content_adv_X format. Added new regex pattern.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 11:33:53 -06:00
FrankZamora
18bf3d191c chore: add detailed debug for inject advanced
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 11:29:28 -06:00
FrankZamora
09d87835b8 chore: add debug comment to diagnose mode
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-10 10:58:48 -06:00
FrankZamora
2896e2d006 feat(php): implement advanced in-content ads with multi-element targeting
- Add incontent_advanced group with 19 configurable fields in schema
- Support 5 density modes: paragraphs_only, conservative, balanced,
  aggressive, custom
- Enable ad placement after H2, H3, paragraphs, images, lists,
  blockquotes, and tables
- Add probability-based selection (25-100%) per element type
- Implement priority-based and position-based ad selection strategies
- Add detailed mode descriptions in admin UI for better UX
- Rename 'legacy' terminology to 'paragraphs_only' for clarity
- Support deterministic randomization using post_id + date seed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-10 10:42:53 -06:00
FrankZamora
c2fff49961 docs(config): add advanced incontent ads specification
- proposal.md: define problem and expected changes
- design.md: 9 technical decisions with rationale
- spec.md: complete GIVEN/WHEN/THEN scenarios
- tasks.md: implementation tasks with dependencies

Features specified:
- 7 ad insertion locations (H2, H3, p, img, lists, blockquotes, tables)
- 5 density modes (legacy, conservative, balanced, aggressive, custom)
- 2 selection strategies (position vs priority)
- Deterministic probability with daily seed
- Backward compatibility with legacy fields

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-09 19:58:50 -06:00
FrankZamora
85f3387fd2 perf(php): add conditional debug logging to prevent gb logs
- add ROI_DEBUG constant (default false) to control debug output
- create roi_debug_log() function for conditional logging
- replace all error_log DEBUG calls with roi_debug_log
- keep ERROR logs always active for exception tracking
- to enable debug, add define('ROI_DEBUG', true) in wp-config.php

this prevents production logs from growing to gb sizes
(previous error.log was 4.8gb from constant debug output)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 17:52:50 -06:00
FrankZamora
ff5ba25505 feat(php): implement cache-first architecture hook
Add CacheFirstHooksRegistrar that fires roi_theme_before_page_serve
hook on template_redirect priority 0 for singular pages.

- Only fires for anonymous users (cache doesn't apply to logged in)
- Only fires for singular pages (posts, pages, CPTs)
- Provides post_id to external plugins
- Does NOT define DONOTCACHEPAGE (allows page caching)

Plan 1000.01 implementation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 12:11:48 -06:00
FrankZamora
eab974d14c docs(config): add cache-first-architecture specification
Define arquitectura cache-first para ROI-Theme:
- Hook roi_theme_before_page_serve en template_redirect p=0
- Solo para páginas singulares y usuarios anónimos
- Permite que plugins externos evalúen acceso antes de servir página
- NO define DONOTCACHEPAGE (permite cache)

Plan 1000.01 - Preparación para integración con IP View Limit.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-07 12:07:14 -06:00
FrankZamora
b509b1a2b4 fix(php): toc fallback to raw content when filtered has no headings
When plugins like Thrive Visual Editor transform content for
non-logged users, headings may be removed from the filtered content.
This fix uses raw post_content as fallback when filtered content
has no headings but raw content does.

Also removes temporary debug logging added for diagnosis.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 23:08:24 -06:00
FrankZamora
83d113d669 chore(php): add more debug for toc heading detection
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 23:05:51 -06:00
FrankZamora
0c1908e7d1 chore(php): add toc debug logging for guest visibility issue
Temporary debug logging to diagnose why TOC shows for logged users
but not for guests. Logs visibility checks at each layer.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 23:03:42 -06:00
FrankZamora
5333531be4 fix(templates): add missing components to archive templates
- Add social-share component to category.php and archive.php
- Add related-post component to category.php and archive.php
- Now archive templates have same components as single.php

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 22:40:53 -06:00
FrankZamora
fb68f2023c fix(theme): improve post-grid spacing, pagination and archive templates
- Fix flexbox gap issue causing unequal horizontal/vertical spacing
- Reset Bootstrap row/col margins to use only CSS gap property
- Replace WordPress pagination with Bootstrap-style pagination
- Add cta-post component to category.php and archive.php templates
- Fix spacing controls UI with separate horizontal/vertical gap fields
- Update FieldMapper with new gap_horizontal and gap_vertical attributes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 22:26:19 -06:00
FrankZamora
79e91f59ee feat(theme): add [roi_post_grid] shortcode for static pages
- Create PostGridShortcodeRegistrar for WordPress shortcode registration
- Implement RenderPostGridUseCase following Clean Architecture
- Add PostGridQueryBuilder for custom WP_Query construction
- Add PostGridShortcodeRenderer for HTML/CSS generation
- Register shortcode in DIContainer with proper DI
- Add shortcode usage guide in post-grid admin panel
- Fix sidebar layout: add hide_for_logged_in check to wrapper visibility

Shortcode attributes: category, tag, author, posts_per_page, columns,
show_pagination, show_thumbnail, show_excerpt, show_meta, etc.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 21:33:20 -06:00
FrankZamora
c23dc22d76 feat(templates): add archive-header and post-grid components
- Add ArchiveHeader component (schema, renderer, formbuilder)
- Add PostGrid component (schema, renderer, formbuilder)
- Unify archive templates (home, archive, category, tag,
  author, date, search)
- Add page visibility system with VisibilityDefaults
- Register components in AdminDashboardRenderer
- Fix boolean conversion in functions-addon.php
- All 172 unit tests passed

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 20:36:27 -06:00
FrankZamora
b79569c5e7 docs: add templates-unificados openspec specification
Defines unified listing templates architecture.

Key additions:
- Two new components: archive-header, post-grid
- 10-phase implementation sequence
- _page_visibility group pattern
- Graceful handling of missing content
- CSS pagination via CSSGeneratorService

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 19:14:09 -06:00
FrankZamora
6be292e085 chore: eliminar related-posts.php legacy (plan 101 fase 3)
- eliminar inc/related-posts.php (reemplazado por relatedpostrenderer)
- eliminar require en functions.php

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 18:17:48 -06:00
FrankZamora
885276aad1 chore: purgar archivos legacy (plan 101 fase 2)
- eliminar 5 template parts reemplazados por renderers
- eliminar header.js (90% codigo muerto)
- eliminar apu-tables-auto-class.js (migrdo a php)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 18:11:04 -06:00
FrankZamora
1e6a076904 chore: purgar archivos no utilizados (plan 101 fase 1)
- eliminar carpetas vacias admin/herosection y bootstrapicons
- eliminar 7 scripts legacy con credenciales hardcodeadas
- eliminar formbuilder duplicado en shared/infrastructure/ui
- eliminar 11 archivos .gitkeep en carpetas con contenido

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-06 18:09:52 -06:00
FrankZamora
a33c43a104 fix(admin): corregir guardado customcssmanager con toast
- crear bootstrap para handler post en admin_init
- ocultar botones globales para custom-css-manager
- simplificar formbuilder eliminando handler duplicado
- reemplazar alert por toast para notificaciones

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-06 15:02:06 -06:00
FrankZamora
78d2ba57b9 fix(php): disable zlib compression conflicting with w3tc
Disable roi_enable_gzip_compression() function that was enabling
zlib.output_compression, preventing W3TC from caching pages.
Nginx handles gzip at server level instead.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
pre-fix-custom-css-manager
2025-12-05 18:55:09 -06:00
FrankZamora
1c0750604b chore(config): remove pre-commit hook that runs non-existent tests
El hook pre-commit ejecutaba npm test, pero el proyecto no tiene
tests configurados. Solo se necesita commit-msg para commitlint.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 15:00:18 -06:00
FrankZamora
bf304f08fc fix(css): centrar verticalmente contenido del hero section
Agrega propiedades flexbox al contenedor .hero-section para que el
contenido (título y badges) se muestre centrado verticalmente cuando
no hay badges de categorías.

Cambios:
- display: flex
- align-items: center
- justify-content: center

También incluye specs OpenSpec para arquitectura del tema.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 14:44:50 -06:00
FrankZamora
30b30b065b feat: add OpenSpec slash commands for Claude Code
- Remove .claude/ from .gitignore to share commands with team
- Add /openspec:proposal command for creating change proposals
- Add /openspec:apply command for implementing changes
- Add /openspec:archive command for archiving completed changes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 12:59:05 -06:00
FrankZamora
b2d5cdfb57 feat: install and configure OpenSpec for spec-driven development
- Add openspec/ directory with AGENTS.md and project.md
- Add root AGENTS.md stub for AI assistants
- Create Claude Code slash commands:
  - /openspec:proposal - Create change proposals
  - /openspec:apply - Implement changes
  - /openspec:archive - Archive completed changes
- Configure project.md with ROI Theme conventions and architecture

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-05 12:57:08 -06:00
FrankZamora
b40e5b671a chore: backup before OpenSpec installation 2025-12-05 12:51:08 -06:00
FrankZamora
61c67acca5 fix(admin): agregar mapeo hide_for_logged_in en FieldMappers (Plan 99.16)
Sin el mapeo en los FieldMappers, el campo no se guardaba en BD.
Agregado mapeo para: CtaBoxSidebar, CtaLetsTalk, CtaPost, TopNotificationBar.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 18:40:31 -06:00
FrankZamora
ffe6ea8e65 feat(visibility): añadir opción "Ocultar para usuarios logueados" (Plan 99.16)
- Crear UserVisibilityHelper centralizado en Shared/Infrastructure/Services
- Añadir campo hide_for_logged_in en schemas de 4 componentes
- Integrar validación en Renderers: TopBar, LetsTalk, CTASidebar, CTAPost
- Añadir checkbox UI en FormBuilders de los 4 componentes
- Refactorizar adsense-placement.php para usar el helper centralizado
- Deprecar función roi_should_hide_for_logged_in() (backwards compatible)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 18:28:53 -06:00
FrankZamora
36d5cf56de fix(wrappers): eliminar wrappers vacíos y corregir exclusiones AdSense (Plan 99.15)
## Problema
- Componentes deshabilitados/excluidos dejaban wrappers HTML vacíos
  (navbar 32px, sidebar col-lg-3 294px)
- AdSense ignoraba exclusiones por URL pattern en grupo _exclusions

## Solución Plan 99.15 (Clean Architecture)

### Domain Layer
- WrapperVisibilityCheckerInterface: contrato para verificar visibilidad

### Application Layer
- CheckWrapperVisibilityUseCase: orquesta verificaciones de visibilidad

### Infrastructure Layer
- WordPressComponentVisibilityRepository: consulta BD + PageVisibilityHelper
- WrapperVisibilityService: facade estático para templates
- BodyClassHooksRegistrar: agrega clases CSS failsafe al body

### Templates modificados
- header.php: renderizado condicional de <nav> wrapper
- page.php/single.php: lógica dinámica col-lg-9/col-lg-12 según sidebar

### CSS Failsafe
- css-global-utilities.css: reglas body.roi-hide-* como respaldo

## Fix AdSense (Inc/adsense-placement.php)
- Agregado PageVisibilityHelper::shouldShow() a todas las funciones:
  roi_render_ad_slot, roi_render_rail_ads, roi_enqueue_adsense_script,
  roi_inject_content_ads, roi_render_anchor_ads, roi_render_vignette_ad,
  roi_enqueue_anchor_vignette_scripts

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 11:46:21 -06:00
FrankZamora
23339e3349 feat(adsense): add exclusion system support (Plan 99.11)
- Add _page_visibility fields to FieldMapper
- Add _exclusions fields to FieldMapper
- Add page visibility checkboxes to FormBuilder
- Add ExclusionFormPartial integration

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-03 22:37:56 -06:00
FrankZamora
caa6413bc6 Reapply "refactor: remove legacy HeroSection component (orphaned code)"
This reverts commit ea695010f3.
2025-12-03 21:17:04 -06:00