# Especificacion: Hook de Pre-Evaluacion de Pagina ## Purpose Define un hook que permite a plugins externos evaluar condiciones ANTES de que WordPress sirva una pagina singular. Este hook es util para plugins de control de acceso, rate limiters, membership, etc. **Alcance del tema:** ROI-Theme SOLO provee el hook. La implementacion de logica de acceso es responsabilidad de cada plugin. --- ## Requirements ### Requirement: Hook roi_theme_before_page_serve The system MUST provide a hook that fires before WordPress serves a singular page, allowing external plugins to evaluate conditions and potentially redirect. #### Scenario: Plugin externo evalua acceso antes de servir pagina - **GIVEN** un plugin de control de acceso enganchado a `roi_theme_before_page_serve` - **WHEN** un visitante anonimo solicita una pagina singular (post, page, CPT) - **THEN** el tema DEBE disparar `do_action('roi_theme_before_page_serve', $post_id)` - **AND** el hook DEBE ejecutarse en `template_redirect` con priority 0 - **AND** si el plugin llama `wp_safe_redirect()` + `exit`, la pagina NO se sirve #### Scenario: Ningun plugin enganchado - **GIVEN** ningun plugin esta escuchando `roi_theme_before_page_serve` - **WHEN** un visitante solicita una pagina - **THEN** la pagina se sirve normalmente - **AND** no hay impacto en rendimiento #### Scenario: Solo paginas singulares - **GIVEN** el hook `roi_theme_before_page_serve` - **WHEN** la solicitud es para archivo, home, search, feed, o admin - **THEN** el hook NO DEBE dispararse #### Scenario: Usuarios logueados excluidos - **GIVEN** un usuario autenticado (logged in) - **WHEN** solicita cualquier pagina - **THEN** el hook NO DEBE dispararse - **BECAUSE** los plugins de cache no cachean paginas para usuarios logueados #### Scenario: REST API excluida - **GIVEN** una peticion REST API (REST_REQUEST === true) - **WHEN** se procesa la peticion - **THEN** el hook NO DEBE dispararse - **BECAUSE** las peticiones REST tienen su propio ciclo de vida y no sirven paginas HTML --- ### Requirement: Contexto para Plugins The hook MUST provide sufficient context for plugins to make decisions. #### Scenario: Plugin accede a informacion del post - **GIVEN** un plugin enganchado a `roi_theme_before_page_serve` - **WHEN** el hook se dispara - **THEN** el plugin recibe `$post_id` como parametro - **AND** `get_queried_object()` retorna el WP_Post completo - **AND** funciones como `is_singular()`, `is_single()`, `is_page()` funcionan #### Scenario: Plugin accede a informacion del visitante - **GIVEN** un plugin enganchado al hook - **WHEN** el hook se dispara - **THEN** `$_SERVER['REMOTE_ADDR']` esta disponible - **AND** headers HTTP estan disponibles via `$_SERVER` --- ### Requirement: No Interferir con Cache The theme MUST NOT define cache-blocking constants. #### Scenario: Tema no bloquea cache - **GIVEN** el tema roi-theme instalado - **WHEN** plugins de cache (W3TC, WP Super Cache, etc.) estan activos - **THEN** el tema NO DEBE definir `DONOTCACHEPAGE` - **AND** el tema NO DEBE enviar headers `Cache-Control: no-cache` #### Scenario: Plugin decide bloquear cache - **GIVEN** un plugin necesita bloquear cache para una pagina - **WHEN** el plugin esta enganchado al hook - **THEN** es responsabilidad del PLUGIN definir `DONOTCACHEPAGE` - **AND** el tema NO participa en esa decision --- ## Known Limitations ### Limitation 1: Page Cache Bypass **Severity**: CRITICAL para plugins que requieren evaluacion en cada request Cuando Page Cache esta habilitado (W3TC, WP Super Cache, etc.), el hook `roi_theme_before_page_serve` NO SE EJECUTA para paginas cacheadas. **Razon tecnica:** ``` Request → advanced-cache.php → [Cache HIT] → HTML servido ↓ WordPress NUNCA carga ↓ Hook NUNCA se dispara ``` **Implicacion para plugins:** - Rate limiters: Los limites no se evaluan en cache hits - Membership plugins: El acceso no se verifica en cache hits - Geolocation: Las restricciones no aplican en cache hits **Solucion:** Los plugins que requieren evaluacion en cada request deben implementar su propia estrategia (JavaScript-First, cookies, edge workers, etc.). Esto esta FUERA del alcance de esta spec. ### Limitation 2: Solo Paginas Singulares El hook solo dispara para `is_singular() === true`. Archives, taxonomies, search, y home NO disparan el hook. --- ## Implementation ### Ubicacion en Clean Architecture El hook DEBE registrarse en `Shared/Infrastructure/Hooks/`. ### Archivo: CacheFirstHooksRegistrar.php ```php 0) { do_action('roi_theme_before_page_serve', $post_id); } } } ``` ### Registro en functions.php ```php $cacheFirstHooks = new \ROITheme\Shared\Infrastructure\Hooks\CacheFirstHooksRegistrar(); $cacheFirstHooks->register(); ``` --- ## Acceptance Criteria 1. Hook `roi_theme_before_page_serve` se dispara en `template_redirect` priority 0 2. Solo dispara para `is_singular() === true` 3. NO dispara para usuarios logueados 4. Pasa `$post_id` como parametro 5. No define DONOTCACHEPAGE ni headers anti-cache 6. Plugins pueden enganchar y hacer redirect/exit 7. Sin impacto en rendimiento si ningun plugin engancha --- ## Version History | Version | Date | Changes | |---------|------|---------| | 1.0 | 2025-12-07 | Initial spec | | 2.0 | 2025-12-07 | Simplified: Only defines hook, removed plugin implementation details |