Get posts for custom taxonomies & terms in WordPress

27 September, 2013 by Tom Elliott

Taxonomies are basically a way of grouping data in WordPress. The most common default taxonomies used in WordPress are when grouping posts as either ‘categories’ or ‘tags’ and these are named and recorded in the WordPress database as ‘category’ and ‘post_tag’ respectively. Specific categories or tags are called terms.

Many plugins and theme functionality will use their own custom taxonomies to group data together in a meaningful way. A photo gallery for example might have a taxonomy name ‘gallery_cat’ with terms such as ‘Sunsets’, ‘Portraits’, ‘Nature’ etc. Each term has an associated name, slug and term ID.

To query WordPress and return posts based on these custom taxonomy names and terms, we can use ‘tax_query’ within get_posts() as indicated below:

<?php
get_posts(array(
	'post_type' => 'gallery',
	'tax_query' => array(
		array(
		'taxonomy' => 'gallery_cat',
		'field' => 'term_id',
		'terms' => 45)
	))
);
?>

The ‘tax_query’ array takes 3 required arguments:

  1. ‘taxonomy’- the slug that is used to identify the taxonomy.
  2. ‘field’ – can be either ‘term_id’ (the numeric ID of the term), ‘slug’ or ‘name’ (the term name such as ‘Sunsets’)
  3. ‘terms’ – will need to be the ID value, slug or name depending what ‘field’ is set to.

Here’s another example which will select all posts with the terms ‘Sunsets’ and ‘Nature’, based on the same custom taxonomy. As you can see, to select multiple terms from the custom taxonomy, we need to put them as a comma seperated string within an array.

<?php
get_posts(array(
	'showposts' => -1,
	'post_type' => 'gallery',
	'tax_query' => array(
		array(
		'taxonomy' => 'gallery_cat',
		'field' => 'name',
		'terms' => array('Sunsets', 'Nature'))
	),
	'orderby' => 'title',
	'order' => 'ASC')
);
?>

We have set ‘showposts’ to -1 so that all posts will be returned and the posts will be ordered alphabetically by title.

If you are unsure of what values should go into post_type, taxonomy and terms, the easiest way to find out is to select the custom taxonomy and one of the terms within the WordPress admin and look at the URL at the top, as shown in the below.

Custom Taxonomy URL sample

Finally, we can put all this in a simple loop to display our content, title and ID of all posts belonging to our chosen terms.

<?php
$myposts = get_posts(array(
	'showposts' => -1,
	'post_type' => 'gallery',
	'tax_query' => array(
		array(
		'taxonomy' => 'gallery_cat',
		'field' => 'slug',
		'terms' => array('sunsets', 'nature'))
	))
);

foreach ($myposts as $mypost) {
      echo $mypost->post_title . '<br/>';
      echo $mypost->post_content . '<br/>';
      echo  $mypost->ID . '<br/><br/>';
}
?>


Creating a manual list of related posts in WordPress »
Improve a WordPress website Page Speed by 50% in 5 minutes »


