Crear un child theme en WordPress

La creación de un child theme nos da la posibilidad de adaptar un theme pre existente a nuestro gusto. Cambiar algunas fuentes, espaciado, colores e incluso funciones de un theme que nos gusta para no tener que escribirlo de cero.

La principal ventaja de hacerlo a través de un child theme, en vez de modificar el theme original, radica en que cuando se actualice el theme original no perderemos nuestras modificaciones obteniendo así lo mejor de dos mundos, actualizaciones y personalización.

Como desventaja, agregamos una capa más que tiene que ser ejecutada sobre el theme original lo que podría, aunque no debería, hacer más lenta la carga del sitio. Además, dependiendo de la profundidad de las modificaciones, puede ocurrir que una actualización del theme original entre en conflicto con el child theme pero, nuevamente, es raro que ocurra.

El principio de funcionamiento de los child themes es que cualquier template que tengamos en nuestro theme, será ejecutado en vez del homónimo en el theme original. Es decir, si en nuestro child theme creamos un comments.php, este será ejecutado en vez del archivo incluido en el parent theme.

La única excepción a esto son los archivos functions.php que ámbos serán ejecutados, primero el del child theme y luego el del parent.

Para poder crear un child theme es necesario que el tema «padre» o parent esté instalado y tener acceso al directorio themes de tu sitio con permisos de escritura.

Los pasos serían:

  1. Accede a la carpeta donde tienes alojado los themes.
  2. Crea una nueva carpeta donde se alojará tu child-theme. Si no se te ocurre ningun nombre, una buena opción es <nombre del theme original>-child
  3. Crea los archivos functions.php y style.css
  4. Agrega el contenido mínimo a cada archivo
/*
 Theme Name:   <nombre de nuestro theme>
 Theme URI:    <url>
 Description:  <descripción>
 Author:       <autor>
 Author URI:   <url-autor>
 Template:     <nombre de la carpeta del theme padre>
 Version:      <versión de nuestro theme>
 License:      <licencia>
 License URI:  <url de la licencia>
 Text Domain:  <text domain>
*/

El nombre del theme tiene que ser único, no puede ser el mismo del parent.

En template, va únicamente el nombre de la carpeta del theme para el que estamos creando el child.

Al momento de elegir licencia es importante tener en cuenta que sea compatible con la licencia del tema original.

Si no vamos a cambiar los strings del theme original, no hace falta especificar el text-domain.

<?php
add_action( 'wp_enqueue_scripts', 'my_theme_enqueue_styles' );
function my_theme_enqueue_styles() {
    wp_enqueue_style( '<parent-theme>', get_template_directory_uri() . '/style.css' );
 
    wp_enqueue_style( 'child-style',
        get_stylesheet_directory_uri() . '/style.css',
        array( '<parent-theme>' ),
        wp_get_theme()->get('Version')
    );
}

En los child themes get_template_directory_uri() nos devuelve el path al directorio del theme original y get_stylesheet_directory_uri() nos devuelve el path al directorio del child theme.

¿Por qué cargamos el stylesheet del parent theme si ya lo hace este automáticamente? Porque los hooks, a menos que les indiquemos específicamente lo contrario, se ejecutan en el orden en que fueron cargados. Entonces, si no agregamos el stylesheet del parent theme en nuestro functions.php, este se va a cargar después del nuevo stylesheet haciendo que los cambios no se vean.

Es importante que hagamos el enqueue del parent theme con el mismo handle que en el theme original para evitar que se cargue dos veces. Si estuviéramos extendiendo o modificando el theme Divi, habría que reemplazar parent-theme por divi-style. Este dato lo podemos encontrar en el propio functions.php del parent theme.

Además, como se muestra en el ejemplo, es importante utilizar en el nombre de las funciones que creemos un prefijo único para evitar que colisionen con otras funciones del parent theme u otros plugins.

Una vez cargados los archivos, y las modificaciones del caso, el theme aparecerá junto a los demás en la sección Apariencia. Es importante recordar que no podemos eliminar el parent theme mientras esté activo el child.

Errores comunes cuando empezamos a utilizar React

