Espero que aprendáis tanto como yo al escribir este artículo, porque aquí hay mucha miga.
Una tarea CRON es una tarea programada que llama a un archivo externo cada cierto tiempo. Por ejemplo, podemos tener un archivo PHP y decirle al servidor que lo ejecute cada minuto, hora, día o semana.
Pero al hablar de WordPress debemos aclarar ciertos puntos para no caer en errores o perjudicar el rendimiento de nuestra web.
Una parte de esta información ha sido recogida de la documentación de WordPress y traducida al Castellano, pero hay contenido extra añadido por mi 🙂
Índice de Contenido
Qué es WP-CRON o el CRON de WordPress
CRON es una de las grandes ventajas de WordPress, con él podemos programar tareas, pero hay ciertas diferencias con una tarea CRON de servidor.
Podemos decir que WP-Cron es el sistema que WordPress usa para gestionar tareas basadas en periodos de tiempo.
Tiempos de ejecución de una tarea CRON en WordPress
Mientras que en el servidor podemos configurar el momento exacto de la tarea, en WordPress debemos contar con alguna visita en la web para que se ejecute. Esto es debido a la secuencia de carga de WordPress.
Si WordPress necesita de visitas para que se ejecuten las tareas ¿Qué pasa si establecemos una tarea para que se ejecute cada 10 minutos pero no hay visitas? Pues nada, que se ejecutaría con la siguiente visita.
Voy a intentar poner un ejemplo en el que se vea claro:
Imagina que colocamos una tarea cada 10 minutos y la primera ejecución se realiza a las 12 de la mañana. Si nadie visita la web hasta las 13:12, esta tarea no se realizaría hasta entonces. Y si alguien realiza una visita a las 13:22 se volvería a ejecutar.
En qué hook se ejecutan las tareas CRON
Cada vez que se carga una web hecha en WordPress, hay una secuencia establecida con funciones “enganchadas” a cada paso. Uno de estos hooks, concretamente “init”, es el que cuenta con una función enganchada que hace lo siguiente:
- Revisa la base de datos para ver si existe alguna tarea programada
- En caso de que hayan tareas, se llamaría al archivo
wp-cron.php
(localizado en la carpeta raíz) - Este archivo contiene los elementos necesarios para ejecutar la función llamada
¿Una tarea CRON ralentiza la carga de la web?
Conociendo lo anterior, esta es una pregunta que cualquiera se haría. La respuesta sencilla sería decirte que no, pero hay mucho más que eso, es un poco ambigua. Sí que ralentiza la web porque al final son recursos consumidos. Y no, porque no afecta directamente a la carga de la página cuando wp-cron.php
se activa, si no que las tareas se realizan en segundo plano (de forma asíncrona).
Además, el hecho de que con cada visita se revisen las tareas CRON es innecesario en la mayor parte de los casos. Es por esto que más abajo te explico cómo desactivar CRON en WordPress y, en caso de necesitarlo, activarlo desde el servidor.
Dónde se alojan los detalles de las tareas CRON
Los datos de cada tarea creada en WordPress se guardan en la navaja suiza de la base de datos, la archiconocida tabla options
. Podremos encontrar los detalles en nuestro phmyadmin bajo el option_name
cron. O también podríamos traer el valor con la función get_option()
y mostrarla, por ejemplo, mediante var_dump()
:
<?php
$cron_option = get_option('cron');
echo '<pre>';
var_dump( $cron_option );
echo '</pre>';
CRON y caché en WordPress
Muchas webs usan un plugin de caché para la optimización de recursos y tiempo de carga. Pero esto puede afectar directamente a la ejecución de nuestras tareas. Si queremos tener una tarea que se ejecute periódicamente junto con un plugin de caché, debemos asegurarnos que el plugin nos lo permita.
También debemos tener en cuenta que la zona de administración de WordPress no es cacheada y que, por ejemplo, si tenemos algún tipo de membresía sí que se ejecutarán los procesos.
Ejemplo de CRON en WordPress
Para este ejemplo voy a crear un sencillo plugin con 2 archivos y una tarea programada que se ejecutará cada 10 minutos. Desde la función de activación del plugin podremos añadir CRON.
Además, esta tarea escribirá algo en un archivo .txt para verificar que está funcionando.
<?php
/*
Plugin Name: CronWebHeroe
Plugin Uri: https://webheroe.com/
Description: Plugin to create a custom cron task
Author: Álvaro Torres
Author URI: https://webheroe.com/
Version: 1.0
License: GPLv2 or later
Text Domain: whtaskscron
*/
if( ! defined('ABSPATH') ) exit;
define( 'MI_RUTA', dirname(__FILE__) );
/**
* Añadimos la tarea en la activación del plugin y le decimos con qué periodicidad debe ejecutarse.
*/
function webheroe_activation() {
if ( ! wp_next_scheduled('webheroe_cron') ) {
wp_schedule_event( time(), 'ten_minutes', 'webheroe_cron' );
}
}
register_activation_hook( __FILE__, 'webheroe_activation' );
/**
* Creamos un nuevo periodo de tiempo para 10 minutos.
*/
function webheroe_ten_cron( $schedules ) {
$schedules['ten_minutes'] = array(
'interval' => 10 * MINUTE_IN_SECONDS,
'display' => __( 'Cada 10 minutos', 'pwc'), );
return $schedules;
}
add_filter( 'cron_schedules', 'webheroe_ten_cron' );
/**
* Esta función es la que enlaza al archivo donde estará la tarea a ejecutar.
*/
function webheroe_cron_exec() {
require_once( MI_RUTA . '/cron/archivo_a_ejecutar.php' );
}
add_action( 'webheroe_cron', 'webheroe_cron_exec' );
Y aquí tenéis el archivo donde se encuentra el código que se ejecutará:
<?php
file_put_contents( MI_RUTA . '/miarchivodetexto.txt', 'Prueba de texto', FILE_APPEND );
Como puedes ver es de lo más simple. Solo tenéis que seguir los siguientes pasos:
- Poner la tarea en cola llamando al hook
- Crear un periodo de tiempo personalizado si lo necesitamos
- Colocar la ruta al archivo a través del hook colocado en la activación de la tarea
- Colocar la magia en el archivo al que se llama
Lógicamente, para que este plugin funcione debería tener, como mínimo la siguiente estructura:
/
miplugin.php
miarchivodetexto.txt
/cron/archivo_a_ejecutar.php
Cómo establecer una tarea CRON que se ejecute una sola vez
Lo más habitual es utilizar esta funcionalidad para tareas periódicas, pero si queremos planificar una tarea única también es posible. Para añadir CRON y que se ejecute una sola vez solo tendríamos que sustituir la función de activación del código anterior y colocar wp_schedule_single_event
:
<?php
function webheroe_activation() {
if ( ! wp_next_scheduled( 'webheroe_cron' ) ) {
wp_schedule_single_event( time(), 'ten_minutes', 'webheroe_cron' );
}
}
register_activation_hook( __FILE__, 'webheroe_activation' );
CRON y WP-CLI
WP-CLI es la interfaz de línea de comandos de WordPress. Básicamente es lo que da la capacidad de realizar muchas tareas en consola. Y entre ellas encontramos algunas relativas al CRON de WordPress.
Cómo comprobar qué tareas están en cola
Si queremos verificar que una tarea existe podemos usar el comando wp cron event list
. Este comando nos devolverá un listado de tareas donde veremos:
- hook
- next_run_gmt
- next_run_relative
- recurrence
Así conoceremos qué tareas están en cola junto con el resto de datos.
Borrar CRON y desactivar tareas
El evento wp cron event delete
borra todas las tareas relativas al hook concreto. Si seguimos el ejemplo anterior, podríamos usar el siguiente comando:
wp cron event delete webheroe_cron
Cómo saber que nuestra tarea funciona correctamente
Además, para comprobar que el CRON de WordPress funciona y que nuestra tarea está correctamente en cola, podremos verificar que el sistema está funcionando correctamente mediante el comando wp cron test
.
Básicamente, lo que hace este comando es comprobar en qué estado están las constantes disable_wp_cron
y alternate_wp_cron
.
También podremos ejecutar una tarea mediante el comando wp cron event run
. Siguiendo el ejemplo anterior tendríamos que usar el siguiente comando:wp cron event run webheroe_cron
Ver periodos configurados
Con el comando wp cron schedule
también podremos ver los periodos configurados en nuestro sistema.
Quitar tarea de la cola
Mediante el comando wp cron event unschedule
podremos quitar una tarea de la cola. Sería por ejemplo:
wp cron event unschedule webheroe_cron
Ejecutar tareas para WordPress desde CRON del servidor
Para hacer tendremos que empezar desactivando wp-cron.php, lo que también será una mejora considerable del rendimiento de nuestra web porque estaremos evitando el chequeo constante de posibles tareas.
Cómo desactivar CRON de WordPress
Desactivarlo es tan sencillo como acceder al archivo wp-config.php
(en la carpeta raíz) y añadir el valor true a la constante DISABLE_WP_CRON
. Es decir, habría que añadir el siguiente código:
<?php
define( 'DISABLE_WP_CRON', true );
Configurar tarea en el servidor
Dependiendo del servidor con el que contemos, las tareas se ejecutarán de un modo u otro. Es por esto que quizá lo que os explique a continuación no funcione en vuestro servidor. Pero de ser así, os recomiendo que os pongáis en contacto con su soporte y estoy seguro que os informarán de cada paso.
En muchos servidores contamos con una sección concreta para definir las tareas CRON, donde solo tendremos que facilitar el comando con la ruta, así como el intervalo de tiempo.
Un comando típico para ejecutar wp-cron.php
sería:
php /home/customer/www/miweb.com/public_html/wp-cron.php
Consideraciones a tener en cuenta
Cuándo usar wp-cron.php y cuándo usar CRON desde el servidor
A mi forma de verlo, creo que wp-cron
es súper útil en ciertas ocasiones. Imaginemos por ejemplo que queremos desarrollar un plugin que necesita de tareas periódicas. Como supongo que entenderás, no te vas a poner a pedir acceso al servidor a cada usuario que instale este plugin.
Sin embargo, el hecho de poder establecer periodos concretos y reales, hace de CRON desde servidor una herramienta mucho más potente. Pero claro, solo usuarios con conocimientos podrían establecer estas tareas.
Intervalos de tiempo por defecto en WordPress
- hourly (cada hora)
- twicedaily (2 veces al día)
- daily (cada 24 horas)
- weekly (cada semana)
Definición de tiempos en WordPress
El sistema de tiempo en WordPress, al igual que PHP, funciona mediante segundos. Es por eso que WordPress nos facilita una serie de constantes de tiempo para ahorrarnos tener que calcular cada vez que queremos definir un periodo:
- MINUTE_IN_SECONDS (para un minuto)
- HOUR_IN_SECONDS (para una hora)
- DAY_IN_SECONDS (para un día)
- WEEK_IN_SECONDS (para una semana)
- MONTH_IN_SECONDS (para un mes)
- YEAR_IN_SECONDS (para un año)
Funciones nativas para CRON en WordPress
También contamos con un gran número de funciones nativas en WordPress para trabajar con nuestro sistema CRON. Entre ellas encontramos:
- wp_schedule_event()
- wp_get_schedules()
- wp_get_schedule()
- wp_get_scheduled_event()
- wp_reschedule_event()
- wp_next_scheduled()
- wp_schedule_delete_old_privacy_export_files()
- wp_reschedule_event()
- wp_schedule_https_detection()
- wp_clear_scheduled_hook()
- wp_schedule_update_network_counts()
- wp_schedule_delete_old_privacy_export_files()
- _wp_cron()
- _get_cron_array()
- wp_unschedule_event()
¡importante! Tiempo de ejecución limitado
Normalmente, los servidores suelen tener un tiempo máximo de ejecución del script. Si la función requiere de mucho tiempo por lo que sea, es muy probable que la ejecución no termine y acabe dando error. Es por esto que deberíamos establecer un tiempo de ejecución máximo lógico.
Si, por ejemplo, queremos hacer llamadas a diferentes APIs externas, dependeremos del tiempo de respuesta de sus servidores. Y bueno, saber qué tiempo exacto sería imposible debido a la inestabilidad que (casi) todos los servidores tienen.Para establecer un tiempo máximo de ejecución lo podríamos hacer desde php.ini. Pero quizá no sea el método más acertado si solo queremos este beneficio para la ejecución de nuestro script en CRON. En estos casos podemos colocar al principio del script la función PHP ini_set('max_execution_time', 300);
la que nos permitirá establecer el tiempo del script en segundos. En el ejemplo anterior sería una ejecución de 5 minutos. Y si queremos que el tiempo de ejecución sea ilimitado tendremos que establecer el valor en segundos a 0. Es decir: ini_set('max_execution_time', 0);
WebHeroe, además de agencia de marketing digital, también somos una agencia de desarrollo de plugins. Consúltanos y te informaremos.