El día de año nuevo
cambié el tema del blog (una versión modificada de Redoable) por Arthemia 2 y
descubrí que incluía el script timthumb.php para generar las miniaturas de las
entradas en la portada, archivos y búsqueda, ¡qué bien!. Pero nada más
activarlo y entrar en el blog propiamente dicho, las imágenes no se muestran…
Voy a la documentación del tema y veo que hay que copiar la ruta de la imagen
que quiero como miniatura en un campo personalizado de la entrada, con nombre
‘Image’ y la URL relativa (esto es, wp-content/uploads/año/mes/imagen.jpg).
Vaya rollazo, ¿no hay nada automático?.
No me cuentes historias,
show me the code!
Obtener los archivos
adjuntos a una entrada
Buscando por el Codex
de WordPress encontré algo que podía ser útil: la función get_children(). Por
lo visto WordPress relaciona internamente cada fichero con su entrada
correspondiente, y esta función devuelve todos los adjuntos que hemos subido
mediante el uploader al escribir la entrada. Además permite filtrar el
resultado por tipo (attachment), el identificador de la entrada (post_id) y el
tipo MIME del archivo (image).
$attachments =& get_children(
array(
'post_type' => 'attachment',
'post_parent' => get_the_ID(),
'post_mime_type' => 'image'
));
Tras varias pruebas
-no todo sale siempre a la primera- compruebo que las todas miniaturas
funcionan sin tener que usar los campos personalizados (que sinceramente, nunca
me iba a molestar en rellenar) y me voy a la cama tan tranquilo.
El desastre
Al día siguiente…
¡horror!, el blog carga lentísimo y pocos minutos después recibo un mensaje del
Hostmaster porque hay un proceso que está llamando continuamente a una IP caída
(que resultó ser la de Twitter). Desactivo el plugin culpable -Twittwoo- e
instalo WP-Super-Cache a petición del Hostmaster. Segundo horror: las
miniaturas a tomar por saco. Borro la caché que había generado, desactivo y
elimino todos los ficheros. Siguen sin aparecer las miniaturas y el Hostmaster
me indica que desde el día de año nuevo a las 21:15h aparece este otro mensaje
de error en los logs del servidor:
[Thu Jan 01 21:15:04
2009] [error] [client 84.77.X.X] Usage: file [-bcikLhnNsvz] [-f namefile] [-F
separator] [-m magicfiles] file..., referer: http://www.frickr.es/
[Thu Jan 01 21:15:04
2009] [error] [client 84.77.X.X]
file -C -m magicfiles, referer: http://www.frickr.es/
Pues parece que
timthumb.php hace una llamada a una función que calcula no-se-qué de un número
mágico y falla o el servidor no la soporta. Y encima el WP-Super-Cache me ha
modificado el .htaccess, pero por suerte el Hostmaster me sube uno limpio para
WordPress. Resumiendo: que el dichoso timthumb.php en realidad nunca ha
funcionado bien, y hay que encontrar otra solución.
Me pongo a buscar
otra vez en el Codex y esta vez descubro que desde la versión 2.5 WordPress
permite especificar tamaños para generar miniaturas de todas las imágenes que
se suben. Perfecto: si nativamente el sistema genera las miniaturas, y yo puedo
acceder a todos los adjuntos de un post, me falta relacionar el adjunto con la
miniatura del tamaño que necesito. Sigo inspeccionando las funciones internas y
me encuentro con wp_get_attachment_image_src(), justo lo que necesito:
(array) $image =
function wp_get_attachment_image_src (
$attachment_id,
$size='thumbnail',
$icon = false
);
// Returns an array
containing:
$image[0] => url
$image[1] => width
$image[2] =>
height
Bueno, pues vamos a
configurar WordPress y a modificar el código del tema (theme) para hacer que
soporte las miniaturas internas de WordPress y eliminar cualquier rastro del
timthumb.php.
Nota: el código a
continuación ha sido probado bajo WordPress 2.7. Debería funcionar también en
WordPress 2.5 o superior, aunque no me hago responsable de los resultados.
Paso 1: Configurar el
tamaño de las miniaturas
Antes que nada,
tendremos que pensar cuáles serán los tamaños que necesitaremos para nuestras
miniaturas. WordPress genera 3 tamaños distintos de miniaturas, además de
conservar el tamaño original. Para el que no sepa dónde se cambian, está en
Opciones » Objetos (vaya nombre tan poco intuitivo). Yo puse los mismos valores
que venían especificados en mi theme Arthemia 2.
wordpress_miniaturas
Paso 2: Insertando el
código final en el theme
Lo bueno que tiene
dejar de utilizar timthumb.php es que ya no se llamará más a este script cada
vez que queramos cargar una miniatura. Vale que tiene un sistema de cachés y es
bastante efectivo, pero el approach de los chicos de WordPress es mucho más
eficiente: subes una imagen y se almacenan las miniaturas en 3 tamaños
diferentes, para siempre. Esto hace las cosas mucho más sencillas y no hay que
procesar un PHP entre medias, libera recursos de CPU, RAM y se reduce el tiempo
de carga. Todos ganan (menos Tim :-D). El código final es este (los comentarios
están en inglés por si alguien llega hasta aquí y no entiende español):
<?php
$image = null; // Clear the value from the
previous post
// Get all attachments from the post ID
with type image
$attachments =&
get_children(array('post_parent'=>get_the_ID(),'post_type'=>'attachment','post_mime_type'=>'image'));
// If attachments are found...
if ($attachments == TRUE) {
// ... go through all of them
foreach($attachments as $att) {
// Get the image source for every
image attachment found
// Post_ID, Size ('thumbnail',
'medium', 'large', 'full' or an Array), Icon (true/false)
$image =
wp_get_attachment_image_src($att->ID,'thumbnail',false);
break; // Comment this line to get
all images inside the post
}
}
echo '<!--
Attachment_ID='.$att_id.'-->'; // Comment this line if everything works OK
(used for debugging)
if (isset($image)) {
?>
<a href="<?php the_permalink()
?>" rel="bookmark" title="Enlace permanente a <?php
the_title(); ?>">
<img src="<?php echo $image[0]
?>" alt="<?php the_title(); ?>" class="left"
width="<?php echo $image[1]; ?>" height="<?php echo
$image[2]; ?>" /></a>
<?php } ?>
Paso 3: Vamos por
partes (para amateurs)
1
2
3
4
<?php
$image = null; // Clear the value from the
previous post
// Get all attachments from the post ID
with type image
$attachments =&
get_children(array('post_parent'=>get_the_ID(),'post_type'=>'attachment','post_mime_type'=>'image'));
Lo primero que
hacemos es abrir una etiqueta php allí donde queramos mostrar la miniatura,
siempre dentro de El Bucle (The Loop). Con $image = null; vaciamos esta
variable por si contiene valores de la iteración (post) anterior. Si no lo
hacemos, la minuatura podría repetirse en una entrada que vaya después y a la
que no le hayamos adjuntado ninguna imagen. Por último, utilizamos la función
get_children() que hemos visto antes pasándole como parámetros el número del
post actual, y los filtro para que sólo nos devuelva los adjuntos y dentro de
éstos, las imágenes. El resultado de esta operación se almacena en la variable
$attachments.
6
7
8
9
10
11
12
13
14
15
// If attachments are found...
if ($attachments == TRUE) {
// ... go through all of them
foreach($attachments as $att) {
// Get the image source for every
image attachment found
// Post_ID, Size ('thumbnail',
'medium', 'large', 'full' or an Array), Icon (true/false)
$image =
wp_get_attachment_image_src($att->ID,'thumbnail',false);
break; // Comment this line to get
all images inside the post
}
}
Comprobamos si al
hacer la petición a get_children() hemos recibido algún resultado, y en caso
afirmativo, recorremos cada uno de los adjuntos con la sentencia foreach, y
pedimos con wp_get_attachment_image_src() que nos almacene en $image los datos
que necesitamos (URL, ancho y alto) para la miniatura de tamaño thumbnail (por
ejemplo). Para ello, le hemos especificado tambien el identificador de adjunto
que usa internamente WordPress con $att->ID y que no queremos incluir un
icono en la imagen con el tercer parámetro false. Como en mi caso yo sólo
quiero la primera imagen que tenga incluída en mis entradas -podría tener
varias-, he colocado un break; (salto) para que se detenga al obtener la
miniatura de la primera imagen.
17
18
19
20
echo '<!--
Attachment_ID='.$att_id.'-->'; // Comment this line if everything works OK
(used for debugging)
if (isset($image)) {
?>
La línea 17
simplemente imprime un comentario con el identificador interno de la imagen que
ha obtenido de nuestro post. Para poder ver el resultado tendremos que mostrar
el código fuente en el navegador. Si todo funciona correctamente, podemos
comentar esta línea insertando dos barras // delante del echo. En la línea 19
indicamos que sólo queremos que se ejecute el código que viene a continuación
si se ha obtenido una miniatura. Quedaría bastante mal insertar una imagen con una
URL rota que no lleva a ninguna parte.
21
22
23
<a
href="<?php the_permalink(); ?>" rel="bookmark"
title="Enlace permanente a <?php the_title(); ?>">
<img src="<?php echo $image[0]
?>" alt="<?php the_title(); ?>" class="left"
width="<?php echo $image[1]; ?>" height="<?php echo
$image[2]; ?>" /></a>
<?php } ?>
Y por último creamos
el código HTML de el enlace al post, con la imagen en su interior. Usamos la
función the_permalink() para obtener la URL de la entrada y the_title() para el
título. Para finalizar imprimimos la URL de la minuatura con echo $image[0];,
el ancho con $image[1] y la altura con $image[2], tal como vimos antes en la
documentación del Codex. Y que no se nos olvide cerrar la condición al final
con su llave } correspondiente.
Paso 4: Regenerar las
miniaturas con los nuevos tamaños
Si habéis cambiado
los tamaños de las miniaturas en el paso 1, hay que tener en cuenta que todas
las imágenes subidas hasta la fecha fueron escaladas al tamaño que estaba
especificado entonces. La solución manual sería eliminar todas las imágenes una
por una y volverlas a subir para que WordPress coja los nuevos tamaños. Suerte
que está el plugin Regenerate Thumbnails para solucionarnos la papeleta
automáticamente por nosotros. Una vez instalado y activado, sólo hay que ir a
Herramientas » Regen. Thumbnails y pulsar sobre el botón Regenerate all
Thumbnails para establecer todas las miniaturas a los nuevos tamaños. ¿A que no
ha sido para tanto? ;-)