Olvidar la clave de los elementos al usar map

Si bien no es un error, por eso únicamente genera una advertencia, el uso de keys (claves) es una práctica altamente recomendada. Las keys en los elementos de una lista permiten individualizarlos y tratarlos de forma independiente del resto de la lista y de su orden dentro de la misma.

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) =>
    <li>
      {number}
    </li>
  );
  return (
    <ul>{listItems}</ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
ReactDOM.render(
  <NumberList numbers={numbers} />,
  document.getElementById('root')
);

Este código devuelve la siguiente lista:

<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
</ul>

Si agregamos el elemento 0 (cero) al arreglo numbers, obtendríamos

<ul>
  <li>0</li>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
  <li>5</li>
</ul>

Es el resultado que queríamos obtener, ¿qué diferencia hacen entonces las keys?

Las keys lo que hacen es cambiar drásticamente la eficiencia en la React hace los cambios al DOM. Sin las keys, se hace una comparación elemento a elemento de la lista anterior con la nueva basados en su posición dentro de la misma, el primer elemento de la vieja se compara con el de la nueva y así sucesivamente. Si hay una diferencia con entre estos elementos React se encarga de mutar el DOM para reflejarlo.

En este caso, el primer elemento de la lista vieja es el 1 y el de la nueva el 0 por lo que se cambia el DOM; los siguientes elementos a comparar son el 2 de la vieja y el 1 de la nueva con lo que se vuelve a cambiar el DOM. Así hasta recorrer toda la lista. En la práctica para agregar un nuevo elemento en una lista con cinco ítems, hacemos 6 cambios en el DOM.

Si tenemos las keys asignadas, cada elemento de la lista vieja se compara con el elemento que tenga la misma key en la lista nueva. Entonces, los elementos preexistentes que no hayan sido modificados, todos en este caso, se mantienen, no generan mutaciones en el DOM. Únicamente se agrega un elemento para reflejar el nuevo ítem del arreglo y se hace un cambio para actualizar el DOM.

Devolver más de un componente o elemento

El método render de React espera recibir un componente o elemento, todo el demás contenido que queramos incluir tiene que estar anidado dentro de este. Construcciones al estilo:

<img src="..." alt="..."><br>

<label for="...">...</label><input type="...">

<h3>...</h3>
<p>...</p>

Todas son correctas en lo que a HTML respecta pero son erróneas como return del método render.

Olvidarnos de exportar los componentes

// Mensaje.js
import React, {Component} from 'react';

class Mensaje extends Component {
    render() {
        return (
            <div className="mensaje">{ this.props.texto }</div>
        );
    }
}
// index.js
import React, { Component } from "react";
import { render } from "react-dom";

import Mensaje from './Mensaje.js';

class App extends Component {
    render() {
        return (
            <div>
                <h3>Mi mensaje</h3>
                <Mensaje texto="Hola Mundo!" />
            </div>
        );
    }
}

render( <App />, document.getElementById('root') );

Al correr este código obtendremos el siguiente error:

Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components). Check the render method of `App`.

Podemos revisar letra por letra el contenido del método render del componente App y no vamos a encontrar ningún error porque el problema está en Mensaje.js. Si lo revisamos atentamente podemos ver que nos faltó exportar la clase por defecto por lo que cuando importamos en App, terminamos con una variable apuntando a la nada misma en vez de al componente esperado.

En este caso, al tener 4 líneas únicamente el componente App es muy sencillo darnos cuenta que el error no se encuentra en este pero, en una aplicación más grande, con varios componentes externos y un par de operadores ternarios puede ser muy difícil detectarlo.

Modificar el estado de forma directa

Uno de los principios de funcionamiento de React es la inmutabilidad de la propiedad state del componente. Aunque dicha inmutabilidad no es (era) posible de garantizar en tiempo de ejecución por lo que el siguiente código será ejecutado sin generar errores ni advertencias de ningún tipo:

this.state.contador = 0;

Pero en la próxima llamada a setState el cambio será descartado de forma silenciosa provocando que el código no funcione de la forma esperada pero sin generar ningún tipo de error.

Añadir cosas al estado que no están relacionadas con el renderizado del componente

