Entender el funcionamiento del cron de WordPress hará que podamos mejorar bastante el rendimiento de nuestra web. En resumen podríamos decir, que es el encargado de ejecutar las tareas que haya programadas, y se lanza en cada visita que llega a la web. Vamos a verlo un poco más en detalle.
Qué es cron
El nombre cron viene del griego chronos (χρονος) que significa “tiempo”. En el sistema operativo Unix, cron es un proceso que se ejecuta en segundo plano (demonio) y que se encarga de lanzar procesos a intervalos regulares. Los procesos que deben ejecutarse y la hora en la que deben hacerlo se especifican en el fichero crontab.
Cron se ejecuta en segundo plano (background) cada minuto, y revisa las tareas que hay en crontab para ver si hay alguna que la tenga que ejecutar.
Crontab es un simple archivo de texto que guarda una lista de comandos a ejecutar en un tiempo especificado por el usuario y puedes escribir en él ejecutando el comando “crontab -e” desde la terminal de Linux. Para que te hagas una idea de lo que contiene este fichero aquí tienes un pantallazo de la shell de uno de los servidores Linux que administro:
El cron de WordPress
Sin embargo el cron de WordPress no funciona de la misma manera, de hecho se podría decir que no es un cron “real” ya que su ejecución depende de WordPress no del servidor, es decir depende de las visitas que tenga la web. Es decir, se ejecuta cada vez que alguien entra en la web. Cuando llega una visita a cualquier página de la web el cron de WordPress chequea si hay alguna tarea por ejecutar. Si no hay visitas, el cron no se ejecuta. Si por ejemplo teníamos una tarea programada para las 5pm y hasta las 7pm no hay ninguna visita, la tarea se ejecutara pero tarde, a partir de las 7pm, no a las 5pm como la teníamos programada.
Aunque cueste creer, la gran mayoría de los casos de uso excesivo de recursos en WordPress son debidos a un problema en el WP-Cron, y casi siempre el problema se resuelve desactivándolo.
Para solucionar este posible desfase podemos hacer que sea el cron real del servidor el que ejecute el cron de WP (wp-cron.php) y que no dependa de las visitas a la web. Además, el hecho de que todo este proceso se ejecute cada vez que alguien entra a la web hace decaer el rendimiento de la web.
Por ello, mi consejo es desactivarlo y llamarlo solo a intervalos regulares desde fuera. La manera de desactivarlo es definiendo la constante DISABLE_WP_CRON a true, así que escribimos en el fichero wp-config.php la siguiente línea:
define('DISABLE_WP_CRON', true);
Configurar un cron real
Para ejecutar un cron real, una vez deshabilitado el cron de WordPress, se puede hacer de varias formas. Es posible que tu proveedor de hosting te de la opción de configurar tareas de cron. Por ejemplo en SiteGrodund, que utiliza cPanel, puedes hacerlo entrando en cPanel -> Avanzada > Cron Trabajos.
Como ves necesitas indicar el comando a ejecutar, que en nuestro caso es el interprete de PHP, con su ruta completa. Si tienes dudas de cuál es la ruta que usa tu servidor puedes averiguarlo con la función phpinfo() de PHP. Vas a la sección Environment y miras la variable PHPHANDLER, que en mi caso es /usr/local/php71/bin/php:
La ruta del wp-cron.php, en el caso de Siteground es /home/usuario/public_html/web/wp-cron.php, sustituyendo usuario por tu nombre de usuario y web por el nombre de la carpeta de tu sitio web, así que el comando completo quedaría de la siguiente forma:
/usr/local/php71/bin/php /home/usuario/public_html/web/ www/wp-cron.php
Podemos programar esta tarea para que se ejecute por ejemplo cada 30 minutos:
A partir de ahora, el cron de nuestro WordPress se ejecutará cada 30 minutos, independientemente del número de visitas que tengamos.
Si queremos ver todas las tareas que hay programadas para ejecutarse podemos hacerlo instalando el plugin WP Crontrol.
Funcionamiento interno del cron de WordPress
El cron de WP se ejecuta usando dos ficheros:
-/wp-includes/cron.php: Contiene toda la API del cron.
-/wp-cron.php: Cuando se ejecuta, llama a los hooks (ganchos) asociados a eventos.
El proceso que ocurre cuando se carga una página de WP es el siguiente:
- Un visitante solicita una página del sitio web.
- En /wp-includes/default-filters.php, WordPress “engancha” la función wp_cron() a la acción init.
- Cuando la acción init ocurre en /wp-settings.php, la función wp_cron() se ejecuta.
- wp_cron() se asegura de que el cron de WP no este deshabilitado y qué eventos han pasado su fecha de ejecución.
- Si un evento ha pasado su tiempo de ejecución entonces se ejecuta spawn_cron()
- spawn_cron() carga wp-cron.php a través de una solicitud HTTP.
- El archivo wp-cron.php carga y maneja todos los eventos en cola.
Programando nuestras propias tareas
Contamos con dos funciones:
Para crear eventos recurrentes:
wp_schedule_event( $timestamp, $recurrence, $hook, $args )
Para crear un único evento:
wp_schedule_single_event( $timestamp, $hook, $args )
Para ver un ejemplo practico podríamos programar un evento para que cada hora nos envíe un email. Lo podríamos hacer añadiendo el siguiente código en functions.php:
//Creamos la función que se encarga de programar la tarea cada hora en caso de que no exista function activa_evento() { if ( !wp_next_scheduled( 'evento_enviar_email' ) ) { wp_schedule_event(time(), 'hourly', 'evento_enviar_email'); } } //Indicamos que nuestra función activa_evento se ejecute una vez WP termina su carga add_action('init', 'activa_evento'); //La función encargada de enviar el correo function enviar_email() { wp_mail( 'contacto@vicentegarcia.com', 'Tarea ejecutada', 'Evento cada hora. Fecha de ejecución: '.date('d/m/Y H:i:s') ); } //Indicamos que la funcion enviar_email se ejecute cuando se dispare nuestra tarea evento_enviar_email add_action('evento_enviar_email', 'enviar_email');
Aunque el cron lo hemos dejado programado para que se ejecute cada 30 min., nuestra tarea de enviar el email se ejecutara cada hora, ya que así se lo hemos indicado (hourly).
En caso de cambiarte de hosting recuerda volver a configurar el cron. Si con tu nuevo hosting no tienes opción para configurarlo, entonces tendrás que volver a activar el cron de WordPress.