Support » Fixing WordPress » Custom Taxonomy – Related Posts Query

  • I just started experimenting with Custom Taxonomies in WordPress 3.0.1.

    I understand how to query posts associated with my custom taxonomy when explicitly stating a term, but I can’t figure out how to create a dynamic query for something like related posts.

    I expected that if my custom taxonomy functioned as a replacement for the default categories for a custom post type that I could simply use the typical category related tags like get_the_category(); to interact with the custom taxonomy, but that does not seem to be the case.

    For example, in a single.php template, I would typically add the following code to the sidebar to display the titles of other posts in the same category as the main post.

    <?php
    $categories = get_the_category($post->ID);
    if ($categories) {
    	$category_ids = array();
    	foreach($categories as $individual_category) $category_ids[] = $individual_category->term_id;
    
    	$args=array(
    		'category__in' => $category_ids,
    		'post__not_in' => array($post->ID),
    		'showposts'=>5, // Number of related posts that will be shown.
    		'caller_get_posts'=>1
    	);
    	$my_query = new wp_query($args);
    	if( $my_query->have_posts() ) {
    		echo '<h3>Related Posts</h3><ul>';
    		while ($my_query->have_posts()) {
    			$my_query->the_post();
    		?>
    			<li><a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>"><?php the_title(); ?></a></li>
    		<?php
    		}
    		echo '</ul>';
    	}
    }
    ?>

    Does anyone know how the same result is achieved when using a custom taxonomy? In essence, I’m looking for the the alternative to the_get_category(); function for custom taxonomies.

    http://codex.wordpress.org/Function_Reference/get_the_category

    I haven’t tried anything similar when the custom taxonomy functions like tags, but I suppose I’d run into similar problems. So down the road, I’ll likely be looking for an alternative to the get_the_tags(); function as well. Thus, even though I have a specific question, I also have a broader question about the functions for custom taxonomies that replace their category and tag counterparts. I may be missing it in the codex, but it doesn’t seem like this is clearly addressed anywhere.

