Esta é uma postagem de convidado de Josh Pollock
A exibição de posts em grade semelhante à do Pinterest tem sido um design popular para as páginas de índice de blogs do WordPress há algum tempo. Ele é popular não só porque imita a aparência do popular site de mídia social, mas também porque faz o melhor uso do espaço na tela. Em um índice de blog do WordPress, ele permite que a visualização de cada post tenha o tamanho que naturalmente precisa ter, sem deixar espaço extra.
Neste tutorial, mostrarei como usar a popular biblioteca JavaScript Masonry para criar layouts de grade em cascata para o índice do seu blog, bem como páginas de arquivo para o seu tema. Abordarei alguns problemas que você precisa considerar para a otimização para dispositivos móveis e como resolvê-los.
Observação: este é um tutorial de nível avançado para aqueles que se sentem à vontade para editar temas do WordPress e têm conhecimento suficiente de HTML/CSS.
Etapa 1: Adicione as bibliotecas necessárias ao seu tema
Atualização: O WordPress 3.9 agora inclui a versão mais recente do Masonry.
Primeiro, você precisa carregar o Masonry em seu 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
Esse código simplesmente carrega o Masonry e o torna disponível para os arquivos de modelo do seu tema (consulte nosso guia sobre como adicionar corretamente JavaScripts e estilos no WordPress). Observe também que não estamos adicionando o jQuery como uma dependência para nenhum dos dois. Uma das vantagens do Masonry 3 é que ele não exige o jQuery, mas pode ser usado com ele. Em minha experiência, a inicialização do Masonry sem o jQuery é mais confiável e abre a possibilidade de ignorar o carregamento do jQuery, o que pode ajudar no tempo de carregamento da página e em problemas de compatibilidade.
Etapa 2: inicializar o Javascript
Esta próxima função configura o Masonry, define os contêineres que serão usados com ele e também garante que tudo aconteça na ordem correta. O Masonry precisa calcular o tamanho de cada um dos itens na página para fazer o layout da grade dinamicamente. Um problema que encontrei com o Masonry em muitos navegadores é que ele calcula incorretamente a altura dos itens com imagens de carregamento lento, o que leva à sobreposição de itens. A solução é usar imagesLoaded para evitar que o Masonry calcule o layout até que todas as imagens sejam carregadas. Isso garante o dimensionamento adequado.
Essa é a função e a ação que produzirá o script de inicialização no rodapé da 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
A função é explicada passo a passo com comentários em linha. O que a função Javascript faz é dizer ao Masonry para procurar dentro de um contêiner com o id “masonry-loop” os itens com a classe “masonry-entry” e calcular a grade somente depois que as imagens forem carregadas. Definimos o contêiner externo com querySelector e o interno com itemSelector.
Etapa 2: criar loop de alvenaria
Em vez de adicionar a marcação HTML do Masonry diretamente a um modelo, vamos criar uma parte do modelo separada para ele. Crie um novo arquivo chamado “content-masonry.php” e adicione-o ao seu tema. Isso permitirá que você adicione o loop do Masonry a quantos modelos diferentes desejar.
Em seu novo arquivo, você adicionará o código mostrado abaixo. A marcação é semelhante à que você veria normalmente em qualquer visualização de conteúdo. Você pode modificá-lo como quiser, mas certifique-se de que o elemento mais externo tenha a classe “masonry-entry” que definimos como itemSelector na última etapa.
<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-->
Essa marcação tem classes para cada uma de suas partes, de modo que você pode adicionar marcações que combinem com seu tema. Gosto de adicionar uma borda agradável e ligeiramente arredondada a .masonry-entry. Outra boa opção é não colocar nenhuma borda no .masonry-entry, mas dar a ele uma leve sombra. Isso fica particularmente bom quando a miniatura da postagem se estende até a borda do contêiner, o que pode ser feito com as margens e os paddings de 0 em todas as direções do .masonry-thumbnail. Você deverá adicionar todos esses estilos em um arquivo chamado masonry.css no diretório css do seu tema.
Etapa 3: Adicionar o loop de alvenaria aos modelos
Agora que temos nossa parte de modelo, você pode usá-la em qualquer modelo do seu tema que desejar. Você pode adicioná-lo ao index.php, mas não ao category.php se não quiser que ele seja usado para arquivos de categoria. Se quiser que ele seja usado somente na página inicial do tema, quando estiver configurado para mostrar as postagens do blog, você o usará no home.php. Seja qual for a sua escolha, tudo o que você precisa fazer é envolver o loop em um contêiner com o ID “masonry-loop” e adicionar a parte do modelo ao loop usando get_template_part(). Certifique-se de iniciar o contêiner do loop de alvenaria antes de while (have_posts() ).
Por exemplo, aqui está o loop principal do index.php do 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; ?>
E aqui ele é modificado para usar nosso 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; ?>
Etapa 4: Definir larguras responsivas dos itens de alvenaria
Há várias maneiras de definir a largura de cada item do Masonry. Você pode definir a largura usando um número de pixels ao inicializar o Masonry. Não gosto muito de fazer isso, pois uso temas responsivos e isso exige algumas consultas de mídia complexas para que as coisas fiquem corretas em telas pequenas. Para designs responsivos, descobri que a melhor coisa a fazer é definir um valor de largura para .masonry-entry com uma porcentagem, com base em quantos itens você deseja em uma linha e deixar que o Masonry faça o resto da matemática para você.
Tudo o que isso requer é dividir 100 pelo número de itens que você deseja definir como porcentagem em uma entrada simples no style.css do seu tema. Por exemplo, se você quiser quatro itens em cada linha, poderá fazer isso em seu arquivo masonry.css:
.masonry-entry{width:25%}
Etapa 5: Otimização para dispositivos móveis
Poderíamos parar por aqui, mas não acho que o resultado final funcione muito bem em telas de telefones pequenos. Quando estiver satisfeito com a aparência do seu tema com a nova grade Masonry em seu desktop, verifique-o em seu celular. Se não estiver satisfeito com a aparência no telefone, será necessário fazer um pequeno trabalho.
Não creio que haja espaço suficiente na tela de um telefone para tudo o que adicionamos à nossa parte de modelo de conteúdo de alvenaria. Duas boas soluções disponíveis são encurtar o trecho para telefones ou ignorá-lo completamente. Aqui está uma função extra que você pode adicionar ao functions.php do seu tema para fazer isso. Como não acho que essas questões sejam um problema em tablets, estou usando um excelente plug-in Mobble em todos os exemplos desta seção para fazer as alterações apenas em telefones, não em tablets. Também estou verificando se o Mobble está ativo antes de usá-lo e, se necessário, recorrendo à função mais geral de detecção de dispositivos móveis, wp_is_mobile, que está integrada ao 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 você pode ver, começamos armazenando o comprimento do trecho longo e o comprimento do trecho curto em variáveis, uma vez que usaremos esses valores duas vezes e queremos poder alterá-los em um só lugar se precisarmos mais tarde. A partir daí, testamos se podemos usar o is_phone() do Mobble. Se for o caso, definimos o trecho curto para telefones e o trecho longo se não formos. Depois disso, fazemos a mesma coisa básica, mas usando wp_is_mobile, que afetará todos os dispositivos móveis, se is_phone() não puder ser usado. Esperamos que a parte else dessa função nunca seja usada, mas é bom ter um backup, por precaução. Depois que a lógica do comprimento do trecho estiver definida, basta conectar a função ao filtro excerpt_length.
Encurtar o trecho é uma opção, mas também podemos eliminá-lo completamente com um processo simples. Aqui está uma nova versão do content-masonry, com toda a parte do trecho omitida nos telefones:
<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-->
Desta vez, estamos testando para ver se não estamos em um telefone/dispositivo móvel e, em caso afirmativo, retornamos a parte do trecho do nosso loop. Se estivermos em um telefone/dispositivo móvel, não faremos nada.
Outra coisa que você pode querer fazer é aumentar a largura dos itens de alvenaria, o que reduz o número de itens em uma linha, em dispositivos móveis. Para fazer isso, adicionaremos um estilo em linha diferente ao cabeçalho com base na detecção do dispositivo. Como essa função usa wp_add_inline_styles, ela dependerá de uma folha de estilo específica. Nesse caso, estou usando masonry.css, o que talvez você queira, para manter os estilos de alvenaria separados. Se acabar não usando esse arquivo, poderá usar o identificador de outra folha de estilo já 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
Essa função busca a folha de estilo personalizada e, em seguida, define um valor para a largura usando o que agora deve ser uma lógica muito familiar. Depois disso, criamos a variável $custom_css passando o valor da largura para uma parte do CSS de aparência normal com {$width}. Depois disso, usamos wp_add_inline_style para dizer ao WordPress que imprima nossos estilos inline no cabeçalho sempre que a folha de estilo Masonry estiver sendo usada e, em seguida, conectamos toda a função a wp_enqueue_scripts e estamos prontos.
Se optar por combinar seus estilos Masonry em uma folha de estilo existente, certifique-se de usar o identificador dessa folha de estilo com wp_add_inline_style ou seus estilos inline não serão incluídos. Gosto de usar wp_add_inline_style porque geralmente envolvo o gancho de ação para enfileirar o Masonry em uma condicional para que ele seja adicionado somente quando necessário. Por exemplo, se eu estiver usando o Masonry somente no índice do meu blog e nas páginas de arquivo, eu faria o seguinte:
if ( is_home() || is_archive() ) { add_action( 'wp_enqueue_scripts', 'slug_scripts_masonry' ); }
Esses últimos exemplos devem abrir algumas outras ideias em seu cérebro. Por exemplo, você poderia usar uma lógica semelhante para ignorar completamente o Masonry em um dispositivo móvel. Além disso, wp_add_inline_style() é uma função menos usada, mas muito útil, pois permite que você defina programaticamente estilos diferentes com base em qualquer tipo de condicional. Ela pode permitir que você altere radicalmente o estilo de qualquer elemento com base não apenas na detecção do dispositivo, mas as alterações também podem ser baseadas no modelo que está sendo usado ou até mesmo se o usuário está conectado ou não.
Espero que você veja essas diferentes alterações que estou fazendo como uma oportunidade de ser criativo. A alvenaria e os sistemas de grade em cascata semelhantes já são populares há algum tempo, portanto, chegou a hora de dar novas reviravoltas nessa ideia popular. Mostre-nos nos comentários quais são as maneiras legais que você encontrou para usar o Masonry em um tema do WordPress.
Josh Pollock, um profissional multifuncional do WordPress, escreve sobre o WordPress, desenvolve temas, atua como gerente de comunidade do Pods Framework e defende soluções de código aberto para design sustentável.
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