Esta es una entrada invitada de Josh Pollock
La visualización de entradas en cuadrícula tipo Pinterest ha sido un diseño popular para las páginas de índice de los blogs de WordPress durante un tiempo. Es popular no solo porque imita el aspecto del popular sitio de medios sociales, sino también porque hace el mejor uso del espacio en la pantalla. En el índice de un blog de WordPress, permite que la vista previa de cada entrada tenga el tamaño que necesita de forma natural, sin dejar espacio extra.
En esta guía práctica, le mostraré cómo usar la popular biblioteca Masonry JavaScript para crear disposiciones de cuadrícula en cascada para el índice de su blog, así como páginas de archivo para su tema. Voy a abordar algunos problemas que hay que tener en cuenta para la optimización para móviles y cómo resolverlos.
Nota: Este es un tutorial de nivel avanzado para aquellos que se sientan cómodos editando temas de WordPress y tengan suficientes conocimientos de HTML/CSS.
Paso 1: Añadir las bibliotecas necesarias a su tema
Actualización: WordPress 3.9 ahora incluye la última versión de Mosaico.
Primero necesitas cargar Mosaico en tu tema, usando este código:
if (! function_exists('slug_scripts_masonry') ) : if ( ! is_admin() ) : function slug_scripts_masonry() { wp_enqueue_script('masonry'); wp_enqueue_style('masonry’, get_template_directory_uri().'/css/’); } add_action( 'wp_enqueue_scripts', 'slug_scripts_masonry' ); endif; //! is_admin() endif; //! slug_scripts_masonry exists
Este código simplemente carga mosaico y lo hace disponible para los archivos de plantilla de su tema (vea nuestra guía sobre cómo añadir correctamente JavaScripts y Estilos en WordPress). También tenga en cuenta que no estamos añadiendo jQuery como una dependencia para cualquiera de los dos. Una de las ventajas de Masonry 3 es que no requiere jQuery, pero puede usarse con él. En mi experiencia, inicializar Mosaico sin jQuery es más fiable, y abre la posibilidad de omitir la carga de jQuery, lo que puede ayudar tanto con los tiempos de carga de la página como con las incidencias de compatibilidad.
Paso 2: Inicializar el Javascript
Esta siguiente función establece Masonry, define los contenedores que se utilizarán con él y también se asegura de que todo sucede en el orden correcto. Masonry necesita calcular el tamaño de cada uno de los elementos de la página para poder disponer su cuadrícula dinámicamente. Un problema que he encontrado con Masonry en muchos navegadores es que Masonry calculará mal la altura de los elementos con imágenes de carga lenta, lo que lleva a la superposición de elementos. La solución es utilizar imagesLoaded para evitar que Masonry calcule la estructura / disposición / diseño / plantilla hasta que todas las imágenes estén cargadas. Esto asegura un tamaño adecuado.
Esta es la función y acción que mostrará el script de inicialización en el pie de página:
if ( ! function_exists( 'slug_masonry_init' )) : function slug_masonry_init() { ?> <script> //set the container that Masonry will be inside of in a var var container = document.querySelector('#masonry-loop'); //create empty var msnry var msnry; // initialize Masonry after all images have loaded imagesLoaded( container, function() { msnry = new Masonry( container, { itemSelector: '.masonry-entry' }); }); </script> <?php } //add to wp_footer add_action( 'wp_footer', 'slug_masonry_init' ); endif; // ! slug_masonry_init exists
La función se explica paso a paso con comentarios integrados. Lo que hace la función de JavaScript es decirle a Masonry que busque dentro de un contenedor con el id “masonry-loop” elementos con la clase “masonry-entry” y que calcule la cuadrícula solo después de que se carguen las imágenes. Establecemos el contenedor exterior con querySelector y el interior con itemSelector.
Paso 2: Crear bucle de mosaico
En lugar de añadir el marcado HTML para mosaico directamente a una plantilla vamos a crear una parte de plantilla separada para ello. Cree un nuevo archivo llamado “content-masonry.php” y añádalo a su tema. Esto le permitirá añadir el bucle de mosaico a tantas plantillas como desee.
En tu nuevo archivo añadirás el código que se muestra a continuación. El código es similar al que verías normalmente en cualquier vista previa de contenido. Puedes modificarlo como necesites, sólo asegúrate de que el elemento más externo tiene la clase “masonry-entry” que establecimos como itemSelector en el último paso.
<article class="masonry-entry" id="post-<?php the_ID(); ?>" <?php post_class(); ?> > <?php if ( has_post_thumbnail() ) : ?> <div class="masonry-thumbnail"> <a href="<?php the_permalink(' ') ?>" title="<?php the_title(); ?>"><?php the_post_thumbnail('masonry-thumb'); ?></a> </div><!--.masonry-thumbnail--> <?php endif; ?> <div class="masonry-details"> <h5><a href="<?php the_permalink(' ') ?>" title="<?php the_title(); ?>"><span class="masonry-post-title"> <?php the_title(); ?></span></a></h5> <div class="masonry-post-excerpt"> <?php the_excerpt(); ?> </div><!--.masonry-post-excerpt--> </div><!--/.masonry-entry-details --> </article><!--/.masonry-entry-->
Este marcado tiene clases para cada una de sus partes, por lo que puedes añadir marcas que se adapten a tu tema. Me gusta añadir un bonito borde ligeramente redondeado a .masonry-entry. Otra buena opción es no poner borde a .masonry-entry, pero darle una ligera sombra. Eso se ve particularmente bien cuando la miniatura de la entrada se extiende todo el camino hasta el borde del contenedor, que se puede lograr dando .masonry-thumbnail márgenes y rellenos de 0 en todas las direcciones. Usted querrá añadir todos estos estilos en un archivo llamado masonry.css en el directorio css de su tema.
Paso 3: Añadir lazo mosaico a las plantillas
Ahora que tenemos nuestra parte de plantilla puedes usarla en cualquier plantilla de tu tema que quieras. Puedes añadirlo a index.php, pero no a category.php si no quieres que se use para los archivos de categorías. Si solo quieres que se use en la página de inicio de tu tema, cuando está establecida para mostrar entradas de blog, lo usarías en home.php. Dondequiera que usted elija todo lo que necesita hacer es envolver su bucle en un contenedor con el id “masonry-loop” y añadir la parte de la plantilla en el bucle utilizando get_template_part(). Asegúrese de iniciar el contenedor del bucle de mosaico antes de while (have_posts() ).
Por ejemplo, aquí está el bucle principal del index.php de twentythirteen:
<?php if ( have_posts() ) : ?> <?php /* The loop */ ?> <?php while ( have_posts() ) : the_post(); ?> <?php get_template_part( 'content', get_post_format() ); ?> <?php endwhile; ?> <?php twentythirteen_paging_nav(); ?> <?php else : ?> <?php get_template_part( 'content', 'none' ); ?> <?php endif; ?>
Y aquí está modificado para conseguir utilizar nuestro bucle mosaico:
<?php if ( have_posts() ) : ?> <div id="masonry-loop"> <?php /* The loop */ ?> <?php while ( have_posts() ) : the_post(); ?> <?php get_template_part( 'content', 'masonry' ?> <?php endwhile; ?> </div><!--/#masonry-loop--> <?php twentythirteen_paging_nav(); ?> <?php else : ?> <?php get_template_part( 'content', 'none' ); ?> <?php endif; ?>
Paso 4: Establecer anchuras adaptables de los elementos de mosaico
Hay varias formas de establecer la anchura de cada elemento / artículo de Masonry. Puedes establecer el ancho usando un número de píxeles cuando inicializas el mosaico. No soy un fan de hacer eso ya que uso temas adaptables y requiere algunas consultas de medios complejos para hacer las cosas bien en pantallas pequeñas. Para diseños adaptables, he encontrado que lo mejor es establecer un valor de anchura para .masonry-entry con un porcentaje, basado en el número de elementos que desea en una fila y dejar que Masonry haga el resto de los cálculos por usted.
Todo lo que esto requiere es dividir el 100 por el número de elementos que desea establecer el porcentaje en una simple entrada en style.css de su tema. Por ejemplo, si quieres cuatro elementos en cada fila puedes hacer esto en tu archivo masonry.css:
.masonry-entry{ancho:25%}
Paso 5: Optimización para móviles
Podríamos parar aquí, pero no creo que el resultado final funcione increíblemente bien en las pantallas pequeñas de los teléfonos. Una vez que esté satisfecho con el aspecto de su tema con la nueva cuadrícula de mosaico en su escritorio, compruébelo en su teléfono. Si no estás contento con cómo se ve en tu teléfono, entonces tendrás que hacer un poco de trabajo.
No creo que haya suficiente espacio en la pantalla de un teléfono para todo lo que hemos añadido a nuestra parte de contenido-plantilla de mosaico. Dos buenas soluciones disponibles para usted son acortar el extracto para los teléfonos u omitirlo por completo. Aquí hay una función extra que puedes añadir al functions.php de tu tema para hacer eso. Porque no creo que estos problemas son un problema en las tabletas, estoy usando un gran plugin Mobble en todos los ejemplos en esta sección para hacer los cambios solo en los teléfonos, no tabletas. También estoy marcando / comprobando para ver si Mobble está activo antes de usarlo y si es necesario volver a la función de detección móvil más general wp_is_mobile que se construye en WordPress.
if (! function_exists('slug_custom_excerpt_length') ) : function slug_custom_excerpt_length( $length ) { //set the shorter length once $short = 10; //set long length once $long = 55; //if we can only set short excerpt for phones, else short for all mobile devices if (function_exists( 'is_phone') { if ( is_phone() ) { return $short; } else { return $long; } } else { if ( wp_is_mobile() ) { return $short; } else { return $long; } } } add_filter( 'excerpt_length', 'slug_custom_excerpt_length', 999 ); endif; // ! slug_custom_excerpt_length exists
Como puedes ver, empezamos almacenando la longitud del extracto largo y la longitud del extracto corto en variables, ya que usaremos esos valores dos veces y queremos poder cambiarlos desde un lugar si lo necesitamos más adelante. A partir de ahí comprobamos si podemos usar is_phone() de Mobble. Si es así establecemos el extracto corto para teléfonos y el extracto largo si no lo somos. Después de eso hacemos lo mismo, pero utilizando wp_is_mobile, que afectará a todos los dispositivos móviles, si is_phone() no se puede utilizar. Esperemos que la parte else de esta función nunca se utilice, pero es bueno tener una copia de seguridad por si acaso. Una vez que se establece la lógica de la longitud del extracto, sólo queda enganchar la función al filtro excerpt_length.
Acortar el extracto es una opción, pero también podemos eliminarlo por completo con un sencillo proceso. Aquí hay una nueva versión de contenido mosaico, con toda la parte del extracto omitido en los teléfonos:
<article class="masonry-entry" id="post-<?php the_ID(); ?>" <?php post_class(); ?> > <?php if ( has_post_thumbnail() ) : ?> <div class="masonry-thumbnail"> <a href="<?php the_permalink(' ') ?>" title="<?php the_title(); ?>"><?php the_post_thumbnail('masonry-thumb'); ?></a> </div><!--.masonry-thumbnail--> <?php endif; ?> <div class="masonry-details"> <h5><a href="<?php the_permalink(' ') ?>" title="<?php the_title(); ?>"><span class="masonry-post-title"> <?php the_title(); ?></span></a></h5> <?php //put the excerpt markup in variable so we don't have to repeat it multiple times. $excerpt = '<div class="masonry-post-excerpt">'; $excerpt .= the_excerpt(); $excerpt .= '</div><!--.masonry-post-excerpt-->'; //if we can only skip for phones, else skip for all mobile devices if (function_exists( 'is_phone') { if ( ! is_phone() ) { echo $excerpt; } } else { if ( ! wp_is_mobile() ) { echo $excerpt; } } ?> </div><!--/.masonry-entry-details --> </article><!--/.masonry-entry-->
Esta vez estamos probando si no estamos en un teléfono / dispositivo móvil y si es así devolvemos la parte del extracto de nuestro bucle. Si estamos en un teléfono / dispositivo móvil no hacemos nada.
Otra cosa que podríamos hacer es aumentar el ancho de los elementos / artículos de mosaico, lo que reduce el número en una fila, en los dispositivos móviles. Para ello, vamos a añadir un estilo integrado diferente a la cabecera basado en la detección de dispositivos. Dado que esta función utiliza wp_add_inline_styles dependerá de una hoja de estilo específica. En este caso estoy usando masonry.css, que es posible que desee, para mantener sus estilos de mosaico por separado. Si no terminas usando eso puedes usar el manejador de otra hoja de estilos ya registrada.
if ( ! function_exists ( 'slug_masonry_styles' ) ) : function slug_masonry_styles() { //set the wide width $wide = '25%'; //set narrow width $narrow = '50%'; /**Determine value for $width**/ //if we can only set narrow for phones, else narrow for all mobile devices if (function_exists( 'is_phone') { if ( is_phone() ) { $width = $narrow; } else { $width = $wide; } } else { if ( wp_is_mobile() ) { $width = $narrow; } else { $width = $wide; } } /**Output CSS for .masonry-entry with proper width**/ $custom_css = ".masonry-entry{width: {$width};}"; //You must use the handle of an already enqueued stylesheet here. wp_add_inline_style( 'masonry', $custom_css ); } add_action( 'wp_enqueue_scripts', 'slug_masonry_styles' ); endif; // ! slug_masonry_styles exists
Esta función busca la hoja de estilos personalizada, y luego establece un valor para el ancho usando lo que ahora debería ser una lógica muy familiar. Después creamos la variable $custom_css pasando el valor de anchura a una parte de CSS de aspecto normal con {$width}. Después usamos wp_add_inline_style para decirle a WordPress que imprima nuestros estilos integrados en la cabecera siempre que se esté usando la hoja de estilos de mosaico y luego ganchamos toda la función a wp_enqueue_scripts y ya está.
Si elige combinar sus estilos Masonry en una hoja de estilos existente, asegúrese de usar el handle de esa hoja de estilos con wp_add_inline_style o sus estilos integrados no serán incluidos. Me gusta usar wp_add_inline_style porque generalmente envuelvo el gancho de acción para poner en cola Mosaico en una condicional para que solo se añada cuando sea necesario. Por ejemplo, si solo utilizo mosaico en el índice de mi blog y en las páginas de archivo, haría lo siguiente:
if ( is_home() || is_archive() ) { add_action( 'wp_enqueue_scripts', 'slug_scripts_masonry' ); }
Estos últimos ejemplos deberían abrir otras ideas en tu cerebro. Por ejemplo, se podría utilizar una lógica similar para omitir Mosaico por completo en un dispositivo móvil. También wp_add_inline_style() es una función menos utilizada, pero muy útil, ya que le permite establecer mediante programación diferentes estilos basados en cualquier tipo de condicional. Puede permitirle cambiar radicalmente el estilo de cualquier elemento basándose no solo en la detección del dispositivo, sino que los cambios también podrían basarse en qué plantilla se está utilizando, o incluso si el usuario está conectado o no.
Espero que veas estos diferentes cambios que estoy haciendo como una oportunidad para ser creativo. Los sistemas de mosaicos y cuadrículas en cascada similares han sido populares desde hace un tiempo, así que es hora de darle un nuevo giro a esta popular idea. Muéstranos en los comentarios qué formas geniales se te han ocurrido para el uso de mosaico en un tema de WordPress.
Josh Pollock escribe acerca de WordPress, desarrolla temas, gestiona la comunidad de Pods Framework y aboga por soluciones de código abierto para el diseño sostenible.
Syed Balkhi
Hey WPBeginner readers,
Did you know you can win exciting prizes by commenting on WPBeginner?
Every month, our top blog commenters will win HUGE rewards, including premium WordPress plugin licenses and cash prizes.
You can get more details about the contest from here.
Start sharing your thoughts below to stand a chance to win!
Gabi
Hi, i wanted to know if there is a way of using the masonry grid to show registered users. Any ideas?
Neil
Just a quick note if you’re getting the “imagesLoaded” error, try adding the Javascript code after the wp_footer call in your footer.php.
This work for me:
Add to functions.php
add_action( ‘wp_enqueue_scripts’, ‘slug_masonry’ );
function slug_masonry( ) {
wp_enqueue_script(‘masonry’); // note this is not jQuery
}
In your loop, make sure your div is:
And the image class is:
and then after wp_footer in your footer.php this:
//set the container that Masonry will be inside of in a var
var container = document.querySelector(‘#masonry-loop’);
//create empty var msnry
var msnry;
// initialize Masonry after all images have loaded
imagesLoaded( container, function() {
msnry = new Masonry( container, {
itemSelector: ‘.masonry-entry’
});
});
Marisa Di Monda
Hi Andy I just tried this and I couldn’t get it to work. Everything is still running vertically in one column.
Any solutions?
Marisa Di Monda
I’m having the same problem. Did you guys solve it?
Peter
did not work for me. i see only two images on my front page which are arranged underneath. don’t know where is the problem
Eva
For some reason my posts will just all show just in rows like normal, not in masonry form, I’m not really sure how this can happen. Any ideas?
Peter
yeah, i have the same error. any solutions for this?
jcbrmn06
For anyone still having issues with this, I noticed that this code:
//set the container that Masonry will be inside of in a var
var container = document.querySelector(‘#masonry-loop’);
//create empty var msnry
var msnry;
// initialize Masonry after all images have loaded
imagesLoaded( container, function() {
msnry = new Masonry( container, {
itemSelector: ‘.masonry-entry’
});
});
Was before the masonry JS library. Therefore you get the imagesLoaded error. Like Andy suggested below putting it in the header should fix it. Basically you just have to make sure the library has to come before this code.
Andy Giesler
Thanks again for this tutorial, it really helped start me on my way.
Even with everything in place, I saw intermittent problems where the tiles simply ran down the left of the page in a single column, and Firebug confirmed that sometimes the Masonry code didn’t execute. This happened only occasionally, and only in Firefox.
It seemed that under certain load scenarios, there were probems with code trying to execute before the required files were loaded. I don’t think this was an imagesLoaded problem, since that has different symptoms.
I fixed the problem as follows:
1. The “slug_masonry_init” function places the masonry init code inline into the footer. I removed that whole function (as well as the add_action ‘wp_footer’ code) and moved the JS into an extenal file: masonry-init.js
2. I wrapped the masonry init code in jQuery to take advantage of its document.ready ability. It’s unfortunate to pull in jQuery since this is the jQuery-free version of Masonry, but document.ready seemed necessary for the code to execute in all load scenarios.
(function( $ ) {
“use strict”;
$(function() {
});
}(jQuery));
3. I enqueued the scripts like this:
wp_enqueue_script( ‘masonry’ );
wp_enqueue_script( ‘jquery’ );
wp_enqueue_script( ‘masonryInit’, get_stylesheet_directory_uri().’/js/masonry-init.js’, array( ‘masonry’, ‘jquery’ ) );
Daniel Nikolovski
Done exactly as the tutorial says, wp 3.9.1.. imagesLoaded isn’t even being loaded. Some help would be highly appreciated
Tiago Celestino
This , where is define ‘masonry-thumb’?? this default thumbnail size with masonry WordPress?
WPBeginner Staff
Checkout our guide on how to properly add javascript and styles in WordPress.
Jenny Beaumont
I’m having trouble getting this to work…followed things accordingly, based on _s, but my columns don’t wrap – just get one long one. Have any css examples to go with? I’m obviously missing something. cheers!
marisa
Hi Jenny
I am having the same trouble. Did you solve your problem?
caratcake
I’m desperately confused. I performed every step down to the letter, and my site just goes blank. A problem with the functions file. My browser doesn’t even allude to which line causes any error, all I get is ”
Server error
The website encountered an error while retrieving (url) It may be down for maintenance or configured incorrectly.”
The same happened for the WP Admin login page. I deleted functions.php in my theme folder, and the login screen was restored, but the front page was not. If you could give me any clues to what the problem might be, I would be very grateful. Regardless, many thanks for the tutorial and in depth explanations.
Andy Giesler
In case this helps others to get the sample working:
It wasn’t working for me even after I made the fix that others have noted — changing “function slug_masonry_exists()” to “function slug_masonry_init()”. The libraries were being loaded, but Masonry wasn’t doing its thing.
Then I changed the wp_enqueue_script calls so that Masonry and imagesLoaded got loaded in the header instead of at the bottom.
Suddenly everything worked.
Jean
Hi, i can´t figure out how do change the wp_enqueue_script. I will really appreciate if you can explain that in detail. Thanks!
gabi
Hello, It doesn’t work for me I have this error message :
” Parse error: syntax error, unexpected T_ENDIF in…”…functions.php on line 17
It means an error on the script from the 3td step. What did I miss ?
werner
Will you update your post due to the fact that now with 3.9 Masonry3 is in WordPress core?
Editorial Staff
Yes we’re working on updating it.
Administrador
Steven Gardner
The initialization script keeps being called before imagesloaded has been defined so I get
Uncaught ReferenceError: imagesLoaded is not defined
How can I make sure imagesLoaded is there first before I start to initialise things?
Violacase
imagesLoaded is called before enqueueing has been established. Give it a low priority so that it is called last, like:
add_action( ‘wp_footer’, ‘slug_masonry_init’, 100000 );
This did the trick for me.
Nota: I think this article needs to be updated. Not only because of this issue.
Chplusink
Thanks! This is the only solution that worked for me.
Kate
Thanks for this post. I am trying to set up a blog page with Masonry posts, but I’m snagged at step 1. Whenever I add the functions for adding the two libraries to my functions file, my site goes totally blank. Since I am developing in a subdirectory, I tried to make the paths to the js files absolute rather than relative, but that didn’t help. Any idea what I’m missing?
Steven Gardner
Yeah me too.
I’m using version 3.8.3 so wordpress haven’t upgraded to V3 of masonry yet which I though may have been the issue.
they do plan to in the 3.9 release http://make.wordpress.org/core/2014/03/27/masonry-in-wordpress-3-9/
Angie Lee
Hi,
I’m getting this error: “ReferenceError: imagesLoaded is not defined” please help.
Violacase
See above
Amitabha Ghosh
Thanks. It’s a great post and it is working for me. I am doing a template with this code and it is working perfect. But two obstacles I am facing
1. I want to limit my posts in my index page so that it shows first 6 to 7 posts and below will be a button with “Load More” feature which when clicked shall load the other posts.
2. I am trying to integrate infinite scroll javascript of Paul Irish but I couldn’t make it work. Any help??
Thanks
Ismar Hadzic
Well I followed all of your steps and I run on fatal error ” PHP Fatal error: Call to undefined function wp_enquqe_style() ” and i still don’t understand why wp_enquqe_style() i don’t understand why can you check that out.
AndyM
Hi
I was going to comment to point out that it’s a typo and should be:
wp_enqueue_style
Andre
Great tutorial…just one thing in step 3…this:
…has a missing bracket:
Aurélien Denis
Hi there!
This post is great start but I found some mistakes…
1/ You should use the_title_attribute() for the attribute title instead of the title
2/ add_action( ‘wp_footer’, ‘slug_masonry_exists’ ); is the correct code and not add_action( ‘wp_footer’, ‘slug_masonry_init’ );
Cheers!
Zulian
Actually, you don’t need to use title attributes.
AndyM
I’m wondering if
if ( ! function_exists( ‘slug_masonry_init’ )) :
function slug_masonry_exists() { ?>
should be:
if ( ! function_exists( ‘slug_masonry_init’ )) :
function slug_masonry_init() { ?>
Ben Racicot
Can’t get this working with an infinite scroll setup in my $ajax success CB. Any advice would be great.
Tomasz Bystrek
I was looking for this effect, but I did’t know how it is called and how to search for it, until now. I’ll definitely try it in one of my future project of photo blog. Thanks!
Katrina Moody
Great post – wish it was around when I started working with Masonry on a theme a few weeks ago
A couple variations – I created a new post-thumbnail image size to pull in so that both horizontal and vertical images would have equal attention within the Masonry pages – it’s fairly easy to change out the actual image for a new one (I did that at first, creating a new “entry-thumbnail” size and allowing unlimited length so that horizontal images would display properly). Then I just edited the post-thumbnail
I also wrapped the post-thumbnail within an tag so that I could allow it to return to the post permalink (I changed that out to return the media file link so I could implement a lightbox effect – per a client’s request) so visitors could go directly to the post.
I also added a hover effect to the post-thumbnail to indicate it was clickable
Now I need to pick through what I’ve done and compare it to yours and see what I can improve with your knowledge (love the WordPress community!)
Ivan Vilches
guys all that code is on functions.php ? thanks