Cada vez que se realiza un cambio en el estado de un componente este va a ser renderizado de nuevo por lo que es importante no incluir en el mismo atributos que no tengan que ver con el render.

Por ejemplo, si creamos un componente encargado de subir un archivo vía ajax e incluimos una barra de progreso que permite ver el porcentaje de carga y usamos un atributo del estado para llevar el control del porcentaje, cada vez que este varíe el componente va a volver a ser renderizado provocando la interrupción de la carga en el peor de los casos y que en el componente sea renderizado 100 veces en el mejor.

Ídem si creamos un componente que ejecute una acción cada x segundos y guardamos un contador de las veces que fue ejecutado en el estado.

La forma correcta de guardar este tipo de datos es utilizar variables específicas de la instancia.

var counter = 0;
var timer;

componentDidMount() {
    timer = setInterval(this.tick, 1000);
}

tick() {
    this.counter++;
}

componentWillUnmount() {
    this.clearInterval(this.timer);
}

render() {
  <div>Ejecuciones: { this.counter } </div>
}

En la misma línea de lo antedicho, cualquier dato que pueda ser calculado a través de las propiedades pasadas al componente tampoco debería ser almacenada en el estado.

No usar propTypes

Muchos errores en el funcionamiento de nuestros componentes pueden ser difíciles de detectar si no utilizamos propTypes. Esta librería nos permite especificar exactamente el tipo de dato que esperamos recibir y tira un error cuando esto no ocurre permitiendo saber dónde empezar a buscar el problema.

Pasar props numéricos como strings

Si pasamos a nuestro componente a través de las propiedades un valor numérico entrecomillado, ese valor va a ser pasado como un string. Si queremos que el tipo sea correcto tenemos que recurrir a las llaves como cuando pasamos el valor de las variables.

<Componente num={13} />

Olvidarse que el método setState es asincrónico

Las llamadas a setState se ejecutan de forma asincrónica por lo que no podemos fiarnos que el estado se modifique inmediatamente y, por lo tanto, que las evaluaciones que hagamos basados en el mismo reciban el estado actualizado en el momento de realizado el cambio.

setState({contador: this.state.contador + 1});
if (contador >= 5) {
    // ...
}

El bloque condicional del código anterior no se puede asegurar que se vaya a ejecutar cuando contador sea igual a 5. Dependiendo de lo que tarde en actualizarse el estado puede que cuando lo haga, el contador valga 6 o 7.

Usar class en vez de className

A menos que estemos utilizando React en conjunto con los Web Components [note]Por ahora únicamente tienen soporte en Chrome por lo que es poco probable.[/note], si queremos asignar una clase CSS a un elemento HTML, tenemos que utilizar className.

<div className="container">...</div>

No comenzar el nombre de un componente con mayúscula

Para React, los componentes se diferencian de las etiquetas HTML mediante el nombre. Si el nombre comienza con mayúscula se considera un componente y se lo compila como los demás. Si el nombre comienza con minúscula se considera una etiqueta HTML y se pasa como un string, es decir, no va a ser compilado con todas sus consecuencias.

Cuándo (no) usar módulos o librerías externas en JavaScript

Cuándo no sabemos cómo programar la funcionalidad

Los módulos o librerías tienen que simplificar el proceso de desarrollo, no reemplazarlo. Su función es agilizar la escritura de código aportando una capa de abstracción sobre una funcionalidad cuyo desarrollo es complejo o engorroso. Si no sabemos cómo se hace algo, difícilmente podamos resolver los errores que surjan o sacar el máximo provecho a la herramienta que estamos usando.

Cuándo la funcionalidad aportada por el módulo o librería es mínima

Para entender esto nada mejor que referirnos a la historia de left-pad y como la baja por parte de su autor del módulo de 11 líneas de código provocó lo más parecido a un apocalipsis informático desde el Y2K. Casos similar es el módulo isarray con una línea de código y 10 millones de descargas semanales. Es necesario encontrar un balance, externalizar funciones muy sencillas nos expone a ciertos riesgos que no los corremos con módulos o librerías más complejas; no hacerlo implica tener que escribir más código con lo cual podemos cometer más errores pero nos aseguramos que esté siempre disponible y sea funcional en nuestro ecosistema.

