Modificar contenedores de imágenes en el lado del servidor en WordPress
Siempre que esté creando soluciones personalizadas para otras personas, es posible que tenga que lidiar con casos matizados de cómo WordPress está representando el contenido.
Esto generalmente se reduce al tema, al menos un complemento o la combinación de ambos. Y si necesita trabajar con imágenes individualmente, entonces puede ser un desafío. El problema de intentar escribir una publicación como esta es que es difícil incluso describir una situación en la que podrías necesitar algo como esto.
Aún así, voy a hacer lo mejor que pueda. Es decir, quiero compartir cómo modificar contenedores de imágenes en el lado del servidor antes de representarlos en el lado del cliente y hacerlo usando la biblioteca DOMDocument de PHP.
¿Suena como mucho? Con suerte, puedo desglosar esto con bastante facilidad.
Antes de entrar en el código, supongamos que tiene un elemento que representa imágenes en un solo elemento de párrafo (o cualquier tipo de elemento a nivel de bloque) y necesita envolver cada elemento en algún tipo de clase para que pueda acceder a través de CSS o JavaScript.
Donde estamos
Entonces, para empezar, digamos que las imágenes se muestran así:
Y necesitas renderizarlos así:
Ahora, puede o no necesitar espacio entre ellos. Realmente no importa porque tienes control sobre esto a través de CSS. Pero usted tiene control sobre cómo se envía esto a través del cable al lado del cliente.
Para hacer esto, necesitas algunas cosas:
- Acceso a la biblioteca DOMDocument de PHP,
- Comprensión de cómo manipular el contenido a través del gancho the_content de WordPress,
- Una estrategia sobre cómo desea envolver las imágenes.
Revisaré cada uno de estos en el código, pero baste decir que voy a envolver cada imagen en un elemento de párrafo. Obviamente, puedes optar por hacer lo que quieras.
Cómo hacerlo
Primero, asegúrese de haber declarado que está usando el contenido del documento DOM sobre su clase :
<?php
namespace Acme;
use DOMDocument;
class AcmeContentSubscriber
{
// ...
}
A continuación, continúe y cree un gancho para the_content. La forma en que lo haga dependerá de cómo haya organizado su código (ya sea OOP o no). Para este ejemplo, voy a mostrar un ejemplo muy simple de cómo hacerlo :
<?php
public function contentSubscriber()
{
add_action( 'the_content', [$this, 'addImageAttributes']);
}
Después de eso, deberá trabajar un poco (todo lo cual se encuentra a continuación pero fuera del alcance de esta publicación). Esto incluye:
- convertir la codificación de las entidades HTML,
- creando una instancia del documento DOM,
- cargando el HTML de la publicación desde el contenido entrante
En el código, debería verse así :
<?php
public function addImageAttributes($content)
{
$content = mb_convert_encoding($content, 'HTML-ENTITIES', "UTF-8");
$document = new DOMDocument();
libxml_use_internal_errors(true);
$document->loadHTML(utf8_decode($content));
// ...
}
A continuación, debe iterar a través de los elementos img y asegurarse de que está configurando un atributo adecuado. Puede optar por utilizar una clase, puede optar por utilizar un atributo de datos o puede optar por utilizar otra cosa. Esta parte no importa.
Tenga en cuenta que para una imagen dada, querrá verificar que el siguiente elemento no sea un elemento de párrafo, ya que eso es lo que estoy optando por envolver la imagen. En otras palabras, si el siguiente elemento no es un párrafo, envolveremos el elemento en un elemento de párrafo.
Para hacer esto, el esqueleto de la función principal debería verse así :
<?php
public function addImageAttributes($content)
{
$content = mb_convert_encoding($content, 'HTML-ENTITIES', "UTF-8");
$document = new DOMDocument();
libxml_use_internal_errors(true);
$document->loadHTML(utf8_decode($content));
$images = $document->getElementsByTagName('img');
foreach ($images as $image) {
$image->setAttribute('class', 'acme-iamge');
if ($image->nextSibling->tagName !== 'p') {
$this->wrapImage($document, $image);
}
}
// ...
}
Entonces, la función responsable de envolver el elemento en un elemento de párrafo debería verse así :
<?php
/**
* This function is used to wrap individual images in a paragraph element.
*
* @param $document The DOM Document which is to be rendered.
* @param $image The image to wrap with the new paragraph element.
*/
private function wrapImage($document, $image)
{
if (null === $image) {
return;
}
$wrapper = $document->createElement('p');
$wrapper->setAttribute('class', 'acme-image');
$image->parentNode->replaceChild($wrapper, $image);
if (null !== $image) {
$wrapper->appendChild($image);
}
}
Asegúrese de leer el DocBlock del código para comprender cómo funciona la función. Simplemente pon:
- acepta una instancia del documento y el elemento de imagen,
- crea un elemento de párrafo,
- agrega un atributo de clase
- reemplaza el elemento de imagen original con el párrafo,
- y agrega la imagen como un elemento secundario
Y dado que hemos basado el objeto del documento en el método, no tenemos que devolver nada.
La versión final de la función original debería verse así :
<?php
public function addImageAttributes($content)
{
$content = mb_convert_encoding($content, 'HTML-ENTITIES', "UTF-8");
$document = new DOMDocument();
libxml_use_internal_errors(true);
$document->loadHTML(utf8_decode($content));
$images = $document->getElementsByTagName('img');
foreach ($images as $image) {
$image->setAttribute('class', 'acme-image');
if ($image->nextSibling->tagName !== 'p') {
$this->wrapImage($document, $image);
}
}
return $document->saveHTML();
}
Y su salida debería verse como la imagen de arriba. Recuerde, sin embargo; debe devolver los resultados de la instancia del documento a WordPress, para que represente correctamente el HTML. Y eso es lo que hace la función saveHTML en el código anterior.
