Diseñando una clase alrededor de los hooks de WordPress

Ésta es una traducción de un articulo inglés. Puedes encontrar el articulo original en inglés aquí.

¿Conoces este hombre “Carl”? Siempre está hablando de la programación orientada a objetos. Incluso te convenció de tentar a aprender el sujeto.

Tentaste de aplicar parte de lo que enseña creando una clase. Comenzaste a escribir el código por eso. Y luego sucedió. Necesitaste usar un hook (o gancho) de WordPress.

¿Qué haces con ellos?

Tres soluciones posibles

Haces un poco de investigación sobre el Internet. Tu investigación te descubre tres métodos para resolver el problema con los hooks de WordPress. Puedes poner todos tus hooks en el método :

  • En el método __construct de tu clase.
  • En un método separado de tu clase.
  • Al exterior de tu clase.

Ahora, el diseño es todo sobre encontrar soluciones a un problema. Todos son soluciones valides al problema : ¿Cómo enganchar un objeto dentro WordPress? Has resuelto el problema y funciona. ¿Entonces, cuál es el problema?

El problema es como manejas los hooks de WordPress en tu clase. Es de eso que se tratan las opciones 1 y 2. Pero uno es mejor que el otro.

Opción 1 funciona, pero es una solución débil. No entiende el rol del constructor. Por otra parte, la opción 2 lo entiende. Mientras no recreas el mismo problema que la opción 1.

La tercera opción no hace nada malo. Eso es porque no tienta de resolver el problema en la clase. ¿Y sabes qué? Está bien.

No confundirás el propósito del constructor de esa manera.

El rol del constructor

El trabajo del constructor es de crear el estado inicial de un objeto. Espero que todos pueden estar de acuerdo con eso. (¡Esperemos!) El problema comience cuando tentando de determinar el límite de ese trabajo.

El constructor está solamente en cargo del estado INTERNO inicial de un objeto. Eso es el origen del problema con tomar los hooks de WordPress en el constructor.

Los hooks de WordPress tienen nada a hacer con la configuración del estado interno inicial de un objeto. De la perspectiva del diseño orientado a objetos, enganchando dentro WordPress es un trabajo separado. Es mejor de manejarlo como tal. O al menos, es una mejor práctica para ti.

Pruebas unitarias

En ninguna parte es eso más obvio que cuando tientas de probar tu código. Las pruebas unitarias son un tema enorme y a menudo mal entendido. No vamos a investigar el concepto mucho aquí ya que es bastante complejo.

Sin embargo, hay una cosa crucial a comprender sobre las pruebas unitarias. Es que necesitas ejecutar cada prueba en aislamiento. También una prueba unitaria ideal solamente ejecuta el código que deseas probar.

No es posible todo el tiempo. Dicho eso, deberías esforzarte de ejecutar el menor código posible durante una prueba. Es un habito importante con pruebas unitarias.

No puedes lograr eso si tus hooks están en el constructor. Eso es porque no puedes crear una instancia de tu clase sin cargar WordPress. Pero una prueba unitaria no debería necesitar ninguno (o casi ninguno) código de WordPress para hacer su trabajo.

Digamos que no puedes probar tu código. Eso es un indicador fuerte que alguna cosa es mala con el diseño de tu código. El problema aquí es el acoplamiento alto a WordPress en tu constructor.

Cómo arreglar el problema

Ahora veamos diferentes maneras en que podemos arreglar el problema.

Usando un método separado

Poner tus hooks de WordPress en un método separado (opción 2) es una excelente (y simple) manera de resolver el problema. Sólo necesitas reorganizar tu código un poco. Eso es.

Sin embargo, tienes que ser cuidadoso. Todavía es posible hacerlo mal. Es la primera cosa que la veremos.

class MiPlugin
{
    public function __construct()
    {
        $this->iniciar();
    }
 
    public function iniciar()
    {
        add_action('wp_loaded', array($this, 'en_cargado'));
    }
 
    public function en_cargado()
    {
        // ...
    }
}