Cuándo vamos a utilizar una única función de una librería multipropósito o general

Es muy común ver en una página, Bootstrap y sus dependencias jQuery, Hammer.js y Popper.js al completo para utilizar una grilla para acomodar los contenidos o jQuery, jQuery UI, y Select2 para implementar un select con autocomplete o, más últimamente, React + Babel para mostrar un sitio a todos los efectos estático del lado del cliente. Si únicamente vamos a necesitar una funcionalidad específica es más que probable que existan algunas librerías específicas o que su implementación sea lo suficientemente sencilla para que podamos crear nuestro propio módulo.

Cuándo necesitamos la máxima velocidad y el mínimo tamaño

Raramente es necesario lograr tan alto nivel de optimización pero, de hacer falta, siempre se logran mejores resultados mientras menos capas de abstracción y recursos externos utilicemos.

Patrón de Carga Diferida: Inicialización diferida

Esta entrada es la parte 1 de 4 en la serie Patrón de Carga Diferida

El patrón de carga diferida es una técnica para mejorar la performance utilizada en casos en que nos encontramos con que no todas las características de un programa son usadas durante su ejecución o para distribuir los tiempos de carga, cuando estos son muy grandes, durante la ejecución para poder mejorar los tiempos de respuesta al iniciar.

Hay cuatro formas comunes de implementar la carga diferida: inicialización diferida, proxy virtual, fantasma y value holder.

Inicialización diferida

Esta técnica implica la inicialización del contenedor del recurso como nulo, o equivalente en el lenguaje, y recién realizar la carga en el momento de su primer uso.

Por ejemplo, establecer el identificador de la conexión al servidor de bases de datos como null y al momento de realizar una consulta, verificar si la conexión está inicializada o hace falta establecerla.

Algunas consideraciones que es necesario tener en cuenta al utilizar este patrón son:

  • Es necesario que cada vez que vayamos a usar el recurso del que estamos difiriendo su inicialización verifiquemos que haya sido cargado. Si bien a nivel performance no debería influir, si puede ser fuente de otros errores por olvido o por tener código duplicado.
  • Como en cualquier otro método de carga diferida, nos podemos encontrar conque el recurso no existe o no está accesible. Además, si toma mucho tiempo cargarlo, la ejecución del programa se puede ver interrumpida.
<?php

class BBDD {
  private $user;
  private $pass;
  private $host;
  private $name;

  private $connection;

  function __construct( $user, $pass, $host, $name ) {
    $this->user = $user;
    $this->pass = $pass;
    $this->host = $host;
    $this->name = $name;

    $this->connection = null;
  }

  function conectar() { /***/ }

  function query( $sql ) {
    if ($this->connection == null)
      $this->conectar();

    /***/
  }
}

 

Propiedades no enumerables en JavaScript

Hasta la especificación ES5 de JavaScript las propiedades de un objeto consistían únicamente de un nombre y un valor. A partir de 2009, fecha de publicación, se agregó la posibilidad de establecer 3 atributos de las propiedades que permiten controlar sus características:

  • configurable
  • writable
  • enumerable

Configurable

Permite establecer si, luego de su creación, se podrán editar los atributos, eliminar la propiedad o modificar las funciones de acceso. Hay que tener en cuenta que una vez establecido a false, no puede volver ser modificado.

Writable

Indica si se puede modificar el valor de la propiedad mediante el uso de operadores de asignación.

Enumerable

Configura si la propiedad va a aparecer en el listado de propiedades del objeto. Por ejemplo, mediante el uso de Object.keys(). Si bien, en principio, no parece tener mucha utilidad es importante considerar qué otras funciones utilizan la enumeración de propiedades para ver su potencial.

Ya mencioné con anterioridad que el operador de propagación y Object.assign() únicamente copian aquellas propiedades enumerables. Además, permite ocultar propiedades de los bucles for … in, ya que al no ser enumeradas no son recorridas por el mismo.

