Dale vida a tu WordPress, el programador de tareas

2020-07-17 - Categorías: PHP / WordPress

WordPress también dispone de un mecanismo para programar acciones en el tiempo, un programador de tareas, al que también podemos llamar el Cron de WordPress. En este post dejo unos howtos o codekatas muy sencillos, para lanzar estas acciones en el tiempo.

He probado bien estas cosas en jnjsite.com, y les comparto aquí algunos resultados. Aparte de las formas de uso, dejo también algunos trucos para mejorar el rendimiento. También dejaré algunas referencias a la documentación oficial que está muy bien, para el que quiera seguir avanzando con el tema.. ?

Originalmente cómo se lanza el programador de tareas

En una instalación limpia de WordPress, su programador de tareas viene en el fichero wp-cron.php. Este programador de tareas inicialmente se ejecuta con cada petición que recibimos a la web. Sí, con cada petición. Esto puede ser un problema, incluso puede llegar a bloquear la web: si hay algo enganchado, quizá una tarea algo pesada que se ejecuta durante demasiado tiempo, por tener muchas visitas y estar contínuamente comprobando las tareas programadas, etc..

En instalaciones de WordPress con muchas visitas, se vuelve entonces totalmente necesario desacoplar el Cron. Pensemos que si por ejemplo tenemos 10-20-100 peticiones por minuto, y la tarea de menor intervalo se ejecuta cada 1 hora, ¿porqué vamos a comprobar el Cron con cada petición a la web? Sería excesivo..

Debemos entonces desacoplar las visitas de la ejecución del Cron..

Desacoplar el Cron de las visitas

Como se explica en el apartado anterior, es necesario desacoplar el Cron de cada petición a la web. Para desacoplarlo tendremos que hacer dos cosas:

  1. Quitarlo de la ejecución normal con cada click de cada visitante, con una configuración.
  2. Engancharlo al sistema operativo del servidor.

Para quitarlo de la ejecución normal tenemos que poner lo siguiente en el fichero de configuración wp-config.php. Al principio del fichero:

define('DISABLE_WP_CRON', true);

Para engancharlo al sistema operativo, tendremos que configurar alguna de forma de lanzarlo desde el servidor. Por ejemplo en jnjsite.com, lo tenemos programado a cada 5 minutos con el crontab del servidor GNU/Linux en donde está alojado. Para hacer esto, basta con poner la siguiente línea en el programador de tareas de GNU/Linux:

*/5 * * * * php /ruta/al/directorio/de/la/web/wp-cron.php > lastCron.log

Cómo utilizar el programador de tareas de cada sistema operativo podría ser contenido para otro post, así que lo dejo aquí. Vayamos ahora a programar en PHP unas acciones..

Caso sencillo, unas acciones en el tiempo

Si miramos la documentación oficial, tendremos varias secciones explicando el funcionamiento. Si agrupamos todo en un pequeño script, así nos quedarían los códigos necesario para ejecutar una acción a cada hora y podríamos ponerlo en un plugin:

// La tarea programada que hace algo..
function jnj_cron_do_something()
{
    /**
     * Aquí el código de todas las acciones que se ejecutarán cada hora.
     */
}
// Engancha la tarea al hook de tarea programada..
add_action('jnj_cron_do_something_hook', 'jnj_cron_do_something');

// Si el hook de tarea programada no está programado, se programa..
if (!wp_next_scheduled('jnj_cron_do_something_hook')) {
    wp_schedule_event(time(), 'hourly', 'jnj_cron_do_something_hook');
}

Este script hace 2 cosas: una es enganchar un hook de ejecución a 1 hora, y la otra es enganchar a dicho hook la ejecución de una función. Esto se puede copiar y pegar, y usar en nuestro plugin de turno, por ejemplo en un fichero /wp-content/plugins/jnj-scheduler.php. Su contenido para hacer lo anterior podría quedar tal que así:

<?php
/**
 * Plugin Name: A plugin for scheduling tasks
 * Plugin URI: https://jnjsite.com/
 * Description: A tiny plugin that schedules tasks
 * Version: 1.0
 * Author: Jaime Niñoles
 * Author URI: https://jnjsite.com/.
 */
defined('ABSPATH') or die('No no no');
define('JNJCRON_PATH', plugin_dir_path(__FILE__));

// La tarea programada que hace algo..
function jnj_cron_do_something()
{
    /**
     * Aquí el código de todas las acciones que se ejecutarán cada hora.
     */
}
// Engancha la tarea al hook de tarea programada..
add_action('jnj_cron_do_something_hook', 'jnj_cron_do_something');

// Si el hook de tarea programada no está programado, se programa..
if (!wp_next_scheduled('jnj_cron_do_something_hook')) {
    wp_schedule_event(time(), 'hourly', 'jnj_cron_do_something_hook');
}

Luego tendremos que activarlo en el backend de WP, en la sección de plugins. Se verá algo como lo siguiente:

Custom WP plugin for scheduling tasks..

Una vez activado, comenzará a ejecutarse la tarea programada..

Cada cuanto tiempo podemos lanzar acciones

Lo siguiente a tener en cuenta es que WordPress no ejecuta cualquier tipo de programación. Por lo menos no es tan flexible, inicialmente, como un programador de tareas de GNU/Linux. Si necesitamos distintos horarios o flexibilidades, podremos ampliar funcionalidades programando un poco.

