Cómo identificar y gestionar tus eventos de WP-Cron, evitar duplicados y distinguir una ejecución de todas las programaciones de una tarea.
Gestionar las tareas programadas de WordPress resulta útil cuando necesitas mantener un catálogo, sincronizar datos o investigar por qué un proceso no se ejecuta. Puedes hacerlo mediante las APIs de WP-Cron, sin instalar un gestor adicional si tu proyecto no lo necesita.
En esta revisión veremos cómo consultar un evento, programarlo con argumentos y distinguir entre eliminar su siguiente ejecución y retirar todas las ejecuciones de una misma tarea. Usaremos como ejemplo un identificador de catálogo; el trabajo real de sincronización pertenece a tu aplicación.
Estructura del cron de WordPress
WP-Cron comprueba las tareas pendientes cuando se carga WordPress. Por defecto depende de las visitas: un evento programado para las 14:00 puede ejecutarse más tarde si no hay actividad o si falla el mecanismo de lanzamiento. No es un proceso que esté funcionando continuamente ni una garantía de ejecución a una hora exacta.
Un evento combina un timestamp UTC, el nombre de un hook y sus argumentos. Si es recurrente, también tiene una programación, como hourly, y su intervalo. El hook no es la función: la función se conecta a él con add_action().
Los argumentos forman parte de la identidad del evento. Debes conservar sus valores, tipos y orden al programarlo, consultarlo o eliminarlo. En este ejemplo utilizaremos siempre [17]: no equivale a no pasar argumentos ni a pasar el texto ['17']. WordPress entrega cada valor del array como un parámetro independiente al callback.
El núcleo guarda la programación en la opción cron, usando el prefijo real de las tablas de esa instalación. No necesitas modificar esa opción por SQL para gestionar tus eventos. Las APIs se encargan de su estructura y permiten detectar errores.
Lanzamiento desde el planificador del servidor. Si necesitas que las tareas pendientes se revisen aunque no haya visitas, puedes utilizar cron del sistema o el programador del alojamiento. Primero prepara y verifica el mecanismo sustituto; después desactiva el lanzamiento por visitas. No es obligatorio cambiarlo en todas las webs ni basta con definir una constante para disponer de un planificador alternativo.
Con WP-CLI disponible, una entrada como esta en el crontab del usuario del sitio solicita la ejecución de los eventos vencidos cada cinco minutos. Todas las rutas son ejemplos que debes sustituir, y el directorio del registro debe existir y permitir la escritura a ese usuario:
*/5 * * * * /ruta/a/wp --path=/ruta/a/wordpress cron event run --due-now >> /home/usuario/logs/wp-cron.log 2>&1Es una plantilla de crontab de usuario, no una orden para pegar directamente en la terminal. En /etc/crontab también se especifica el usuario, y los paneles de alojamiento pueden pedir la frecuencia y el comando en campos separados. Usa una cuenta con los permisos del sitio, no root; confirma además que el ejecutable WP-CLI utiliza una versión de PHP compatible.
Elige la frecuencia según el retraso que admite el proyecto. Una consulta cada cinco minutos puede dejar un evento pendiente hasta el siguiente lanzamiento, además del tiempo que consuman otras tareas. Quince minutos pueden ser demasiados para determinados procesos. Ninguno de esos intervalos garantiza la hora exacta de comienzo ni que el trabajo termine antes de la siguiente llamada.
Antes de habilitar el nuevo disparador, comprueba las rutas y el usuario, y prueba con una tarea controlada en un entorno de trabajo. wp cron event run --due-now ejecuta las tareas vencidas de la instalación: pueden enviar correos, hacer copias o modificar datos. No lo utilices como una consulta inocua. Evita duplicar el lanzamiento con otros programadores y comprueba que no quede trabajo solapado.
Cuando hayas verificado el mecanismo alternativo, añade esta constante una sola vez en wp-config.php, antes de que se cargue WordPress:
define('DISABLE_WP_CRON', true);Esta opción desactiva el disparo automático asociado a las visitas; no borra los eventos ni bloquea por sí sola el acceso HTTP a wp-cron.php. Si tu alojamiento solo admite llamadas web, puedes programar una petición HTTPS a ese archivo, siguiendo la documentación oficial. En ese caso siguen interviniendo el servidor web y sus límites; no bloquees la ruta que necesita ese mecanismo.
Conserva los errores en un registro privado con rotación y comprueba tanto el lanzamiento como el resultado de la tarea. wp cron test prueba el mecanismo de lanzamiento HTTP de WordPress y puede informar de un error cuando DISABLE_WP_CRON está activo; no valida el crontab externo. wp cron schedule list muestra los intervalos disponibles, mientras que wp cron event list muestra los eventos.
La ejecución por consola evita utilizar un proceso PHP del servidor web para ese trabajo, pero sigue consumiendo CPU, memoria y acceso a datos. Si administras varias webs, reparte sus lanzamientos y mide la carga. Para trabajos largos, mantén controles de concurrencia, lotes y reintentos adecuados a la integración. Consulta el alcance de wp cron event run en la versión de WP-CLI instalada.
WP Crontrol como gestor del cron
El plugin se llama WP Crontrol. Permite inspeccionar eventos, sus argumentos y programaciones, y realizar operaciones desde la administración. Puede ser una herramienta útil para diagnosticar una instalación aunque tu desarrollo utilice directamente las APIs.
La elección depende de quién deba gestionar las tareas. Para una inspección visual puede resultar práctico; para integrar un proceso propio puedes utilizar código y, si tienes acceso a la consola, WP-CLI. No hace falta reproducir toda la interfaz de un gestor para programar una tarea de tu aplicación.
Antes de ejecutar, modificar o borrar un evento, identifica quién lo registra y qué hace su callback. Una tarea puede enviar correos, actualizar datos o lanzar una integración. Eliminarla no impide que el plugin que la crea vuelva a registrarla.
Gestionando el cron de WordPress
Los ejemplos siguientes definen funciones auxiliares para un plugin propio. Utilizan rjc_revisar_catalogo como hook y un identificador entero positivo como argumento. Cargar las funciones no programa ni ejecuta una tarea por sí solo. Los parámetros para devolver WP_Error requieren WordPress 5.7 o posterior.
1. Lista de tareas
Si dispones de WP-CLI, puedes listar los eventos sin instalar un gestor adicional. Ejecuta el comando desde la instalación correspondiente o indica su ruta con --path. El campo next_run_gmt muestra la fecha en UTC; args permite distinguir eventos que comparten hook.
wp cron event list --fields=hook,next_run_gmt,recurrence,argsDentro de tu código, para consultar la próxima ejecución de un evento conocido utiliza la API pública wp_get_scheduled_event():
$evento = wp_get_scheduled_event('rjc_revisar_catalogo', [17]);
if (false !== $evento) {
$timestamp_utc = $evento->timestamp;
$programacion = $evento->schedule;
$argumentos = $evento->args;
}Si solo necesitas la fecha puedes usar wp_next_scheduled(), pasando los mismos argumentos y comparando el resultado con false de forma estricta. La función _get_cron_array() que aparecía en la versión anterior es una API interna; no la necesitamos para consultar nuestro evento ni para las operaciones de esta guía.
2. Eliminar tareas programadas
Hay tres operaciones distintas. wp_unschedule_event() elimina el evento identificado por timestamp, hook y argumentos. wp_clear_scheduled_hook() elimina todas las ejecuciones de ese hook con esos argumentos. wp_unschedule_hook() tiene un alcance más amplio: elimina todos los eventos del hook, también los que tengan otros argumentos.
Para retirar la siguiente ejecución de un catálogo, primero buscamos el evento completo. El siguiente ejemplo devuelve 0 si no existe, 1 si lo elimina o un WP_Error si falla:
function rjc_cron_eliminar_siguiente(int $catalogo_id)
{
if ($catalogo_id < 1) {
return new WP_Error('rjc_catalogo_invalido', 'El catálogo debe ser positivo.');
}
$hook = 'rjc_revisar_catalogo';
$args = [$catalogo_id];
$evento = wp_get_scheduled_event($hook, $args);
if (false === $evento) {
return 0;
}
$resultado = wp_unschedule_event($evento->timestamp, $hook, $args, true);
return is_wp_error($resultado) ? $resultado : (true === $resultado ? 1 : 0);
}Eliminar la siguiente ejecución recurrente normalmente interrumpe esa cadena de repetición, porque ya no llegará a ejecutarse y reprogramarse. Sin embargo, no borra otros eventos que ya estén almacenados con el mismo hook y argumentos en timestamps distintos. Tampoco afecta a otro catálogo.
Cuando la intención es retirar todas las ejecuciones de ese catálogo, utiliza esta otra función. Su resultado es el número de eventos eliminados o un WP_Error; cero significa que no había ninguno:
function rjc_cron_eliminar_todos(int $catalogo_id)
{
if ($catalogo_id < 1) {
return new WP_Error('rjc_catalogo_invalido', 'El catálogo debe ser positivo.');
}
return wp_clear_scheduled_hook('rjc_revisar_catalogo', [$catalogo_id], true);
}Si existe una ejecución en curso, eliminar su programación no la cancela. Y si tu propio código registra el evento en cada carga, puede volver a aparecer después de borrarlo: revisa también dónde y cuándo lo programas.
3. Añadir tareas al cron de WordPress
Para una recurrencia de cinco minutos registramos un intervalo de 300 segundos. Conservamos las programaciones que WordPress ya proporciona:
function rjc_cron_intervalos(array $intervalos): array
{
$intervalos['rjc_cinco_minutos'] = [
'interval' => 5 * MINUTE_IN_SECONDS,
'display' => 'Cada cinco minutos',
];
return $intervalos;
}
add_filter('cron_schedules', 'rjc_cron_intervalos');El filtro debe estar disponible cuando se programa y cuando WordPress reprograma la tarea. Por eso conviene cargarlo desde el plugin que contiene la funcionalidad, y no registrarlo únicamente dentro de su callback de activación.
La siguiente función comprueba la combinación de hook y argumentos antes de programar. Si ya existe con otra recurrencia, devuelve un error para que decidas cómo migrarla. Si no existe, solicita una primera ejecución dentro de un minuto:
function rjc_cron_programar(int $catalogo_id)
{
if ($catalogo_id < 1) {
return new WP_Error('rjc_catalogo_invalido', 'El catálogo debe ser positivo.');
}
$hook = 'rjc_revisar_catalogo';
$args = [$catalogo_id];
$evento = wp_get_scheduled_event($hook, $args);
if (false !== $evento) {
if ($evento->schedule !== 'rjc_cinco_minutos') {
return new WP_Error('rjc_intervalo_distinto', 'La tarea ya tiene otro intervalo.');
}
return true;
}
return wp_schedule_event(
time() + MINUTE_IN_SECONDS,
'rjc_cinco_minutos',
$hook,
$args,
true
);
}Invoca rjc_cron_programar(17) desde un punto de configuración controlado, por ejemplo la activación de tu plugin, y comprueba el resultado con is_wp_error(). No copies una llamada de programación automática en cada carga si quieres poder retirar la tarea. El retraso de un minuto expresa cuándo estará pendiente, no cuándo terminará ni una hora garantizada de inicio.
Además debes registrar una función que haga el trabajo. Este ejemplo completo de callback solo escribe una línea en el registro de PHP; sirve para comprobar la conexión entre el hook y su argumento, no sincroniza ningún catálogo:
add_action('rjc_revisar_catalogo', 'rjc_cron_mostrar_catalogo', 10, 1);
function rjc_cron_mostrar_catalogo($catalogo_id)
{
error_log('Demostración de cron: catálogo ' . (int) $catalogo_id);
}El último argumento de add_action() indica que el callback acepta un parámetro. En tu integración sustituirás la demostración por el trabajo real. Si usas más argumentos, registra cuántos acepta el callback y mantén un formato estable para esos valores.
Para una ejecución única existe wp_schedule_single_event(), que no recibe un nombre de recurrencia. Al desactivar tu plugin, limpia los eventos que sean de su responsabilidad con sus argumentos correspondientes. Si una interfaz permite programar o borrar tareas, valida permisos y protege la petición con un nonce.
Conclusiones
Podemos gestionar nuestras tareas con las APIs de WordPress sin añadir un gestor permanente. Lo esencial es identificar cada evento por timestamp, hook y argumentos, distinguir el alcance de cada borrado y comprobar los errores de programación.
Comprobar antes de programar evita duplicados en llamadas sucesivas, pero no constituye un bloqueo atómico entre peticiones simultáneas. Para una integración real, diseña operaciones idempotentes, evita procesar dos veces el mismo lote y utiliza un mecanismo de exclusión adecuado si el trabajo puede solaparse.
WP-Cron no convierte automáticamente una operación larga en un proceso rápido o fiable. Divide los trabajos extensos en lotes, registra inicio, resultado y errores, y define qué ocurre cuando hay un fallo o un reintento. Las medidas de rendimiento de una instalación concreta no permiten prometer una mejora porcentual general.
Las pruebas de estos ejemplos cubren argumentos, duplicados, intervalos, borrado selectivo y errores. Antes de utilizarlos, adáptalos a tu entorno y comprueba la integración completa en condiciones reales: no son recetas universales listas para copiar y usar.
¿Tienes alguna pregunta?