Pero, una de las consecuencias más útiles de establecer una propiedad como no enumerable es que serán ocultadas a JSON.stringify(). Esto nos permite tener, de forma sencilla, total control sobre la información que exponemos del objeto.

var obj = {
    'prop1': 'value1'
};
Object.defineProperty(obj, 'prop2', { value: 'value2', enumerable: false });

JSON.stringify(obj); // { prop1: value1 }

Limitaciones y diferencias de Object.assign() y el operador de propagación en JavaScript

Con el (nuevo) auge de la programación funcional y de librerías como Redux ha resurgido el concepto de inmutabilidad. La existencia de estructuras de datos que no pueden cambiar su valor luego de haber sido iniciadas. Cualquier manipulación de la información requiere que creemos un nuevo objeto que copie los datos del original e introduzca los cambios deseados.

Más allá de las ventajas y desventajas de la inmutabilidad, en la práctica, cuando lo implementamos en nuestras aplicaciones nos encontramos en la necesidad de copiar con cierta asiduidad estructuras de datos. En ES6, como siempre en JavaScript, la forma elegida para la representación de estos datos son los objetos. Y aquí llegamos al tema del post, existen varias formas de copiar objetos.

Dejando de lado la forma más obvia y chabacana de copiar «manualmente» propiedad por propiedad, existen dos métodos para obtener una copia modificada de un objeto:

Object.assign()

obj = Object.assign( target, source1, ..., sourceN )

Como su nombre lo indica, esta función no está pensada originalmente para clonar objetos sino para asignar nueva información a un objeto existente pero pasando como target un objeto «vacio» podemos lograr el mismo efecto.

Operador de propagación

obj = { ...source1, ..., ...sourceN }

Ídem que con el caso anterior, la idea original de el operador de propagación no era copiar objetos sino simplificar la expansión de expresiones en situaciones donde se esperaba una cantidad múltiple y, generalmente, desconocida de parámetros. En este caso, la creación de un nuevo objeto que reciba como contenido el objeto original expandido es el truco para lograr  la copia deseada.

Diferencias

La diferencia entre estos métodos es que el primero setea nuevos valores en las propiedades de un objeto mientras que, el segundo, crea nuevas propiedades y les asigna información.

Es decir, si tenemos setter definidos en nuestro objeto, Object.Assign() los va a llamar y el operador de propagación, no. Esto también tiene como consecuencia que si nuestro objeto tiene propiedades de solo lectura el operador de propagación no las va a respetar, únicamente el Object.Assign().

Limitaciones

Las principales limitaciones que nos encontramos con ambos métodos es que la copia realizada es superficial y que únicamente se consideran las propiedades propias y enumerables del objeto.

Es decir, el nuevo objeto no ninguna propiedad definida en prototype, heredada o que se haya indicado explícitamente como no enumerable. Además, si tenemos algún objeto anidado este no se copiará sino que lo hará su referencia.

 

En conclusión ambas opciones son muy similares y su rendimiento es casi idéntico, aunque un poco mejor el del operador de propagación, por lo que el decantarse por uno u otro depende más de cuestiones subjetivas.

Particularmente, encuentro el funcionamiento del operador de propagación más acorde a lo que significa trabajar con objetos inmutables ya que si o si crea un nuevo objeto. Además, al momento de tratar con objetos anidados, resulta mucho más legible:

cons obj = {
    prop1: value1,
    obj1: {
        prop2: value2,
        prop3: value3
    }
}

const copia = {
    ...obj
    obj1: {
        ...obj.obj1
    }
};

Evitar los post duplicados al utilizar múltiples loops en WordPress

Durante el desarrollo de un theme de WordPress es habitual que lleguemos a una instancia en la que el loop por defecto se queda corto y necesitamos implementar nuevas querys para poder mostrar la información de la forma deseada.

Al ser independientes las distintas querys entre sí puede ocurrir que traigan más de una vez el mismo post a colación provocando que se vean repetidos en nuestro sitio. Para poder tener mayor control sobre qué post se incluyen en los resultados del query WP_Query pone a nuestra disposición la opción post__not_in que nos permite especificar los ID de los post que queremos dejar fuera del loop.

