🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
6.0 KiB
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_redirectcon 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_idcomo 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
declare(strict_types=1);
namespace ROITheme\Shared\Infrastructure\Hooks;
final class CacheFirstHooksRegistrar
{
public function register(): void
{
add_action('template_redirect', [$this, 'fireBeforePageServe'], 0);
}
public function fireBeforePageServe(): void
{
if (is_user_logged_in()) {
return;
}
if (!is_singular()) {
return;
}
if (is_admin() || wp_doing_ajax() || wp_doing_cron()) {
return;
}
if (defined('REST_REQUEST') && REST_REQUEST) {
return;
}
$post_id = get_queried_object_id();
if ($post_id > 0) {
do_action('roi_theme_before_page_serve', $post_id);
}
}
}
Registro en functions.php
$cacheFirstHooks = new \ROITheme\Shared\Infrastructure\Hooks\CacheFirstHooksRegistrar();
$cacheFirstHooks->register();
Acceptance Criteria
- Hook
roi_theme_before_page_servese dispara entemplate_redirectpriority 0 - Solo dispara para
is_singular() === true - NO dispara para usuarios logueados
- Pasa
$post_idcomo parametro - No define DONOTCACHEPAGE ni headers anti-cache
- Plugins pueden enganchar y hacer redirect/exit
- 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 |