How to get posts only from a specific custom post type, or how to show posts only from a custom taxonomy. How to keep the original query around, how to deal with posts that have post formats enabled and how to enable pagination on a custom loop.
2012.10.06 added the loop pagination technique.
Resources:
- The codex article
- The 4 Ways to Loop with WordPress article is also an excellent read
Basically, there are three ways to loop.
query_posts()method is good to use when modifying the normal loopWP_Query()method is good for multiple loopsget_posts()method is good for additional "mini loops"
In this post, for the sake of simplicity, I'm using only the query_posts()
method.
This article won't cover the basics of looping or the details of building multiple loops. You should read this great article to get to know the basics of a loop: 4 Ways to Loop with WordPress.
Basic loop
As a reminder, here is the normal bare-bones loop.
<?php
if (have_posts()) : while (have_posts()) : the_post();
?>
<!-- Do stuff -->
<?php
endwhile; else:
?>
<p>Sorry, no posts to display</p>
<?php
endif;
?>Get posts from a specific custom post type
Custom post types have changed WP from a blogging platform into a real CMS. Getting posts from specific custom post types could not be easier.
<?php
// get all music post types
query_posts('post_type=music');
if (have_posts()) : while (have_posts()) : the_post();
?>
<!-- Do stuff -->
<?php endwhile; endif; ?>That’s it. By the way, here are all the parameters you can use to edit the loop.
Get posts from a specific custom taxonomy
2015.04.20 Don't use
query_postsanymore, it's not recommended, usepre_get_postshook. See my new post on looping: "An in depth look into the WP_Query and a WordPress loop".
Custom taxonomies are handy, but looping them is a bit different from what we're used to. If you only need to display the current term, see how to get a custom taxonomy term name.
We'll use the array method rather than query strings.
Query string method looks like this:
query_posts('post_per_page=10&cat=7');And this is the array method:
$args = array(
'post_per_page' => 10,
'cat' => 7
);
query_posts($args);Here’s the loop. It uses tax_query, which is an array of arrays.
This example gets 10 posts from the "music" taxonomy in the "mix-tapes" term. See the comments in the code.
<?php
$args = array(
'posts_per_page' => 10,
//Using tax_query
'tax_query' => array(
array(
'taxonomy' => 'music', //taxonomy
'field' => 'slug', //this can be also id
'terms' => array( 'mix-tapes' ) //the term in the taxonomy
)
)
);
query_posts($args);
if (have_posts()) : while (have_posts()) : the_post();
?>
<!--Do stuff-->
<?php endwhile; endif; ?>Easy.
If you want more complex loops you can just add more arrays. This example requires the posts also to have a "thing" as a tag. You can go really specific!
$args = array(
'posts_per_page' => 10,
//Using tax_query
'tax_query' => array(
//start the array for the first condition
array(
'taxonomy' => 'music', //taxonomy
'field' => 'slug', //this can be also id
'terms' => array( 'mix-tapes' ) //the term in the taxonomy
),
//start the arrays for the second condition
array(
'taxonomy' => 'post_tag', //taxonomy
'terms' => array('thing'), //tag
'field' => 'slug'
)
)
);
query_posts($args);What if you want all posts in "mix-tapes" and all posts with a tag named "thing"? The above got only the ones with both.
You can use the relation parameter.
$args = array(
'posts_per_page' => 10,
'relation' => 'OR', //relations parameter, get both terms
'tax_query' => array(
//star the array for the first condition
array(
'taxonomy' => 'music', //taxonomy
'field' => 'slug', //this can be also id
'terms' => array( 'mix-tapes' ) //the term in the taxonomy
),
//start the arrays for the second condition
array(
'taxonomy' => 'post_tag', //taxonomy
'terms' => array('thing'), //tag
'field' => 'slug'
)
)
);
query_posts($args);Dealing with posts that have post format applied
If you don't know about post formats, see the codex.
Post formats are handy little things. There is a conditional tag for them.
if (has_post_format('link')) {
// Do stuff specific to link format
}Sometimes you may want to weed the links out from the main loop and display them
in the sidebar. has_post_format() doesn't really help you in that. The
following code is bad and not really working.
if (have_posts()) : while (have_posts()) : the_post();
if ( has_post_format( 'link' )) {
// Do nothing
} else {
// Normal loop stuff
}
endwhile; endif; wp_reset_query();Yes, that removes the links from the loop but it counts the links as it counts the normal posts. Meaning, if you have four links, and you want to show 10 posts in your home page, it only shows six posts, because it counts the links as well.
Here's how to do that properly using the same method as for taxonomies. Post
formats are nothing but term in a post_format taxonomy. Here we take use of the
operator parameter on line 8.
$args = array(
'posts_per_page' => 10,
'tax_query' => array(
array(
'taxonomy' => 'post_format',
'field' => 'slug',
'terms' => array( 'post-format-link' ),
// This tells the loop to skip the links
'operator' => 'NOT IN'
)
)
);
query_posts($args);So, that skipped all links. If you want only the links, just remove the
operator line.
Read more about the operators in codex.
How to keep the original query around
What does that even mean? It means that WordPress is smart (of course), on home
page when you have the normal loop with no special added to it, WP gets all the
posts, but when you're viewing a category archive, WP only gets posts for that
category, right? But, what if you want, on the category page, reduce the amount
of posts from the preset 10? Then you say query_posts('posts_per_page=7')
before the loop. But this "breaks" the loop by ignoring that you are on a
category page and it gets posts from all categories. Not what you wanted.
Here's how you can customize the loop without "breaking" it.
<?php
global $query_string; //the magic line
query_posts($query_string.'&posts_per_page=7');
if (have_posts()) : while (have_posts()) : the_post();
?>
<!--Do stuff-->
<?php endwhile; endif; ?>If you're using the array method for getting the parameters, it can be a little confusing. This will not work.
global $query_string; //the magic line
$args = array(
'posts_per_page'=> 7,
'order' => 'ASC'
)
query_posts($query_string . $args);
if (have_posts()) : while (have_posts()) : the_post();You need to merge the query array to the parameter array.
global $query_string; //the magic line
$args = array_merge(
$wp_query->query,
array(
'posts_per_page'=> 7,
'order' => 'ASC'
)
);
query_posts($args);
if (have_posts()) : while (have_posts()) : the_post();Enable pagination on a custom loop
Another thing that is easy to break when building a custom loop is the pagination. Your loop shows the right amount of posts, but the "next" and "previous" buttons won't appear. There's an easy fix.
<?php
$paged = get_query_var('paged') ? get_query_var('paged') : 1; //The magic, ternary if statement
$args = array(
'posts_per_page' => 5, //Show 5 posts per page
'post_type' => 'projects', //From projects post type
'paged' => $paged //Enable the pagination
);
query_posts($args);
if ( have_posts() ) : while ( have_posts() ) : the_post();
?>
<!-- Do stuff -->
<?php endwhile; endif; ?>That’s about it for today.