22 Comments

  • capiedge says:

    Hi Tom!
    Thanks for sharing!

    I try your code, and I think that inside of tax_query, one of the “array(” is not necessary.

  • capiedege says:

    So, writing it as below, isn’t correct?

    ‘tax_query’ => array(
    ‘taxonomy’ => ‘gallery_cat’,
    ‘field’ => ‘slug’,
    ‘terms’ => array(‘sunsets’, ‘nature’));

    Thanks again 😉

  • Janeth says:

    Hello Tom,

    Thank you for your tutorial. I was wondering. I created a custom post type named directory. Also I created a custom taxonomy named directorycategories, in which I have three categories: shop, play and stay.

    I am trying to create a different taxonomy template for each slug, to create my directory. so if you click over shop link it will display all the directory list. So, according to your tutorial, the first script should be added in which templates and the second one where? Sorry, I am just starting with wordpress and it is been a huge headache, but I know I will get it. 🙂

    Thanks in advance

    • Tom Elliott says:

      Hi Janeth, I know what you mean.. I felt the same when starting WordPress (still do sometimes!). Each of the 3 code blocks are just 3 different examples, with the last example just showing how get_posts for the taxonomies can be put in a loop to output content, and should work in your template file.

  • Mr Twister says:

    Thanks a lot!

  • Smith says:

    Excellent ! It worked perfectly.You saved my time. I spent many time to find this code. Thanks a lot!

  • Christian Saborio says:

    +1 to the people who are grateful for this. I was trying to display posts that had similar tags on the sidebar, and this did the trick. Thanks!

  • vega says:

    Hi Tom,

    I found your post here and maybe you can help me out. I created a custom taxonomy for three galleries, which I want to show on three fixed pages. I used that code for that in my child function.php:

    function is_add_categories_to_attachments() {
    register_taxonomy_for_object_type( ‘category’, ‘attachment’ );
    }
    add_action( ‘init’ , ‘is_add_categories_to_attachments’ );

    That worked and now I could create those categories (alpha, beta, gamma).

    Then I tried this code to show a gallery with ALL the pictures within a stated category on a page:

    [gallery type="squares" category="alpha" order="DESC" orderby="ID" link="file"]

    Well, that did not work, because the standard gallery_shortcode does not support categories, of course.

    Then I copied the complete gallery_shortcode to the child function.php and used the post_gallery filter, so that I can alter the gallery_shortcode there without a problem:

    function is_gallery($output, $attr) {
    $post = get_post();

    static $instance = 0;
    $instance++;

    if ( ! empty( $attr[‘ids’] ) ) {
    // ‘ids’ is explicitly ordered, unless you specify otherwise.
    if ( empty( $attr[‘orderby’] ) )
    $attr[‘orderby’] = ‘post__in’;
    $attr[‘include’] = $attr[‘ids’];
    }

    // Allow plugins/themes to override the default gallery template.
    $output = apply_filters(‘post_gallery’, ”, $attr);
    if ( $output != ” )
    return $output;

    // We’re trusting author input, so let’s at least make sure it looks like a valid orderby statement
    if ( isset( $attr[‘orderby’] ) ) {
    $attr[‘orderby’] = sanitize_sql_orderby( $attr[‘orderby’] );
    if ( !$attr[‘orderby’] )
    unset( $attr[‘orderby’] );
    }

    extract(shortcode_atts(array(
    ‘order’ => ‘ASC’,
    ‘orderby’ => ‘menu_order ID’,
    ‘id’ => $post ? $post->ID : 0,
    ‘itemtag’ => ‘dl’,
    ‘icontag’ => ‘dt’,
    ‘captiontag’ => ‘dd’,
    ‘columns’ => 3,
    ‘size’ => ‘thumbnail’,
    ‘include’ => ”,
    ‘exclude’ => ”,
    ‘link’ => ”
    ), $attr, ‘gallery’));

    $id = intval($id);
    if ( ‘RAND’ == $order )
    $orderby = ‘none’;

    if ( !empty($include) ) {
    $_attachments = get_posts( array(‘include’ => $include, ‘post_status’ => ‘inherit’, ‘post_type’ => ‘attachment’, ‘post_mime_type’ => ‘image’, ‘order’ => $order, ‘orderby’ => $orderby) );

    $attachments = array();
    foreach ( $_attachments as $key => $val ) {
    $attachments[$val->ID] = $_attachments[$key];
    }
    } elseif ( !empty($exclude) ) {
    $attachments = get_children( array(‘post_parent’ => $id, ‘exclude’ => $exclude, ‘post_status’ => ‘inherit’, ‘post_type’ => ‘attachment’, ‘post_mime_type’ => ‘image’, ‘order’ => $order, ‘orderby’ => $orderby) );
    } else {
    $attachments = get_children( array(‘post_parent’ => $id, ‘post_status’ => ‘inherit’, ‘post_type’ => ‘attachment’, ‘post_mime_type’ => ‘image’, ‘order’ => $order, ‘orderby’ => $orderby) );
    }

    if ( empty($attachments) )
    return ”;

    if ( is_feed() ) {
    $output = “n”;
    foreach ( $attachments as $att_id => $attachment )
    $output .= wp_get_attachment_link($att_id, $size, true) . “n”;
    return $output;
    }

    $itemtag = tag_escape($itemtag);
    $captiontag = tag_escape($captiontag);
    $icontag = tag_escape($icontag);
    $valid_tags = wp_kses_allowed_html( ‘post’ );
    if ( ! isset( $valid_tags[ $itemtag ] ) )
    $itemtag = ‘dl’;
    if ( ! isset( $valid_tags[ $captiontag ] ) )
    $captiontag = ‘dd’;
    if ( ! isset( $valid_tags[ $icontag ] ) )
    $icontag = ‘dt’;

    $columns = intval($columns);
    $itemwidth = $columns > 0 ? floor(100/$columns) : 100;
    $float = is_rtl() ? ‘right’ : ‘left’;

    $selector = “gallery-{$instance}”;

    $gallery_style = $gallery_div = ”;
    if ( apply_filters( ‘use_default_gallery_style’, true ) )
    $gallery_style = ”

    #{$selector} {
    margin: auto;
    }
    #{$selector} .gallery-item {
    float: {$float};
    margin-top: 10px;
    text-align: center;
    width: {$itemwidth}%;
    }
    #{$selector} img {
    border: 2px solid #cfcfcf;
    }
    #{$selector} .gallery-caption {
    margin-left: 0;
    }
    /* see gallery_shortcode() in wp-includes/media.php */
    “;
    $size_class = sanitize_html_class( $size );
    $gallery_div = “”;
    $output = apply_filters( ‘gallery_style’, $gallery_style . “ntt” . $gallery_div );

    $i = 0;
    foreach ( $attachments as $id => $attachment ) {
    if ( ! empty( $link ) && ‘file’ === $link )
    $image_output = wp_get_attachment_link( $id, $size, false, false );
    elseif ( ! empty( $link ) && ‘none’ === $link )
    $image_output = wp_get_attachment_image( $id, $size, false );
    else
    $image_output = wp_get_attachment_link( $id, $size, true, false );

    $image_meta = wp_get_attachment_metadata( $id );

    $orientation = ”;
    if ( isset( $image_meta[‘height’], $image_meta[‘width’] ) )
    $orientation = ( $image_meta[‘height’] > $image_meta[‘width’] ) ? ‘portrait’ : ‘landscape’;

    $output .= “”;
    $output .= ”

    $image_output
    “;
    if ( $captiontag && trim($attachment->post_excerpt) ) {
    $output .= ”

    ” . wptexturize($attachment->post_excerpt) . ”
    “;
    }
    $output .= “”;
    if ( $columns > 0 && ++$i % $columns == 0 )
    $output .= ”;
    }

    $output .= ”

    n”;

    return $output;
    }
    add_filter(“post_gallery”, “is_gallery”,10,2);

    … but here I am stuck. I am just no PHP/Wordpress pro to know how to add the category feature to gallery_shortcode construct. Do you know how to do that?

    Thank you in advance.

  • sanjeet says:

    how to get posts from a perticular portfolio ID , if someone know please answer it

    I want to show the posts from a specific category in recent work

    I have the following code-

    //this shows the single post
    ‘attachment’,
    ‘orderby’ => ‘menu_order’,
    ‘order’ => ASC,
    ‘numberposts’ => -1,
    ‘post_status’ => null,
    ‘post_parent’ => $post->ID,
    );
    $attachments = get_posts($args);
    if ( $attachments ):
    foreach ( $attachments as $attachment ):
    echo wp_get_attachment_image($attachment->ID, ‘full’);
    endforeach;
    endif;
    ?>

    /// this shows the recent work posts

    $term = get_term_by(‘slug’, get_query_var(‘term’), get_query_var(‘taxonomy’));
    query_posts(
    array(
    ‘post_type’ => ‘portfolio’,
    ‘category_id’ => $current_can,
    #’category_name’ => $current_ca,
    ‘posts_per_page’ => 12,
    ‘post__not_in’ => array($post->ID)

    )
    );

    thank you.

  • Selvam says:

    Can we set custom taxonomies for wordpress posts? not custom post types

  • Peter says:

    Thanks for this tut – seems to work fine except for displaying images. I an using acf to store the associated url for the image on each post. However the images do not show up when listing the posts in the taxonomy. When I inspect the element using Google Chrome it shows a number as a url – any ideas?
    Regards

  • zuhaib says:

    Can anyone tell me how to use term_id in this
    ‘offers’,
    ‘posts_per_page’ => 4,

    );

    query_posts($args2);
    if (have_posts()): while(have_posts()): the_post();
    ?>

  • Magglr says:

    Thanks for this guide.

  • Mike England says:

    I would like to personally thank you for writing this article as it helped me understand what I was doing wrong when trying to write a Taxonomy Query.

  • chi~ says:

    Thank you so much! It helped me in understanding my code better. 😀

  • Austin says:

    Man, I love you. Been searching so long for this solution…

  • Sergio says:

    Hello, this the order is by date post, How can I show first sunsets’, and second ‘nature’