WordPress Hosting

Modo mantenimiento en WordPress con archivo .maintenance sin plugins (actualizado)

El truco del archivo .maintenance para poner WordPress en modo mantenimiento sin plugins lleva años funcionando, es el que usa el propio WordPress y lo tengo contado aquí desde hace tiempo. Pues bien, tal y como lo contamos (yo el primero) se queda a medias.

Le faltan tres cosas: corta el paso también a quien está trabajando en la web, no explica que cualquier actualización te lo borra sin avisar, y despacha al visitante con una frase pelada cuando podrías enseñarle una página en condiciones.

Las tres se arreglan sin plugins y sin salirse del método. Vamos a verlo con calma, que tiene más miga de la que parece.

Lo que hace WordPress cuando encuentra el .maintenance

Este mecanismo no lo inventó nadie para poner el cartel de «cerrado por obras» que cuelga WordPress solito cada vez que actualiza un plugin, y que descuelga al terminar. Nosotros lo que hacemos es colgarlo a mano.

El recorrido, que conviene conocer para saber dónde se toca:

  • En wp-settings.php, sobre la línea 79 desde WordPress 7.0, se llama a wp_maintenance(). Y el detalle es que eso pasa antes de cargar los plugins y antes de que WordPress sepa quién eres.
  • Esa función pregunta a wp_is_maintenance_mode(), que hace un require del .maintenance y mira una única variable, $upgrading. Si la marca de tiempo tiene más de diez minutos da el mantenimiento por terminado y el sitio carga con normalidad.
  • Si el mantenimiento sigue vivo y existe un archivo wp-content/maintenance.php WordPress lo incluye y termina ahí la ejecución, y si no existe saca su aviso de serie.

Y aquí está el trucazo importante, que es que el .maintenance no es un archivo de texto, es PHP que WordPress ejecuta. Dentro puedes poner lógica, mirar cookies, mirar la URL pedida y decidir. Es lo que vamos a hacer.

El método de siempre, en dos archivos

Primero la página. Creas wp-content/maintenance.php con esto:

<?php
$protocol = $_SERVER['SERVER_PROTOCOL'];
if ( 'HTTP/1.1' !== $protocol && 'HTTP/1.0' !== $protocol ) {
	$protocol = 'HTTP/1.0';
}
header( "$protocol 503 Service Unavailable", true, 503 );
header( 'Content-Type: text/html; charset=utf-8' );
header( 'Retry-After: 3600' );
?>
Estamos de mantenimiento, vuelve a intentarlo en un rato.
<?php die(); ?>

El 503 no es decorativo, le dice a Google «esto está cerrado un rato, no te lo tomes como que la página ha desaparecido». El Retry-After le sugiere cuándo volver.

Luego va el interruptor. Creas un archivo llamado .maintenance en la raíz de WordPress, al lado de wp-config.php, con una sola línea:

<?php $upgrading = time(); ?>

Con eso ya tienes el sitio cerrado. Para abrirlo borras o renombras el .maintenance y ya está. Hasta aquí el método clásico.

Mejora 1: que el cartel no te cierre la puerta a ti también

Prueba a poner el .maintenance tal cual y a entrar en tu escritorio, resulta que no puedes. Ese archivo corta absolutamente todo, incluidos wp-login.php y wp-admin, así que te quedas fuera de tu propia web y solo puedes volver a entrar borrando el archivo por FTP.

Para una actualización de dos minutos da igual, pero para dejar la web cerrada mientras la montas, no sirve, porque ni tú ni tu cliente podéis ver cómo va quedando.

Como el .maintenance es PHP la excepción hay que meterla dentro. Este es el que yo uso:

<?php
// Por defecto, mantenimiento activo.
$upgrading = time();

$pasa = false;

// El acceso, el escritorio y el cron siguen funcionando.
$ruta = isset( $_SERVER['REQUEST_URI'] ) ? (string) $_SERVER['REQUEST_URI'] : '';
foreach ( array( '/wp-login.php', '/wp-admin', '/wp-cron.php' ) as $puerta ) {
	if ( false !== strpos( $ruta, $puerta ) ) {
		$pasa = true;
		break;
	}
}

// Y quien tenga sesión iniciada ve el sitio de verdad.
if ( ! $pasa ) {
	foreach ( array_keys( $_COOKIE ) as $cookie ) {
		if ( 0 === strpos( $cookie, 'wordpress_logged_in_' ) ) {
			$pasa = true;
			break;
		}
	}
}

if ( $pasa ) {
	// Una hora atrás: WordPress lo lee como mantenimiento caducado y sigue.
	$upgrading = time() - 3600;
}
?>

El truco está en la última línea. No hace falta ningún filtro ni ninguna constante: si $upgrading apunta a hace más de diez minutos, WordPress considera que el mantenimiento ya terminó y carga la web entera con normalidad. Para esa visita concreta el cartel no existe.

Ahora bien, un aviso, y es que a esa altura del arranque no hay funciones de WordPress, así que lo único que se puede mirar es si el navegador manda una cookie cuyo nombre empieza por wordpress_logged_in_, no se valida su firma.