Ahora el problema que nos surge es cómo llevar el control de los posts mostrados en las distintas partes del template. Para este fin existen distintos enfoques, por ejemplo, tener una variable global en donde vayamos almacenando los distintos posts que se ya se hayan mostrado.

En mi caso, utilizo una sencilla clase que incluyo en el functions.php y que utiliza una variable y un par de funciones estáticas para llevar el control de los post ya mostrados:

Como se puede observar alcanza con llamar a WP_Deduplicator::add() después de haber cargado los datos del post o pasandole directamente el ID a excluir y luego, al hacer nuestro próximo query pasar a la opción post__not_in el retorno de WP_Deduplicator::get().

Rendimiento de WSL

Una de las grandes features que trajo la Anniversary Update de Windows 10 es el Windows Subsystem for Linux (WSL), una compatibility layer que permite correr de forma nativa los ejecutables ELF de Linux. Si bien no está pensado para correr un X Window (aunque hay por ahí circulando guías para poder lograrlo) puede perfectamente ejecutar todas esas herramientas y servicios hoy completamente intrínsecos al desarrollo web como son los package managers, linters, test suites, étc.

Como es de esperarse cuando «virtualizamos» un SO tenemos una caída del rendimiento pero, en principio, los tiempos del WSL dejan mucho que desear. Tareas simples como actualizar un paquete con npm o procesar algunos archivos SASS puede demorar varias veces más de lo habitual, incluso varios minutos.

Con un rápido monitoreo se ve que cuando realizamos tareas en WSL se dispara el uso del procesador y del disco. Uno de los procesos que más sube su uso de los recursos del sistema es el asociado al Antimalware / Defender.  Indagando un poco en Google podemos ver que, como sucede desde la época de Vista, Windows sigue sin llevarse bien con los directorios con muchos archivos pequeños.

La filosofía de Linux de tener cientos de módulos con responsabilidades mínimas sumado al escaneo por parte de Windows de cada uno de estos archivos cuando es accedido o modificado hace que los tiempos se multipliquen.

Por lo visto, de momento la única solución posible es desactivar la protección en tiempo real de Windows Defender. La exclusión de la carpeta de datos y del ejecutable de WSL parece no alcanzar por si sola para mejorar la performance aunque probablemente tenga que ver más con que, al ejecutarse de forma nativa los programas de Linux, se nos estén pasando agregar algunos.

Una vez detenido la protección en tiempo real la performance general mejora drásticamente aunque sin llegar a ser la misma que observamos en Linux. Desde el equipo detrás de WSL prometen estar haciendo lo posible para mejorar estos tiempos pero como el problema es intrínseco al sistema de archivos no es probable que se vayan a ver soluciones definitivas en el corto plazo.

Solucionar errores de renovación de certificados Let’s Encrypt en Virtualmin

Para los que administramos nuestros servidores con Virtualmin y probamos desde que apareció la gestión de certificados SSL con Let’s Encrypt, la renovación de los mismos probablemente nos esté dando varios quebraderos de cabeza. Dos de los errores más comunes son:

  • Permission Denied al ejecutar mkdir
  • Invalid response from http://www.example.com/.well-known/acme-challenge/…

La solución de ambos problemas es sencilla. En caso del Permission Denied, se produce porque la primera implementación de Let’s Encrypt en Virtualmin usaba el usuario root para crear la carpeta .well-known y sus contenidos mientras que ahora, como debería ser, utiliza el usuario ‘propietario’ del dominio. Para solucionarlo, desde el File Manager en el panel o a través de SSH, eliminamos la carpeta y cuando ejecutemos la renovación la vuelve a crear con los permisos correctos.

El error de Invalid response, se produce porque no puede acceder desde afuera a la dirección indicada. Se suele producir por varias razones, un .htaccess o web.config muy restrictivos, una política de redirección en Nginx o que se esté forzando la conexión https para todas las conexiones a través de la configuración del servidor. Se puede solucionar agregando una excepción para la carpeta .well-know o, desactivando temporalmente, las políticas que puedan estar evitando el acceso en la configuración de nuestro servidor web.