Detta är ett gästinlägg av Josh Pollock
Den Pinterest-liknande grid-displayen av inlägg har varit en populär design för WordPress bloggindex pages ett tag. Det är populärt, eller ej, för att det efterliknar utseendet på den populära social media-webbplatsen, men också för att det gör bästa möjliga användning av utrymmet på vyn. På ett WordPress blogginlägg, allow each post preview to be the size it naturally needs to be, utan att lämna extra utrymme.
I denna tutorial kommer jag att visa dig hur du använder det populära JavaScript-biblioteket Masonry för att skapa cascading grid layouts för ditt blogg-index, samt archive pages för ditt theme. Jag kommer att ta upp några issues som du behöver tänka på för mobiloptimering och hur du löser dem.
Note: Detta är en tutorial på avancerad nivå för dig som känner dig bekväm med att editera WordPress themes och har tillräckliga kunskaper i HTML/CSS.
Step 1: Add Necessary Libraries To Your Theme (Lägg till nödvändiga bibliotek i ditt theme)
Update: WordPress 3.9 innehåller nu den senaste versionen av Masonry.
Först måste du hämta in Masonry i ditt theme med hjälp av denna kod:
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
Denna kod hämtar helt enkelt masonry och gör den tillgänglig för ditt temas template-filer (se vår guide om hur man korrekt lägger till JavaScripts och Styles i WordPress). Observera också att vi inte lägger till jQuery som ett beroende för någon av dem. En av fördelarna med Masonry 3 är att det inte är obligatoriskt med jQuery, men kan användas med det. Enligt min erfarenhet är initialisering av Masonry utan jQuery mer tillförlitlig och öppnar upp möjligheten att hoppa över att hämta jQuery, vilket kan hjälpa till med både sidans laddningstider och kompatibilitetsproblem.
Step-by-Step 2: Initialisera JavaScript
Nästa funktion ställer in Masonry, definierar de containers som ska användas med den och ser också till att allt sker i rätt order. Masonry måste göra beräkna storleken på vart och ett av objekten på sidan för att kunna layouta sitt grid dynamiskt. Ett problem som jag har sprungit in i med Masonry i många webbläsare är att Masonry kommer att beräkna höjden på objekt med långsamt hämtar images, vilket leder till överlappande objekt. Lösningen är att använda imagesLoaded för att förhindra Masonry från att beräkna layouten tills alla images har laddats. Detta säkerställer korrekt storlek.
Detta är den funktion och action som kommer att mata ut initialiseringsskriptet i sidfoten på page:
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
Funktionen förklaras steg för steg med inline comments. Vad JavaScript-funktionen gör är att berätta för Masonry att leta inuti en container med ID:n ”masonry-loop” efter objekt med klassen ”masonry-entry” och att beräkna grid endast efter att images har laddats. Vi ställer in den yttre containern med querySelector och den inre med itemSelector.
Step-by-Step 2: Skapa Masonry Loop
Istället för att lägga till HTML markup för Masonry direkt till en template kommer vi att skapa en separat template-del för den. Skapa en new fil som heter ”content-masonry.php” och add den till your theme. Detta kommer att allow you att add the Masonry loop till så många olika templates som you vill.
I din nya fil ska du add to koden som visas under. Markeringen liknar vad du normalt skulle se för en preview av content. Du kan ändra den hur du vill, se bara till att det yttersta elementet har klassen ”masonry-entry” som vi angav som itemSelector i det sista steget.
<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-->
Detta markup har klasser för var och en av dess delar så att you kan add markup för att matcha your theme. Jag gillar att lägga till en fin, något rundad kant till .masonry-entry. Ett annat trevligt alternativ är ingen kant för .masonry-entry, men att ge den en liten skugga. Det ser viss bra ut när inläggsminiatyren utökas hela vägen till kanten av containern, vilket kan åstadkommas genom att ge .masonry-thumbnail marginaler och paddings på 0 i alla riktningar. Du kommer att vilja add to all dessa stilar i en fil som heter masonry.css i ditt temas css directory.
Step 3: Add Masonry Loop till templates
Nu när vi har vår template-del kan du använda den i vilken template som helst i ditt theme som du gillar. Du kanske addar den till index.php, men ej category.php om du inte vill att den ska användas för kategori archives. Om du bara vill att den ska användas på ditt temas home page, när den är inställd på att visa blogginlägg, skulle du använda den i home.php. Oavsett var du väljer behöver du bara omsluta din loop i en container med id:et ”masonry-loop” och add to template-delen i loopen med hjälp av get_template_part(). Var noga med att starta Masonry loop container innan while (have_posts() ).
Här är till exempel huvudslingan från twentythirteen’s 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; ?>
Och här är den ändrad för att få använda vår Masonry loop:
<?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; ?>
Step 4: Ställ in responsiva bredder för objekt i Masonry
Det finns flera sätt som du kan ställa in bredden på varje Masonry-objekt. Du kan ställa in bredden med ett antal pixlar när du initialiserar Masonry. Jag är inte ett fan av att göra det eftersom jag använder responsiva teman och det kräver några komplexa mediefrågor för att få saker rätt på små skärmar. För responsiva designer har jag funnit det bästa att göra är att ställa in ett breddvärde för .masonry-entry med en procentsats, baserat på hur många objekt du vill ha i en row och låta Masonry göra resten av matematiken åt you.
Allt detta är obligatoriskt är att dela 100 med antalet objekt som du vill ställa in procentsatsen i en enkel post i ditt temas style.css. Om du till exempel vill ha fyra objekt i varje row kan du göra detta i din masonry.css-fil:
.masonry-entry{width:25%}
Step 5: Mobiloptimering
Vi skulle kunna sluta här, men jag tycker inte att slutresultatet fungerar särskilt bra på små telefonvyer. När du är nöjd med hur ditt theme ser ut med det new Masonry grid på din dator, kontrollera det på din telefon. Om du ej är nöjd med hur det ser ut på din telefon, då behöver du göra lite arbete.
Jag tror inte att det finns tillräckligt med utrymme på en telefons vy för allt vi har addat till vår content-masonry template-del. Två bra lösningar som är tillgängliga för dig är att förkorta excerptet för telefoner eller hoppa över det helt. Här är en extra funktion som du kan add to functions.php i ditt theme för att göra det. Eftersom jag inte tror att dessa issues är ett problem på surfplattor, använder jag ett bra plugin Mobble i alla exempel i detta avsnitt för att bara göra ändringarna på telefoner, eller ej surfplattor. Jag kontrollerar också om Mobble är aktivt innan jag använder det och vid behov faller jag tillbaka till den mer allmänna mobildetekteringsfunktionen wp_is_mobile som är inbyggd i 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
Som you can see we start by storing the long excerpt length and short excerpt length in variables, since we will be using those values twice and we want to be able to change them from one place if we need to later on. Därifrån testar vi om vi kan använda Mobbles is_phone(). Om så är fallet ställer vi in det korta excerptet för telefoner och det långa excerptet om vi inte är det. Efter det gör vi samma grundläggande sak, men använder wp_is_mobile, vilket kommer att påverka alla mobila enheter ,om is_phone() inte kan användas. Förhoppningsvis kommer else-delen av den här funktionen aldrig att användas, men det är bra att ha en backup för säkerhets skull. När logiken för excerpt-längd är inställd är det bara att åtgärds-hooka funktionen till excerpt_length-filtret.
Att förkorta excerptet är ett alternativ, men vi kan också ta bort det helt och hållet med en enkel process. Här är en new version av content masonry, med hela excerptet utelämnat på telefoner:
<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-->
Den här gången testar vi för att se om vi ej befinner oss på en telefon/mobil device och om så är fallet returnerar vi excerptet i vår loop. Om vi är på en telefon / mobil device gör vi ingenting.
En annan sak du kanske vill göra är att öka bredden på Masonry objekt, vilket minskar antalet i en row, på mobila enheter. För att göra detta kommer vi att lägga till en annan inline-stil i headern baserat på enhetsdetektering. Eftersom den här funktionen använder wp_add_inline_styles kommer den att vara beroende av en specifik formatmall. I det här fallet använder jag masonry.css, vilket du kanske vill, för att hålla dina masonry-stilar separerade. Om du inte vill använda den kan du använda handtaget från en annan, redan registrerad stylesheet.
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
Denna funktion eneuques den custom stylesheet, och sedan sätter ett värde för bredd med hjälp av vad som nu bör vara mycket bekant logik. Efter det skapar vi variabeln $custom_css genom att skicka värdet för bredd till en annars vanlig bit CSS med {$width}. Efter det använder vi wp_add_inline_style för att berätta för WordPress att skriva ut våra inline-stilar i Header när Masonry stylesheet används och sedan åtgärds-hookar vi hela funktionen till wp_enqueue_scripts och vi är klara.
Om du väljer att kombinera dina Masonry-stilar i en befintlig stylesheet, se till att använda handtaget för den stylesheet med wp_add_inline_style eller ej kommer dina inline-stilar inte att inkluderas. Jag gillar att använda wp_add_inline_style eftersom jag i allmänhet omsluter åtgärds-hooken för att köa Masonry i ett villkor så att den bara läggs till när det behövs. Till exempel om jag bara använder Masonry på min blogg index och archive pages skulle jag göra så här:
if ( is_home() || is_archive() ) { add_action( 'wp_enqueue_scripts', 'slug_scripts_masonry' ); }
Dessa sista exempel bör öppna upp några andra idéer i din hjärna. Till exempel kan du använda liknande logik för att hoppa över Masonry helt och hållet på en mobil enhet. Även wp_add_inline_style() är en mindre använd, men ändå mycket användbar funktion eftersom den tillåter dig att programmatiskt ställa in olika stilar baserat på alla typer av villkor. Det kan allow you to radically change the style of any element based on not only device detection, but the changes could also be based on which template is being used, or even if the user is logged in or not.
Jag hoppas att you ser dessa olika förändringar som jag gör som en möjlighet att bli kreativ. Masonry och liknande cascading grid-system har varit populära ett tag nu, så det är dags för några new twists på denna populära idé. Visa oss i kommentarerna vilka coola sätt du har kommit på för att använda Masonry i ett WordPress theme.
Josh Pollock är en mångsidig WordPress-kille som skriver om WordPress, utvecklar teman, fungerar som community manager för Pods Framework och förespråkar lösningar med open source för hållbar design.
Syed Balkhi says
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 says
Hi, i wanted to know if there is a way of using the masonry grid to show registered users. Any ideas?
Neil says
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 says
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 says
I’m having the same problem. Did you guys solve it?
Peter says
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 says
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 says
yeah, i have the same error. any solutions for this?
jcbrmn06 says
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 says
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 says
Done exactly as the tutorial says, wp 3.9.1.. imagesLoaded isn’t even being loaded. Some help would be highly appreciated
Tiago Celestino says
This , where is define ’masonry-thumb’?? this default thumbnail size with masonry WordPress?
WPBeginner Staff says
Checkout our guide on how to properly add javascript and styles in WordPress.
Jenny Beaumont says
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 says
Hi Jenny
I am having the same trouble. Did you solve your problem?
caratcake says
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 says
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 says
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 says
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 says
Will you update your post due to the fact that now with 3.9 Masonry3 is in WordPress core?
Editorial Staff says
Yes we’re working on updating it.
Administratör
Steven Gardner says
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 says
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 says
Thanks! This is the only solution that worked for me.
Kate says
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 says
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 says
Hi,
I’m getting this error: ”ReferenceError: imagesLoaded is not defined” please help.
Violacase says
See above
Amitabha Ghosh says
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 says
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 says
Hi
I was going to comment to point out that it’s a typo and should be:
wp_enqueue_style
Andre says
Great tutorial…just one thing in step 3…this:
…has a missing bracket:
Aurélien Denis says
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 says
Actually, you don’t need to use title attributes.
AndyM says
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 says
Can’t get this working with an infinite scroll setup in my $ajax success CB. Any advice would be great.
Tomasz Bystrek says
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 says
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 says
guys all that code is on functions.php ? thanks