WordPress usa un conjunto de reglas de reescritura para poder convertir una URL en una consulta de base de datos.
La expresión regular que maneja las URL de las páginas es muy general, IIRC es algo así como (.+.?)/?
, matemáticamente, prácticamente todo no ha sido compatible con otras reglas.
Por esta razón, no es posible escribir una regla de reescritura que funcione en su caso: porque no puede distinguir a través de expresiones regulares que en una URL como example.com/my-portal/sample-page
la parte 'my-portal' es un CPT y sample-page
es una página.
Las cosas se vuelven más complejas si tiene más niveles de anidación: my-portal/my-portal-child/sample-page
.
Para manejar este tipo de urls, WordPress usa la función get_page_by_path()
: explota la url de la página /
, obteniendo barras de página, luego consulta la base de datos de todas las páginas que tienen esas barras.
Por ejemplo, si tienes una página cuyo slug es "sample-page" y configuras como principal el CPT "my-portal" WordPress calls:
get_page_by_path('my-portal/sample-page')
pero no devuelve ningún resultado porque busca una página con el slug 'muestra de página' cuyo padre es otra página con el slug 'my-portal' . Esa página no existe, por lo que aparece el error 404.
Sin embargo, get_page_by_path()
acepta como tercer argumento una matriz de tipos de publicaciones: si lo configuras como array('page', 'portal')
entonces la función podrá encontrar la página correctamente.
Por lo tanto, puede resolver el problema configurando manualmente la identificación de la página (recuperada como se explicó anteriormente) en las ventanas de consulta WP.
El gancho 'parse_request'
es perfecto para el alcance:
- se ejecuta después de que se haya analizado la url
- pasa a enlazar devoluciones de llamada la instancia del objeto
$wp
que puede usar para establecer las variables de consulta
Código:
add_action('parse_request', function ($wp) {
// only if WP found a page
if (isset($wp->query_vars['pagename']) && ! empty($wp->query_vars['pagename'])) {
$page = get_page_by_path( // let's find the page object
$wp->query_vars['pagename'],
OBJECT,
array('page', 'portal') // we need to set both post types
);
if ($page instanceof WP_Post) { // if we find a page
unset($wp->query_vars['pagename']); // remove pagename var
$wp->query_vars['page_id'] = $page->ID; // replace with page_id query var
}
}
});
Este código, en combinación con el filtro en OP, es todo lo que necesita.
Tenga en cuenta que el código funciona incluso con portales jerárquicos anidados.