Hooks de WordPress explicados de manera sencilla

Voy a intentar explicar los Action Hooks de WordPress de la manera más sencilla posible. A los programadores principiantes les resulta un poco complicado entender este concepto. Es normal si no se ha trabajado nunca en un software que tenga este tipo de arquitectura. Se presuponen conocimientos básicos de programación en PHP. No es necesario conocer nada de la arquitectura de WordPress.

Para ello voy a partir de un supuesto. Una aplicación sencilla que no tiene relación con WordPress. En ella disponemos de dos plantillas para personalizar la cabecera (header.php) y el pie (footer.php).

header.php

<?php
/* header.php */

?>
<html>
<head>
    <title>Nuestro titulo</title>
</head>
<body>
<?

footer.php

<?php
/* footer.php */
?>
</body>
</html>
<?php

Como queremos personalizar el estilo de nuestra página decidimos editar directamente el header.php para enlazar una hoja de estilos. La incrustamos justo antes del tag title.

    <link rel="stylesheet" href="estilos.css" />
    <title>Nuestro titulo</title>

Esta solución funciona pero editar directamente un archivo de la aplicación tiene un problema. Cuando el equipo que desarrolla la aplicación nos entregue una nueva versión del header.php habremos perdido nuestros cambios. Y tendremos que editarlo de nuevo.

¿Cómo se podría evitar esto?

Podríamos pedirle al equipo que mantiene header.php que lo modifique de esta manera:

<?php
/* header.php */

?>
<html>
<head>
    <?php
        if (file_exists('custom_head.php')):
            include 'custom_head.php';
        endif
    ?>
    <title>Nuestro titulo</title>
</head>
<body>
<?

En el fichero custom_head.php es donde vamos ahora a realizar las modificaciones deseadas:

<?php
/* custom_head.php */

?> <link rel="stylesheet" href="estilos.css" /> <?php

De esta forma tan sencilla el problema queda resuelto. Acabamos de diseñar un mecanismo por el que es posible incluir código personalizado en un punto concreto de la aplicación.

La aplicación no sabe nada de nuestro código. De hecho si el fichero custom_head.php no existe ni siquiera se incluirá nada. Este concepto es en el que se basan los Action Hooks de WordPress.

Poniendo un nombre a nuestros Action Hooks

En nuestro ejemplo anterior hemos decidido llamar custom_head.php al fichero que puede emplearse (opcionalmente) para incluir código antes del tag <title>.

¿Pero que ocurre si quisieramos incluir también contenido después de dicho tag? Efectivamente. Podemos añadir otro bloque if y un nuevo fichero.

Ahora tenemos dos puntos diferentes en los que podemos incrustar código. Para evitar confusiones vamos a cambiar el nombre de custom_head.php por before_title.php. El nuevo fichero se llamará after_title.php.

Con esto podemos afirmar que hemos creado nuestros propios Action Hooks:

  • before_title.php: para añadir código antes del título
  • after_title.php: para insertar el código después del título

El nombre de los Action Hooks es muy importante. Con él indicamos la posición exacta en la que deseamos ejecutar nuestro código.

En nuestro ejemplo el equipo que desarrolla la aplicación debería escribir documentación en la que se nos indica el nombre los ficheros que podemos utilizar para añadir nuestro propio código.

Mejorando el diseño de nuestros ganchos

Este sistema funciona pero tiene algunos inconvenientes:

  • Es poco eficiente: el acceso continuo al sistema de ficheros incluso para la más pequeña de las acciones puede suponer una penalización importante en el tiempo de carga del sistema.
  • Tiene sus limitaciones: dos personas que quieran incorporar código en el mismo punto tienen que ponerse de acuerdo ya que tendrán que editar el mismo archivo. No existe una manera de regular la prioridad.

Afortunadamente podemos solucionar esto de manera muy sencilla. Vamos a abandonar la verificación de la existencia de ficheros con ciertos nombres para la inserción del código.

En vez de eso vamos a guardar esta información en la memoria. En una variable global que indique la lista de tareas a ejecutar para cada posición (nombre del hook) y la prioridad que tiene cada una de ellas.

Ya lo tenemos. Así es como funcionan los Action Hooks de WordPress. Vamos a ver los detalles concretos.

La función do_action de WordPress define el punto de ejecucción del action hook

Esta es la definición de la función do_action de WordPress

