Questo è un articolo di Josh Pollock, ospite di questa rubrica
La visualizzazione a griglia degli articoli, simile a quella di Pinterest, è da tempo un design popolare per le pagine indice dei blog WordPress. È popolare non solo perché imita l’aspetto del popolare sito di social media, ma anche perché utilizza al meglio lo spazio sullo schermo. Sull’indice di un blog WordPress, permette a ogni anteprima degli articoli di avere le dimensioni naturali, senza lasciare spazio extra.
In questo tutorial vi mostrerò come utilizzare la popolare libreria JavaScript Masonry per creare layout a griglia a cascata per l’indice del vostro blog e per le pagine di archivio del vostro tema. Mi indirizzo verso alcuni problemi che è necessario considerare per l’ottimizzazione dei dispositivi mobili e come risolverli.
Nota: questo è un tutorial di livello avanzato per coloro che si sentono a proprio agio nella modifica di temi WordPress e hanno sufficienti conoscenze di HTML/CSS.
Passo 1: Aggiungere le librerie necessarie al tema
Aggiornamento: WordPress 3.9 include ora l’ultima versione di Masonry.
Per prima cosa è necessario caricare Masonry nel tema, utilizzando questo codice:
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
Questo codice carica semplicemente masonry e lo rende disponibile ai template del tema (si veda la nostra guida su come add-onare correttamente JavaScript e stili in WordPress). Si noti anche che non stiamo aggiungendo jQuery come dipendenza per nessuno dei due. Uno dei vantaggi di Masonry 3 è che non richiede jQuery, ma può essere utilizzato con esso. Secondo la mia esperienza, l’inizializzazione di Masonry senza jQuery è più affidabile e offre la possibilità di saltare il caricamento di jQuery, il che può aiutare sia i tempi di caricamento delle pagine che i problemi di compatibilità.
Passo 2: inizializzare il Javascript
La funzione successiva imposta Masonry, definisce i contenitori che saranno usati con esso e si assicura che tutto avvenga nella giusta ordinazione. Masonry deve calcolare le dimensioni di ogni elemento della pagina, in modo da disporre la griglia in modo dinamico. Un problema che ho riscontrato con Masonry in molti browser è che Masonry calcola male l’altezza degli elementi con immagini che si caricano lentamente, causando la sovrapposizione degli elementi. La soluzione è usare imagesLoaded per impedire a Masonry di calcolare il layout finché non sono state caricate tutte le immagini. Questo assicura un dimensionamento corretto.
Questa è la funzione e l’azione che emette lo script di inizializzazione nel footer della pagina:
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 funzione è spiegata passo per passo con commenti in linea. La funzione Javascript dice a Masonry di cercare all’interno di un contenitore con l’ID “masonry-loop” gli elementi con la classe “masonry-entry” e di calcolare la griglia solo dopo il caricamento delle immagini. Si imposta il contenitore esterno con querySelector e quello interno con itemSelector.
Passo 2: creazione del loop masonry
Invece di aggiungere il markup HTML per Masonry direttamente a un template, creeremo una parte di template separata per esso. Creare un nuovo file chiamato “content-masonry.php” e aggiungerlo al tema. Ciò consentirà di aggiungere il loop di Masonry a tutti i template che si desidera.
Nel nuovo file si aggiungerà il codice mostrato di seguito. Il markup è simile a quello che si vede normalmente per qualsiasi anteprima di contenuto. Si può modificare in qualsiasi modo, basta assicurarsi che l’elemento più esterno abbia la classe “masonry-entry”, impostata come itemSelector nell’ultimo passo.
<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-->
Questo markup ha classi per ogni sua parte, in modo da poter aggiungere markup in corrispondenza del tema. Mi piace aggiungere un bel bordo leggermente arrotondato a .masonry-entry. Un’altra bella opzione è quella di non aggiungere alcun bordo a .masonry-entry, ma di dargli una leggera ombra. L’effetto è particolarmente bello quando l’immagine in evidenza dell’articolo si estende fino al bordo del contenitore, cosa che si può ottenere dando a .masonry-thumbnail margini e spaziature interne pari a 0 in tutte le direzioni. Tutti questi stili vanno aggiunti in un file chiamato masonry.css nella directory css del tema.
Passo 3: Aggiungere il loop masonry ai template
Ora che abbiamo la nostra parte di template, possiamo utilizzarla in qualsiasi template del tema che desideriamo. Si può aggiungere a index.php, ma non a category.php, se non si vuole che venga usato per gli archivi delle categorie. Se si vuole che venga utilizzato solo nella homepage del tema, quando è impostato per mostrare gli articoli del blog, lo si può usare in home.php. Ovunque si scelga, tutto ciò che si deve fare è wrap il proprio template in un contenitore con l’ID “masonry-loop” e aggiungere la parte del template nel loop usando get_template_part(). Assicurarsi di avviare il contenitore del loop masonry prima di while (have_posts() ).
Per esempio, ecco il loop principale di twentythirteen index.php:
<?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; ?>
Ed eccolo modificato per utilizzare il nostro loop Masonry:
<?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; ?>
Passo 4: Impostazione delle larghezze responsive degli elementi masonry
Esistono diversi modi per impostare la larghezza di ciascun elemento di Masonry. Si può impostare la larghezza usando un numero di sgranati quando si inizializza Masonry. Non sono un fan di questa operazione, poiché uso temi responsive e ciò richiede alcune complesse media query per ottenere il giusto risultato su schermi di dimensioni ridotte. Per i design responsive, ho scoperto che la cosa migliore da fare è impostare un valore di larghezza per .masonry-entry con una percentuale, in base al numero di elementi che si desidera in una riga e lasciare che Masonry faccia il resto dei calcoli per voi.
È sufficiente dividere 100 per il numero di elementi desiderati per impostare la percentuale in una semplice voce dello style.css del tema. Per esempio, se si vogliono quattro elementi in ogni riga, si può fare questo nel file masonry.css:
.masonry-entry{larghezza:25%}
Passo 5: Ottimizzazione per i dispositivi mobili
Potremmo fermarci qui, ma non credo che il risultato finale funzioni incredibilmente bene sugli schermi dei telefoni di piccole dimensioni. Una volta che siete soddisfatti dell’aspetto del tema con la nuova griglia Masonry sul desktop, verificatelo sul vostro telefono. Se non siete soddisfatti di come appare sul telefono, dovrete fare un po’ di lavoro.
Non credo che ci sia abbastanza spazio sullo schermo di un telefono per tutto ciò che abbiamo add-on alla parte del template content-masonry. Due buone soluzioni a disposizione sono accorciare il riassunto per i telefoni o saltarlo del tutto. Ecco una funzione aggiuntiva che si può aggiungere al functions.php del tema per farlo. Poiché non credo che questi problemi siano un problema sui tablet, sto usando l’ottimo plugin Mobble in tutti gli esempi di questa sezione per apportare le modifiche solo sui telefoni, non sui tablet. Sto anche selezionando se Mobble è attivo prima di utilizzarlo e, se necessario, mi affido alla funzione più generale di rilevamento dei dispositivi mobili wp_is_mobile, integrata in 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
Come si può vedere, iniziamo memorizzando la lunghezza del riassunto lungo e la lunghezza del riassunto corto in variabili, dato che utilizzeremo questi valori due volte e vogliamo essere in grado di cambiarli da un unico punto se ne avremo bisogno in seguito. Da qui verifichiamo se possiamo usare is_phone() di Mobble. In caso affermativo, impostiamo il riassunto breve per i telefoni e il riassunto lungo se non lo siamo. Dopodiché facciamo la stessa cosa di base, ma usando wp_is_mobile, che avrà effetto su tutti i dispositivi mobili, se is_phone() non può essere usato. Si spera che la parte else di questa funzione non venga mai utilizzata, ma è bene avere un backup per ogni evenienza. Una volta impostata la logica della lunghezza del riassunto, è sufficiente agganciare la funzione al filtro excerpt_length.
Accorciare il riassunto è un’opzione, ma possiamo anche eliminarlo del tutto con un semplice procedimento. Ecco una nuova versione di content masonry, con l’intera parte del riassunto omessa sui telefoni:
<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-->
Questa volta abbiamo fatto un test per vedere se non siamo su un telefono/dispositivo mobile e, in tal caso, abbiamo restituito la parte riassuntiva del nostro loop. Se siamo su un telefono/dispositivo mobile, non facciamo nulla.
Un’altra cosa che si potrebbe fare è aumentare la larghezza degli elementi masonry, riducendo così il numero dei disponi in riga, sui dispositivi mobili. Per farlo, aggiungeremo un diverso stile inline all’header in base al rilevamento del dispositivo. Poiché questa funzione utilizza wp_add_inline_styles, dipenderà da un foglio di stile specifico. In questo caso sto usando masonry.css, che potrebbe essere utile per mantenere separati gli stili di masonry. Se non lo si utilizza, si può usare la gestione di un altro foglio di stile già registrato.
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
Questa funzione richiama il foglio di stile personalizzato e poi imposta un valore per la larghezza, utilizzando una logica che dovrebbe essere ormai molto familiare. Quindi si crea la variabile $custom_css, passando il valore della larghezza in un CSS altrimenti normale con {$width}. Dopodiché usiamo wp_add_inline_style per dire a WordPress di stampare i nostri stili in linea nell’header ogni volta che viene usato il foglio di stile masonry e poi agganciamo l’intera funzione a wp_enqueue_scripts e abbiamo finito.
Se si sceglie di combinare gli stili di Masonry in un foglio di stile esistente, assicurarsi di usare il gestore di quel foglio di stile con wp_add_inline_style, altrimenti gli stili in linea non saranno inclusi. Mi piace usare wp_add_inline_style perché generalmente wrap l’action hook per l’inserimento di Masonry in un condizionale, in modo che venga aggiunto solo quando necessario. Per esempio, se uso masonry solo sulle pagine dell’indice e dell’archivio del blog, faccio così:
if ( is_home() || is_archive() ) { add_action( 'wp_enqueue_scripts', 'slug_scripts_masonry' ); }
Questi ultimi esempi dovrebbero farvi venire in mente altre idee. Per esempio, si potrebbe usare una logica simile per saltare del tutto il masonry su un dispositivo mobile. Anche wp_add_inline_style() è una funzione poco utilizzata, ma molto utile, perché consente di impostare programmaticamente stili diversi in base a qualsiasi tipo di condizione. Può consentire di cambiare radicalmente lo stile di qualsiasi elemento non solo in base al rilevamento del dispositivo, ma anche in base al template utilizzato o anche se l’utente è connesso o meno.
Spero che le diverse modifiche che sto apportando siano un’opportunità per essere creativi. I sistemi masonry e simili a griglia a cascata sono popolari da un po’ di tempo a questa parte, quindi è arrivato il momento di dare una svolta a questa idea popolare. Mostrateci nei commenti quali modi interessanti avete escogitato per utilizzare il masonry in un tema di WordPress.
Josh Pollock è un esperto di WordPress, scrive su chi siamo, si occupa dello sviluppo di temi, è il manager della Community per il Pods Framework e sostiene le soluzioni open source per il design sostenibile.
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.
Admin
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