Por defecto, WP sólo permite los siguientes intervalos:

  • hourly
  • twicedaily
  • daily
  • weekly

Pero como indico, se puede ampliar como vemos a continuación..

Añadir eventos, e intervalos de tiempo, para lanzar las acciones

Para añadir más intervalos, jugando con un plugin, podemos hacer cosas como lo siguiente:

function wgojnj_add_cron_interval($schedules)
{
    $schedules['minutely'] = [
        'interval' => 60,
        'display' => esc_html__('Every Minute'), ];
    $schedules['five-minutes'] = [
        'interval' => 300,
        'display' => esc_html__('Every 5 Minutes'), ];
    $schedules['ten-minutes'] = [
        'interval' => 600,
        'display' => esc_html__('Every 10 Minutes'), ];
    $schedules['half-hour'] = [
        'interval' => 1800,
        'display' => esc_html__('Half Hour'), ];
    $schedules['six-hours'] = [
        'interval' => 3600*6,
        'display' => esc_html__('Six Hours'), ];

    return $schedules;
}
add_filter('cron_schedules', 'wgojnj_add_cron_interval');

Ahora hemos definido los intervalos six-hours, half-hour, ten-minutes, five-minutes y minutely. Simplemente ya podemos usar esos intervalos en la función anterior que hemos usado, por ejemplo:

wp_schedule_event(time(), 'minutely', 'jnj_cron_do_something_hook');

Ejecución de tareas a ciertas horas exactas

Lo siguiente que podemos querer hacer es eso, podemos hacer por ejemplo que cada día a las 2 de la madrugada ejecute una tarea concreta usando lo siguiente:

wp_schedule_event(strtotime('02:20:00'), 'daily', 'jnj_cron_do_something_hook');

Es sencillo, simplemente hay que usar el primer parámetro poniendo la hora, y en el segundo un intervalo diario.

Ejecución sólo una vez de una tarea

Supongamos ahora que queremos hacer una tarea sólo una vez. Queremos programar algún arreglo en producción, alguna acción puntual de mantenimiento, etc.. pero sólo queremos ejecutarla una vez. Esto podemos hacerlo como en el apartado anterior, definiendo un intervalo grande y luego borrar la tarea. O podemos usar la función wp_schedule_single_event.

Es decir, hay otra opción, por ejemplo si al dar a un botón le ponemos lo siguiente:

wp_schedule_single_event( time() + 3600, 'jnj_cron_do_something_hook' );

..se lanzará dentro de 1 hora (3600) la ejecución del hook jnj_cron_do_something_hook.

Esta función es muy parecida a la anterior.. ¡Pero ojo! No se puede poner esta función en un plugin o theme en cualquier sitio, porque se programaría contínuamente esta acción con cada click. Se puede usar y lanzar al recibir un click como acción puntual del usuario, o un evento que lo desencadene.

Cómo comprobarlo todo y asegurarnos de que no va a fallar

A lo anterior queda pensar, entonces, ¿cómo puedo asegurarme de que la tarea programada va a funcionar correctamente?

Muy fácil, te propongo tres opciones:

  • Una es programar la tarea cambiando el intervalo, y esperando cada vez que programes algo en la tarea para comprobarlo. No es muy eficiente.
  • La segunda opción es lanzar el programador de tareas desde línea de comandos usando ‘php wp-cron.php’ y así poder ver si funciona.
  • La tercera y creo que mejor opción, es poner la tarea programada en una función, y llamarla desde un script externo.

Me explico, la función anterior que realiza la tarea, es la que se ejecuta con cada cron:

function jnj_cron_do_something()
{
    /**
     * Aquí el código de todas las acciones que se ejecutarán cada hora.
     */
    echo 'Aquí podemos escribir información para ver si todo funciona bien..'.PHP_EOL;
}

A esta función podemos llamarla desde línea de comandos con un sencillo script como el siguiente. Si lo ponemos en el directorio raiz del proyecto este fichero test_my_new_cron.php

<?php
require __DIR__.'/wp-load.php';

jnj_cron_do_something();

Ya sólo quedará programar nuestro plugin por un lado, mientras que vamos a línea de comandos y lanzamos lo siguiente para comprobarlo:

php test_my_new_cron.php

Me remito a un post anterior relacionado sobre scripts para WordPress desde línea de comandos para más información.

Un plugin, WP Crontrol, para visualizarlo todo

De los plugins que he visto relacionados he encontrado el WP Crontrol que me ha gustado mucho. Con este plugin puedes ver lo que hay programado, intervalos disponibles, y añadir eventos nuevos con su programación.. Incluso te deja programarlos en el backend, aunque esto puede ser algo peligroso.. ?

WP Crontrol oficial website into WordPress.org

Por ejemplo, un listado de los eventos programados vistos desde WP Crontrol podría ser como el siguiente:

WP Crontrol localhost
WP Crontrol, listando eventos programados.

Un listado de los intervalos de tiempo programados anteriormente en este post se verían como lo siguiente:

WP Crontrol schedules
WP Crontrol, listando intervalos de tiempo disponibles.

Terminando y referencias

Para terminar sólo me queda remitirte a la documentación oficial:

Deja una respuesta

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

 

© 2024 JnjSite.com - MIT license

Sitio hecho con WordPress, diseño y programación del tema por Jnj.