function do_action( string $tag,  $arg = '' ) {

Donde:

  • $tag: es una cadena de caracteres que indica el nombre del Action Hook
  • $arg: es opcional. Son argumentos adicionales que se pasan a nuestro Action Hook

La documentación de WordPress dice lo siguiente:

Esta función invoca todas las funciones adjuntas al gancho de acción $tag. Es posible crear nuevos ganchos de acción simplemente llamando a esta función, especificando el nombre del nuevo gancho a através del parámetro $tag. Se pueden pasar argumentos a los ganchos de acción.

Utilizando do_action en nuestra aplicación de ejemplo

Para terminar de entenderlo vamos a "migrar" nuestra aplicación de ejemplo al modelo de WordPress. Vamos a crear los ganchos que teníamos en el fichero header.php:

<?php
/* header.php */

?>
<html>
<head>
    <?php do_action('before_title'); ?>
    <title>Nuestro titulo</title>
    <?php do_action('after_title'); ?>
</head>
<body>
<?

Así de simple. Ya hemos definido dos ganchos de acción. Llegado a este punto WordPress echará un vistazo a la tabla de Hooks. Y si encuentra en ella alguno que se llame before_title o after_title lo ejecutará.

Ahora sólo nos falta ver como añadimos los hooks a la tabla. Es lo que vamos a ver a continuación. Para ello vamos a utilizar add_action: la función que WordPress nos proporciona para adjuntar funciones a los ganchos de acción.

La función add_action nos permite conectar funciones con los ganchos de acción

La función add_action es el complemento de do_action.

  • Con do_action creamos puntos de acción.
  • Con add_action definimos qué funciones deben ejecutarse en dichos puntos.

Su definición es la siguiente:

function add_action( string $tag, callable $function_to_add, int $priority = 10, int $accepted_args = 1 ) {

Donde:

  • $tag (requerido): el nombre del Action Hook
  • $function_to_add (requerido): callable de la función a la que se debe llamar
  • $priority (opcional): se usa cuando existen varias funciones definidas para el mismo action hook. Con este parámetro podemos indicar en qué orden deben ejecutarse.
  • $accepted_args (opcional): número de parámetros que la función acepta

Finalizando nuestro ejemplo con add_action

Vamos a terminar la adaptación de nuestra aplicación de ejemplo al modelo de ganchos de WordPress. Ya tenemos el header.php migrado. En nuestros ganchos caseros el código a ejecutar en cada punto lo insertabamos dentro de ficheros externos que definíamos en el punto de inserción del gancho. En este caso ya no existen dichos ficheros.

En vez de eso podemos llamar a add_action desde cualquier otro fichero. La única condición es que se ejecute antes el código add_action que el do_action. En WordPress se suele insertar en el fichero functions.php de nuestro tema. En nuestro ejemplo deberíamos añadirlo en un punto que se ejecute antes de header.php:

<?php
add_action('before_title', 'gancho_antes_titulo');
add_action('after_title', 'gancho_despues_titulo');

function gancho_antes_titulo() {
?><link rel="stylesheet" href="estilos1.css" /><?php
}

function gancho_despues_titulo() {
?><link rel="stylesheet" href="estilos2.css" /><?php
}

Como vemos tenemos que definir dos funciones. Una para cada gancho de acción. Conectamos la función con el gancho mediante llamadas a add_action.

Habíamos dicho que una ventaja de este sistema era la gestión de prioridades. Aquí tenéis un ejemplo:

<?php
add_action('before_title', 'gancho_antes_titulo', 10);
add_action('before_title', 'gancho_antes_titulo_ejecutar_antes', 5);

function gancho_antes_titulo() {
?><link rel="stylesheet" href="estilos.css" /><?php
}

function gancho_antes_titulo_ejecutar_antes() {
?><link rel="stylesheet" href="estilos-prioritarios.css" /><?php
}

Hay dos funciones definidas para el mismo gancho. El tercer parámetro de add_action nos permite indicar la prioridad de ejecucción. Por defecto el valor es 10. Las funciones definidas con valores inferiores se ejecutan primero.

Conclusión

WordPress es un software que cuenta con una arquitectura bien diseñada que utiliza el Hooking como mecanismo para extender, limitar o personalizar el comportamiento de la aplicación.

Los Action Hooks nos permiten adecuar el sistema a nuestras necesidades evitando tocar los ficheros "core" del sistema. Esto evita la pérdida de nuestro trabajo cuando se actualiza el núcleo de WordPress así como algunos ficheros concretos de temas o plugins

Para definir un nuevo gancho de acción se emplea la funcion do_action y para conectar funciones con dicho punto se utiliza add_action. Aunque no lo hemos mencionado también existe la funcion remove_action que permite la eliminación de funciones "enganchadas" a los ganchos de acción.

El principio de funcionamiento de un action hook se basa en la creación de puntos de control en los cuales se indica al sistema la opción de ejecutar instrucciones concretas situadas en cualquier otro lugar. El dominio de estos mecanismos nos permite escribir plugins y temas estructuralmente correctos y nos ayuda a depurar problemas.