Puedes ver la clase MiPlugin que tiene el método iniciar con todos nuestros hooks de WordPress. Esta parte es buena. El problema es que lo estás llamando todavía desde nuestro constructor. Esto no resuelve el problema de acoplamiento en absoluto.

class MiPlugin
{
    public function iniciar()
    {
        add_action('wp_loaded', array($this, 'en_cargado'));
    }
 
    public function en_cargado()
    {
        // ...
    }
}
 
$mi_plugin = new MiPlugin();
$mi_plugin->iniciar();

Puedes arreglar esto por eliminar el método ‘iniciar’ del constructor. En lugar de llamarlo ahí, lo llamaste al exterior de tu clase. El resultado es lo mismo, pero eliminaste el acoplamiento de tu clase a WordPress.

Usando un constructor personalizado

Puedes hacer también eso por usar un método estático como constructor personalizado. No es algo que ves usado mucho. (¡A la excepción de esto sitio!) Pero es una manera elegante de hacer alguna cosa como la opción 1.

class MiPlugin
{
    public static function iniciar()
    {
        $self = new self();
        add_action('wp_loaded', array($self, 'en_cargado'));
    }
 
    public function en_cargado()
    {
        // ...
    }
}
 
MiPlugin::iniciar();

Cambiamos el método init en un método estático. new self() crea nuestro objeto que luego pasamos a los hooks de WordPress. Nuestra clase continúa de manejar todo (incluyendo la construcción). Sin embargo, redujiste el acoplamiento de tu clase a WordPress.

Entonces, ¿cómo cargas los hooks de tu clase de esta manera? Tienes dos opciones disponibles para ti. Puedes llamar el método iniciar inmediatamente después de definiste tu clase. Puedes crear también un plugins_loaded hook con un array de pseudo-tipo callback al método iniciar.

class MiPlugin
{
    public static function iniciar()
    {
        $self = new self();
        add_action('wp_loaded', array($self, 'en_cargado'));
    }
 
    public function en_cargado()
    {
        // ...
    }
}
 
add_action('plugins_loaded', array('MiPlugin', 'iniciar'));

¿Porque usar este hook y no un otro? Es el primero hook que WordPress llama cuando hay terminado cargando todos los plugins. Está ahí para prevenir conflictos poténciales o problemas.

Usando una función externa

Es posible que no hayas notado, pero mucho de ese código es casi idéntico al que verías en la opción 3. La diferencia entre los dos es que la opción 3 elimina todo el acoplamiento con WordPress. Te moviste todo ese código en una función al exterior de la clase.

class MiPlugin
{
    public function en_cargado()
    {
        // ...
    }
}
 
function carga_mi_plugin()
{
    $mi_plugin = new MiPlugin();
    add_action('wp_loaded', array($mi_plugin, 'en_cargado'));
}
add_action('plugins_loaded', 'carga_mi_plugin');

Este ejemplo usa una función con el hook plugins_loaded. Sin embargo, ésa no es la única manera de hacerlo. Ni siquiera necesitas usar una función. Puedes sólo enganchar todo debajo la clase si no te estás preocupado por los conflictos.

class MiPlugin
{
    public function en_cargado()
    {
        // ...
    }
}
 
$mi_plugin = new MiPlugin();
add_action('wp_loaded', array($mi_plugin, 'en_cargado'));

Tienes muchas opciones

Entonces, ¿cuál es la mejor opción? Es una pregunta valida a preguntarte. A este punto, la respuesta depende de ti. No hay respuesta correcta.

Puedes encontrar este frustrante. La verdad es que así es como funciona el diseño de software. No hay siempre una solución perfecta en diseño. A menudo tienes que hacer compensaciones.

¿Deseas que tu código esté un poco más acoplado? De esa manera puedes mantener un poco de contexto. ¿O te desacoplas todo? ¿Te importa de usar un constructor personalizado? ¿O es un método bien? Necesitas tomar una decisión.

Vamos a mantener los hooks de WordPress fuera del constructor. ¿De acuerdo?

Deja un comentario

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