Cómo forzar un error 404 en WordPress
Necesito forzar un error 404 en algunas publicaciones basado en condiciones. Logré hacerlo (aunque no sé si fue la forma correcta) y estoy cargando mi plantilla 404.php
como esperaba.
Mi código:
function rr_404_my_event() {
global $post;
if ( is_singular( 'event' ) && !rr_event_should_be_available( $post->ID ) ) {
include( get_query_template( '404' ) );
exit; # para que la página normal no se cargue después de la página 404
}
}
add_action( 'template_redirect', 'rr_404_my_event', 1 );
Código 2 de esta pregunta relacionada - mismo problema:
function rr_404_my_event() {
global $post;
if ( is_singular( 'event' ) && !rr_event_should_be_available( $post->ID ) ) {
global $wp_query;
$wp_query->set_404();
}
}
add_action( 'wp', 'rr_404_my_event' );
Mi problema:
Aunque parece funcionar, obtengo un estado 200 OK
si reviso la pestaña de red. Como es un estado 200
, me preocupa que los motores de búsqueda puedan indexar esas páginas.
Comportamiento esperado:
Quiero que se envíe un estado 404 No encontrado
.

Podrías probar la función de Wordpress status_header()
para agregar el encabezado HTTP/1.1 404 No Encontrado
;
Entonces tu ejemplo Código 2 quedaría:
function rr_404_my_event() {
global $post;
if ( is_singular( 'event' ) && !rr_event_should_be_available( $post->ID ) ) {
global $wp_query;
$wp_query->set_404();
status_header(404);
}
}
add_action( 'wp', 'rr_404_my_event' );
Esta función se utiliza por ejemplo en esta parte:
function handle_404() {
...cut...
// Supongo que es momento de devolver 404.
$wp_query->set_404();
status_header( 404 );
nocache_headers();
...cut...
}
de la clase wp
en /wp-includes/class-wp.php
.
Así que prueba usando este ejemplo modificado de Código 2 además de tu código con template_include
.

El fragmento de Code 2
que publicaste funciona perfectamente. El set_header()
era lo que faltaba.

@birgire te refieres a set_header()
para agregar HTTP/1.1 404 Not Found
pero has usado status_header()
en tu código?

Útil. Estoy verificando parámetros de consulta personalizados, así que no estoy usando la acción, pero resulta un método muy útil en mi clase de plugin.

La forma más robusta que he encontrado para lograr esto es hacerlo en el filtro template_include
, de la siguiente manera:
function wpse91900_force_404(string $template): string {
if ($some_condition) {
global $wp_query;
$wp_query->set_404();
status_header(404);
nocache_headers();
$template = get_404_template();
}
return $template;
}
add_filter("template_include", "wpse91900_force_404");

No recomendaría forzar un error 404.
Si te preocupan los motores de búsqueda, ¿por qué no simplemente agregas una metaetiqueta "no-index,no-follow" a esas páginas y las bloqueas con robots.txt?
Esta podría ser una mejor manera de bloquear el contenido para que no se vea
add_filter( 'template_include', 'nifty_block_content', 99 );
function nifty_block_content( $template ) {
if ( is_singular( 'event' ) && !rr_event_should_be_available( $post->ID ) ) {
$template = locate_template( array( 'nifty-block-content.php' ) );
}
return $template;
}
Probablemente también podrías usar este método para cargar 404.php
pero siento que usar una plantilla de página podría ser una mejor opción.

Muchas gracias por el enlace, voy a cambiar a usar locate_template()
en su lugar. Creo que robots.txt.
no es una forma garantizada de proteger contra la indexación. Algunos motores de búsqueda podrían seguir recogiendo la página. Quiero que la página parezca una página 404 normal. Además, las publicaciones se van a añadir dinámicamente, editar el archivo robots.txt
añadirá más problemas.

Quería compartir la forma en que utilicé la solución marcada
function fail_safe_for_authors() {
if ((is_user_logged_in()) && (is_author()) && ($_COOKIE["user_role"] !== "administrator")) {
global $wp_query;
$wp_query->set_404();
status_header(404);
}
}
add_action("wp", "fail_safe_for_authors");
Hice esto para separar todos los tipos de usuarios del administrador, en este proyecto, solo el admin puede ver la página author.php
.
Espero que pueda ayudar a alguien más.

Redirigir en caso de errores es terrible para el ranking de tu página. Simplemente muestra una plantilla en la misma ubicación que la solicitud incorrecta. Lo que sucederá cuando hagas eso es que inicialmente configurarás un 404, y luego la redirección lo cambiará a un 301 o 302, que luego redirigirá a una página que devuelve un 200. Eso luego es indexado por los motores de búsqueda como una página válida, que es exactamente lo que OP dijo que no quería.

Los códigos de estado se envían en las cabeceras de las peticiones HTTP. Tu función actual está enganchada a un hook que se llamará demasiado tarde.
Deberías intentar enganchar tu función rr_404_my_event()
a la acción send_headers
.
No estoy seguro de si en ese momento es posible verificar el ID de la entrada, pero prueba esto:
add_action( 'send_headers', 'rr_404_my_event' );
function rr_404_my_event() {
global $post;
if ( is_singular( 'event' ) && !rr_event_should_be_available( $post->ID ) {
include( get_query_template( '404' ) );
header('HTTP/1.0 404 Not Found');
exit;
}
}

Corregí algunos errores de sintaxis en tus códigos. Ni siquiera logro que mi plantilla 404 se cargue con eso.

Quizás, en tu 404.php
podrías cargar un header.php
diferente, por ejemplo <?php get_header('404'); ?>
para cargar header-404.php
. En ese encabezado, agregarías header('HTTP/1.0 404 Not Found');
en la sección <head>
.
