
Hay muchos motivos para tener un WordPress que solo vean usuarios conectados: una intranet para tu equipo, un sitio en construcción que el cliente debe revisar, una copia de prueba que no quieres que Google encuentre o un área de alumnos.
La solución típica es redirigir al inicio de sesión a quien no esté conectado. El problema es que eso solo cierra las páginas. Tu contenido sigue saliendo por otras puertas que casi nadie revisa:
- La API REST (
/wp-json/wp/v2/posts) entrega todas tus entradas, con título y contenido completo. - Los feeds (
/feed/) muestran las últimas entradas. - El mapa del sitio (
/wp-sitemap.xml) lista todas tus URLs.
Vamos a construir un mu-plugin que cierre todas, paso a paso. Es también un buen ejercicio para entender cómo WordPress procesa cada tipo de petición.
El mu-plugin completo
Crea wp-content/mu-plugins/cwp-sitio-privado.php:
<?php
/**
* Plugin Name: Sitio privado (Curso WordPress)
* Description: Solo usuarios conectados pueden ver el sitio, la API, los feeds y el mapa del sitio.
*/
// Páginas públicas aunque el sitio sea privado (slugs).
const CWP_PAGINAS_PUBLICAS = array( 'contacto', 'politica-de-privacidad' );
// IPs que pueden ver todo sin iniciar sesión (por ejemplo, tu oficina).
const CWP_IPS_PERMITIDAS = array( '200.0.0.1' );
function cwp_es_visita_permitida() {
if ( is_user_logged_in() ) {
return true;
}
$ip = isset( $_SERVER['REMOTE_ADDR'] ) ? $_SERVER['REMOTE_ADDR'] : '';
return in_array( $ip, CWP_IPS_PERMITIDAS, true );
}
// 1. Páginas: quien no esté conectado va al inicio de sesión.
add_action( 'template_redirect', function () {
if ( cwp_es_visita_permitida() ) {
return;
}
if ( ! empty( CWP_PAGINAS_PUBLICAS ) && is_page( CWP_PAGINAS_PUBLICAS ) ) {
return;
}
auth_redirect(); // Redirige al login y vuelve a esta página después.
} );
// 2. API REST: solo para usuarios conectados.
add_filter( 'rest_authentication_errors', function ( $resultado ) {
if ( ! empty( $resultado ) || cwp_es_visita_permitida() ) {
return $resultado;
}
return new WP_Error( 'cwp_privado', 'Este sitio es privado.', array( 'status' => 401 ) );
} );
// 3. Feeds: fuera.
foreach ( array( 'do_feed', 'do_feed_rdf', 'do_feed_rss', 'do_feed_rss2', 'do_feed_atom' ) as $feed ) {
add_action( $feed, function () {
if ( ! cwp_es_visita_permitida() ) {
wp_die( 'Este sitio es privado.', '', array( 'response' => 403 ) );
}
}, 1 );
}
// 4. Mapa del sitio de WordPress: desactivado.
add_filter( 'wp_sitemaps_enabled', '__return_false' );
// 5. Que los buscadores no indexen nada.
add_filter( 'wp_robots', function ( $robots ) {
$robots['noindex'] = true;
$robots['nofollow'] = true;
return $robots;
} );
Qué hace cada parte
template_redirectse ejecuta justo antes de mostrar cualquier página del sitio. Ahí comprobamos si la visita está permitida; si no,auth_redirect()la manda al login y, después de entrar, la devuelve a la página que quería ver. Las páginas de la listaCWP_PAGINAS_PUBLICASquedan abiertas.rest_authentication_errorses el filtro que WordPress consulta antes de responder cualquier petición a la API. Devolver un error ahí la bloquea por completo para visitantes anónimos. El editor de bloques sigue funcionando porque los usuarios conectados sí pasan.do_feed_*son las acciones que generan cada tipo de feed. Las interceptamos con prioridad 1, antes de que se genere nada.wp_sitemaps_enabledapaga el mapa del sitio nativo. Si usas un plugin de SEO que tiene su propio mapa, desactívalo también en sus ajustes.wp_robotsagreganoindex, nofollowa todas las páginas, por si algún buscador llegó a verlas antes.
Lo que sigue funcionando: la pantalla de inicio de sesión, la recuperación de contraseña, admin-ajax.php y wp-cron.php no pasan por template_redirect, así que no hace falta hacerles excepciones.
Las imágenes y archivos subidos siguen siendo públicos. El servidor los entrega directamente, sin pasar por WordPress. Si alguien tiene la URL de un PDF en wp-content/uploads, lo podrá abrir. Para documentos realmente confidenciales necesitas guardarlos fuera de uploads o usar un plugin de descargas protegidas.
Alternativa rápida para copias de prueba
Si solo quieres esconder una copia de prueba (por ejemplo, prueba.tudominio.cl), cPanel ofrece Privacidad de directorios: proteges la carpeta con usuario y contraseña a nivel del servidor, y nadie ve nada, ni siquiera la pantalla de login de WordPress.
Su punto débil es que también bloquea las peticiones que WordPress se hace a sí mismo (las usan WP-Cron y Salud del sitio). Si ves avisos de «la petición de bucle invertido falló», es por eso, y puedes ignorarlos mientras sea una copia de prueba.
Para probar que todo quedó cerrado
Desde una ventana de incógnito o una terminal:
curl -I https://tudominio.cl/
curl https://tudominio.cl/wp-json/wp/v2/posts
curl -I https://tudominio.cl/feed/
curl -I https://tudominio.cl/wp-sitemap.xml
Lo esperado: la portada redirige (302) al login, la API responde 401, el feed 403 y el mapa del sitio también te manda al login, porque ya no existe y cae en la regla de las páginas.
¿Necesitas que algunos roles vean solo ciertas secciones? Plantea tu caso en el foro y vemos cómo extender este mu-plugin.





