Support » Plugins » Hacks » FIltering posts based on custom taxonomies and categories

  • Resolved Kevin


    Hey guys,

    I’m trying to design a sidebar which lists links to the archive pages for posts based on specific categories and my custom taxonomy labeled “Topics”. I have 4 Categories (Teachings, Posts, Media, Books) and multiple hierarchical “Topics” (i.e. Theology, Philosophy, History, etc.).

    What is making this difficult is that each Topic belongs to multiple Categories. For example, I might have a post that reviews a historical biography (Category=Book, Topic=History), while at the same time have a post that contains a video discussing historical events (Category=Media, Topic=History). Using this example, what I am trying to do is make sure that for every time someone is on post or page that belongs to the Media Category, the sidebar is only listing taxonomies which will link to the videos and not the books. I hope that makes sense. If not here is an example of what I am trying to do:

    (Sidebar when someone is on a media page)
    Theology            (Cat=Media, Topic=Theology)
      -God              (Cat=Media, Topic=Theology->God)
      -Religions        (Cat=Media, Topic=Theology->Religions)
    Philosophy          (Cat=Media, Topic=Philosophy)
      -Metaphysics      (Cat=Media, Topic=Philosophy->Metaphysics)
      -Ethics           (Cat=Media, Topic=Philosophy->Ethics)
Viewing 8 replies - 1 through 8 (of 8 total)
  • Moderator bcworkz


    You can use the ‘tax_query’ arguments of WP_Query to construct elaborate taxonomy queries spanning multiple taxonomies with varying logical relationships.

    Thanks bc, is there a way to use the tax_query arguments and return the terms instead of the posts? I should have mentioned I initially tried using a tax_query with the following code:

    $filterTeachings['tax_query'] = array(
        'relation' =--> 'AND',
            'taxonomy' => 'category',
            'terms' => array('teachings'),
            'field' => 'slug',
            'taxonomy' => 'topics',
            'field' => 'slug',

    But as you can see, it is querying the posts instead of the terms. I have played around with the get_terms argument and searched online how to include two taxonomies, but nothing has worked. Ideally I would like something like this:

    $termfilter = array(
                      'category => 'media',
                      'parent' => 0,
    get_terms( 'topics', $termfilter );

    The problem is that the category value doesn’t fit within the parameters of the get_terms function. Unless I am missing something…

    In fact, now that I think about it, even if I did accomplish this would there be an archive page it would link to? For instance, I would need archive pages with this type of url:

    Would I have to manually create archive pages for each instance like this?

    Moderator bcworkz


    I think I get where you’re going with this. You have to get posts as part of the process, they are the only thing the two taxonomies have in common. WP_Query only works for getting records in the posts table, not taxonomy terms. There’s probably some way to write a complex mySQL query to get what you want through $wpdb, but I’ve no idea what that might look like.

    An alternative, much less efficient, would be to go through the posts returned by WP_Query and extract all relevant terms for listing in the sidebar.

    You don’t need to manually create archives for the ultimate result, for that you can use tax_query. You can have a complex URL like you suggest. It’s a matter of creating the right rewrite rules so the terms find their way into the proper parts of the archive tax_query.

    Thanks bc. The second is what I’ve been planning on doing.

    I think everything would be easier in the long run if I made custom post types for Teachings, Media, and Books instead of assigning them as categories. If you are interested, I did find a post that relates to what we have been talking about, especially you’re suggestion to use $wpdb. Check out Get Terms by Taxonomy and Post-type . When I’m done with everything, I’ll post the code I used just in case it would help any one in the future, and also to see whether or not it is the cleanest solution. Thanks again.

    OK, so here’s what I came up with. Keep in mind that I’m brand new to php so I am not expecting this to be the most efficient way to do this. If anyone has a cleaner way, please feel free to correct me.

    So I made Teachings, Posts, Media, and Books into categories as well as custom post types. The plan is to have the archive page query its posts, and if they have the same post-type, the post-type’s name will be assigned to $type…

    <div class = "sidebar">
    	<div class="sidebar-title">ALL TOPICS </div>
    		<?php // Retrieve Terms based on Current Post-type
    			$type = //this will be the common post-type of posts on the page
    			$args = array(
    						'post_type' => $type,
    						'parent' => 0,
    			$terms = get_terms( 'topics', $args ); // Parent Terms belonging to post-type
    			$args= array(
    						'post_type' => $type,
    			$child_objects = get_terms( 'topics', $args ); // Child Terms belonging to post-type
    			$child_array = json_decode(json_encode($child_objects), true); // Turns objects into strings within multiple arrays
    		<ul id="accordion">
    			<?php //Sidebar Display
    				if ($type == NULL) {
    						$query_var = "";
    					else {
    						$query_var = "/?post_type=" .$type;
    				foreach($terms as $term) {  // For Parents
    					$parentlink = site_url( "/topics/" .$term->slug. $query_var );
    					echo '<li><a href="' .$parentlink. '">'.$term->name.'</a>';
    					echo '<ul>';
    					$term_children = get_term_children($term->term_id,'topics', $args); // For Children
    					foreach($term_children as $term_child_id) {
    						$term_child = get_term_by('id',$term_child_id,'topics');
    						$term_child_array = json_decode(json_encode($term_child), true); // Turns objects into strings within a single array
    						foreach ($child_array as $array) { // Sorts through subarrays which contain term_ids
    							if ( $term_child->term_id == $array['term_id'] ) {
    								$childlink = site_url( "/topics/" .$term_child->slug. "/?post_type=" .$type );
    								echo '<li><a href="' .$childlink. '">' . $term_child->name . '</a></li>';
    					echo '</ul></li>';

    Moderator bcworkz


    I guess I still didn’t fully understand your organizational structure when I suggested you needed to retrieve posts to do this. There is probably a way to do this with only hierarchical taxonomies. However, assigning some part of the organization as post types is not that bad. In fact, not bad at all! Good thinking! It removes some of the complications induced by multiple taxonomies and makes constructing URLs much easier.

    I don’t know about you, but this scheme doesn’t make my head hurt trying to grasp the entire concept like the other one did 🙂 From a DB standpoint this may actually be better than pure taxonomies, though at the cost of loading up PHP with custom post type (CPT) overhead. Overall I’d say it’s a wash. If you had 50 CPTs it would be a different story, but if limited to about a half dozen I don’t think it’s worth worrying about.

    Awesome. Thanks for your input bc.

Viewing 8 replies - 1 through 8 (of 8 total)
  • The topic ‘FIltering posts based on custom taxonomies and categories’ is closed to new replies.