Esto sirve para que tú y tu cliente podáis trabajar, no como control de acceso, pues cualquiera que sepa el nombre de esa cookie se la puede inventar. Si lo que necesitas es un muro de verdad el sitio va con contraseña de servidor o con el modo privado del hosting.

Mejora 2: servir una página entera, no una frase suelta

Lo de «Estamos de mantenimiento» cumple, pero es para un rato. Pero como ya sabes que maintenance.php es PHP normal, resulta que puede leer un HTML completo y mostrarlo tal cual:

<?php
$base   = '/wp-content/espera/';
$pagina = WP_CONTENT_DIR . '/espera/index.html';

header( 'HTTP/1.1 503 Service Unavailable' );
header( 'Content-Type: text/html; charset=utf-8' );
header( 'Retry-After: 3600' );

if ( is_readable( $pagina ) ) {
	$html = (string) file_get_contents( $pagina );

	if ( false === strpos( $html, '<base ' ) ) {
		$html = preg_replace( '#<head([^>]*)>#i', '<head$1><base href="' . $base . '">', $html, 1 );
	}

	echo $html;
	exit;
}

echo 'Estamos de mantenimiento, vuelve a intentarlo en un rato.';

Subes tu página de espera con sus imágenes a wp-content/espera/ y listo. Sirve cualquier HTML, uno que te hayas montado a mano, uno de una plantilla que hayas comprado o el que te dejó el diseñador.

Fíjate en la etiqueta <base>, que es la parte más importante, pues las rutas relativas de un HTML se resuelven contra la URL que pidió el visitante, no contra la carpeta donde está el archivo.

Sin el <base>, si alguien entra en tudominio.com/tienda/camisetas/ el navegador buscará el logotipo en /tienda/camisetas/imagenes/logo.png y verá el icono de imagen rota.

Con esa línea todas las rutas relativas cuelgan de la carpeta correcta y la página se ve igual entre desde donde entre.

No es para siempre: la próxima actualización te lo borra

Vuelve al principio, a lo del cartel que cuelga WordPress cuando actualiza. Ese cartel es este mismo archivo.

Cuando actualizas un plugin, un tema o el núcleo, WP_Upgrader::maintenance_mode() (en wp-admin/includes/class-wp-upgrader.php) escribe su propio .maintenance al empezar y lo borra al terminar. No mira si era tuyo, no pregunta.

O sea, que si tienes el sitio cerrado con este método y una madrugada entran las actualizaciones automáticas de seguridad, tu web amanece abierta y sin que nadie te avise.

Para un corte de una hora es perfecto, para tener el sitio meses en «próximamente» es una bomba de relojería, y sino, desactiva las actualizaciones automáticas.

No vale para todos los usos

Todo hay que decirlo: el .maintenance es la herramienta correcta para lo que es, un corte. Una migración, un cambio de dominio, restaurar una copia de seguridad, esas dos horas en las que no quieres que nadie compre ni comente ni te mande un formulario.

Si lo que quieres es tener la web en «próximamente» durante días o semanas mientras la montas, hay caminos mejores, que además devuelven un 200 normal y no un 503:

  • Si es una tienda, WooCommerce trae ese modo de serie y no necesitas nada más.
  • Si no es una tienda, casi cualquier plugin de «coming soon» decente hace lo mismo, y algunos hosting lo traen en su panel.

El plan mínimo, si vas a cerrar hoy

  1. Sube tu HTML de espera con sus imágenes a wp-content/espera/.
  2. Sube el maintenance.php de arriba a wp-content/.
  3. Sube el .maintenance con las excepciones a la raíz del sitio. Si tu gestor de archivos no lo enseña, activa la opción de ver archivos ocultos.
  4. Compruébalo en una ventana de incógnito, que es la única forma de ver lo que ve un visitante y no lo que ves tú con tu sesión abierta.
  5. Apúntate en algún sitio que lo tienes puesto. Y cuando termines, borra el .maintenance.

Los otros dos archivos pueden quedarse donde están para la próxima, sin el .maintenance no se ejecutan nunca.

Y si se te ocurre alguna excepción más que meter en el archivo (una IP concreta, un parámetro secreto en la URL, lo que sea), me tienes ahí abajo en los comentarios, que seguro que a alguien le viene bien.

Compártelo en tus redes
Resúmelo con tu IA

¿De cuánta utilidad te ha parecido este contenido?

¡Haz clic en las estrellas para valorarlo!

Promedio de puntuación 4.3 / 5. Total de votos: 6

¡Todavía no hay votos! Sé el primero en valorar este contenido.

Ya que has encontrado útil este contenido...

¡Sígueme en las redes sociales!

¿Te gustó este artículo? ¡Ni te imaginas lo que te estás perdiendo en YouTube!



Sobre el autor

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

2 comentarios en “Modo mantenimiento en WordPress con archivo .maintenance sin plugins (actualizado)”

  1. Irene Somenson

    Hola, me funcionó!

    Pero tengo un problemita no puedo acceder tampoco al panel de control. Es decir queda todo en modo mantenimiento.

    ¿Hay alguna manera de que el panel de control quede liberado para hacer las tareas de mantenimiento?

    Muchas gracias por tu aporte!

Scroll al inicio