Viewing 15 replies - 1 through 15 (of 27 total)
  • I’d like to note that I originally got the code for displaying related posts by category from Binny VA’s blog. I’ve implemented it on other WordPress sites, so I know it works.

    http://www.bin-co.com/blog/2009/04/show-related-post-in-wordpress-without-a-plugin/

    I ended up rolling my own function for this task based on the get_the_category() function. Basically, it uses the wp_get_object_terms() function and adds some caching. I haven’t tested it extensively, but it’s been working for me so far.

    function get_the_taxonomy( $taxonomy, $id = false ) {
    	global $post;
    
    	$id = (int) $id;
    	if ( !$id )
    		$id = (int) $post->ID;
    
    	$categories = get_object_term_cache( $id, $taxonomy );
    	if ( false === $categories ) {
    		$categories = wp_get_object_terms( $id, $taxonomy );
    		wp_cache_add($id, $categories, $taxonomy.'_relationships');
    	}
    
    	if ( !empty( $categories ) )
    		usort( $categories, '_usort_terms_by_name' );
    	else
    		$categories = array();
    
    	foreach ( (array) array_keys( $categories ) as $key ) {
    		_make_cat_compat( $categories[$key] );
    	}
    
    	return $categories;
    }

    Hope that helps you out!

    Chris

    The code from chris seems to belong in the function.php, right ? So it’s just there to make the “get_the_taxonomy” working, right?

    If so, how is the code which I supposed to put in the taxonomy.php or single.php or whatever to get the posts of a category of a custom-taxonomy???

    When I tried that out in twenty ten, I got this error message:
    Warning: Missing argument 1 for get_the_taxonomy(), called in /home1/englisi9/public_html/testblog/wp-content/themes/twentyten/getthetax.php on line 8 and defined in /home1/englisi9/public_html/testblog/wp-content/themes/twentyten/functions.php on line 485

    Warning: array_keys() [function.array-keys]: The first argument should be an array in /home1/englisi9/public_html/testblog/wp-content/themes/twentyten/functions.php on line 503

    Would love to see it work.

    I’ve tried it, it produces a nice array object of the given taxonomy but not hierarchical…

    Hi,

    I’m using this code to retrieve related posts based on my custom taxonomy. It works great, but the only problem is that I’m trying to retrieve a total of 4 related posts. This retrieves up to 4 posts per term. What am I doing wrong?

    <?php
    global $post;
    $terms = get_the_terms( $post->ID , 'badge', 'string');
    $do_not_duplicate[] = $post->ID;
    $postnum = 0;
    
    if(!empty($terms)){
        foreach ($terms as $term) {
            query_posts( array(
            'badge' => $term->slug,
            'showposts' => 3,
            'caller_get_posts' => 1,
            'post__not_in' => $do_not_duplicate ) );
            if(have_posts()){ ?>
    
                <?php while ( have_posts() ) : the_post(); $do_not_duplicate[] = $post->ID; ?>
    		<?php $postnum++; ?>
    	<div class="single-small-posts-<?php echo $postnum; ?>">
          			<?php
    			$clipping_image = get_post_meta( $post->ID, 'clipping_image', true );
    			$terms_of_post = get_the_term_list( $post->ID, 'type', '','', '', '' );?>
    
    			<a href="<?php the_permalink() ?>" rel="bookmark" title="<?php the_title();?>"><img src="<?php bloginfo('template_directory'); ?>/scripts/timthumb.php?src=<?php echo $clipping_image ?>&h=140&w=140&zc=1"></a>
    				<p class="single-small-post-cat"><?php if( $terms_of_post ) echo $terms_of_post; ?></p><p class="single-small-post-number">#<?php echo get_post_meta($post->ID,'incr_number',true); ?></p>
    
    		</div>
            		<?php $found_none = '';
         			endwhile; wp_reset_query();
    ?>
    
        <?php }
      }
    }
    if ($found_none) {
    echo $found_none;
    }
    $post = $backup;  // copy it back
    wp_reset_query(); // to use the original query again
    ?>

    maybe increase this number to more than 3?
    'showposts' => 3,

    Hello,

    I tried fcarthy’s code but it throws back a bunch of posts even if they aren’t using taxonomy terms…

    I only have one post that uses one of my “Brands” taxonomy terms, so this script should only return one post. I don’t understand how its fetching the results.

    I am trying to display related “posts” on a custom post type’s single.php template, based on wether or not the posts are associated with at least one of the same terms (in my Brands taxonomy) as the current custom post.

    Does someone know how to do this? I just can’t get this to work properly.
    Thanks,
    C.

    @mistercyril

    Here is the code I have thats functioning. It looks for your specified custom taxonomy, and outputs up to 4 posts that have the same tags. The only problem with this code is that it will find 4 posts for EACH term found. I haven’t been able to make it a total of 4 posts.

    <?php
    global $post;
    $terms = get_the_terms( $post->ID , 'badge', 'string'); //change badge to your taxonomy, these are my tags
    $do_not_duplicate[] = $post->ID;
    $postnum = 0;
    
    if(!empty($terms)){
        foreach ($terms as $term) {
            query_posts( array(
            'badge' => $term->slug, //custom taxonomy, these are my tags
            'showposts' => 4,
    	'orderby' => 'rand', //orders results randomly
            'caller_get_posts' => 1,
            'post__not_in' => $do_not_duplicate ) );
            if(have_posts()){ ?>
    
                <?php while ( have_posts() ) : the_post(); $do_not_duplicate[] = $post->ID; ?>
    		<?php $postnum++; //generates a unique number for each post and applies it to its class to have theming control ?>
    	<div class="post-<?php echo $postnum; ?>">
          			<?php
    			$clipping_image = get_post_meta( $post->ID, 'clipping_image', true );
    			$terms_of_post = get_the_term_list( $post->ID, 'type', '','', '', '' );//change type to your post type ?>
    
    				<?php if( $terms_of_post ) echo $terms_of_post; ?>
    
    		</div>
            		<?php $found_none = '';
         			endwhile; wp_reset_query();
    ?>
    
        <?php }
      }
    }
    if ($found_none) {
    echo $found_none;
    }
    $post = $backup;  // copy it back
    wp_reset_query(); // to use the original query again
    ?>

    *Place code in loop

    I’ve commented some of my code to help you out. I may have left some divs or p tags around from my own code by accident. Please check before using. Let me know if that works.

    @fcarthy, @mistercyril

    Just taking a quick look at that code, if you want it to just print the first 4 posts that it finds, I think you can simply add this to the beginning of the foreach loop:

    if($postnum >= 4) break;

    Not tested or anything, but I hope that helps.

    I forgot to mention to place my code in the loop.

    @sevenspark My problem has always been that I want it to randomize how it finds the posts. If i get what you’re saying this is what would happen:

    Say we have a post with 2 tags. If the first tag has 4 or more posts associated with it, it would display those 4 posts, but disregard the second tag.

    @fcarthy, yes that is correct.

    If you want be “fair” with the tag distribution, you’d want to collect 4 potential posts from each tag in arrays and then loop through each until you have enough. You might do something like this:

    $potentials = array();
    $c = 0;
    $totalFound = 0;
    //Gather your posts for each term
    foreach($terms as $term_name){
       $q = array(
    	'my_custom_tax' =>	$term_name,
    	'numberposts' => 4
       );
       $posts = get_posts($q);
       $totalFound+= count($posts);
       $potentials[$c++] = array_reverse($posts);
    }
    $count = 0;  //The number of good posts we've found
    $index = 0;  //Number of posts we've tried
    $max = $totalFound > 4 ? 4 : $totalFound;
    $posts = array();
    //Now pick one post from each term until we reach our quota, or have checked them all
    while($count < $max){
      //Pop off a post to use
      $post = array_pop($potentials[$index++]);
      //only works if there is a post left in this array
      if($post){
        //don't take duplicates
        if($empty($posts[$post->ID])){
          $posts[$post->ID] = $post;
          $count++;
        }
      }
      $index = ($index % 4);
    }
    foreach($posts as $post){
      //print your posts
    }
    

    This is off the top of my head and untested, but it’s something to play with at least 🙂

    @sevenspark Thanks for your input.

    I just tried it out and am getting : Warning: Invalid argument supplied for foreach()

    I replaced ‘my_custom_tax’ with ‘Brands’ (the taxonomy i want to use). Is this where I should be doing this?

    Also, how can I limit the search to a specific post-type (i.e. posts)?

    Here’s what i have so far:

    <?php
    $potentials = array();
    $c = 0;
    $totalFound = 0;
    //Gather your posts for each term
    foreach($terms as $term_name){
       $q = array(
    	'Brands' => $term_name,
    	'post_type' => 'post',
    	'numberposts' => 4
       );
       $posts = get_posts($q);
       $totalFound+= count($posts);
       $potentials[$c++] = array_reverse($posts);
    }
    $count = 0;  //The number of good posts we've found
    $index = 0;  //Number of posts we've tried
    $max = $totalFound > 4 ? 4 : $totalFound;
    $posts = array();
    //Now pick one post from each term until we reach our quota, or have checked them all
    while($count < $max){
      //Pop off a post to use
      $post = array_pop($potentials[$index++]);
      //only works if there is a post left in this array
      if($post){
        //don't take duplicates
        if($empty($posts[$post->ID])){
          $posts[$post->ID] = $post;
          $count++;
        }
      }
      $index = ($index % 4);
    }
    foreach($posts as $post){
      //print your posts
    }
    ?>

    Yeah, the code isn’t complete. It’s assumed you already have $terms in an array to loop through. You could test it by setting:

    $terms = array( 'term1', 'term2', 'term3' );

    at the top.

    my_custom_tax should get replaced with the slug of the custom taxonomy (most likely ‘brands’ not ‘Brands’)

    To limit the post type just set ‘post_type’ => ‘post’ in the $q array.

    ah but that means terms need to be hard coded right? I think fcarthy and I need to get the terms from the custom post type being viewed and search for corresponding posts (using the same taxonomy terms).

    Am I completely off track?

Viewing 15 replies - 1 through 15 (of 27 total)
  • The topic ‘Custom Taxonomy – Related Posts Query’ is closed to new replies.