Before I launched my blog (about 5 weeks ago), one of the things I looked for, was a clean and easy way to display related posts without installing a plugin.

After a quick search I found this post with the following code:

<?php
//for use in the loop, list 5 post titles related to first tag on current post
$tags = wp_get_post_tags($post->ID);
if ($tags) {
  echo 'Related Posts';
  $first_tag = $tags[0]->term_id;
  $args=array(
    'tag__in' => array($first_tag),
    'post__not_in' => array($post->ID),
    'showposts'=>5,
    'caller_get_posts'=>1
   );
  $my_query = new WP_Query($args);
  if( $my_query->have_posts() ) {
    while ($my_query->have_posts()) : $my_query->the_post(); ?>
      <p><a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>"><?php the_title(); ?></a></p>
      <?php
    endwhile;
  }
}
?>

It was all nice and simple until I received my first 2 comments and noticed something strange:
Wordpress assigned the comments to a different post than the one they were meant for.
If it was a single comment I might have suspected that the commentator made a mistake, but since there were 2 of them, I figured there is something fishy here.

After doing some digging in my WordPress Test Enviroment I found the source for the error: the code loops through posts (lines 15-18), and therefore the main WordPress post object no longer contains the same parameters it contained before this loop.
To explain it without going into programming details – after that loop ends, WordPress will have forgotten what the original post was (the post that we wanted to find related posts for).

Don't Forget wp-reset-query in WordPress Hacks

So the last post in the related posts list is the post that WordPress relates to as the current post (instead of the original).
This is why, each time someone tried to add a comment to post A, WordPress thought they commented on post E (when E is the last post in the related posts list).

To fix this problem I needed to restore the original post object by simply adding a call to the wp-reset-query function after the loop (line 20).
After the change the code should look like this:

<?php
//for use in the loop, list 5 post titles related to first tag on current post
$tags = wp_get_post_tags($post->ID);
if ($tags) {
  echo 'Related Posts';
  $first_tag = $tags[0]->term_id;
  $args=array(
    'tag__in' => array($first_tag),
    'post__not_in' => array($post->ID),
    'showposts'=>5,
    'caller_get_posts'=>1
   );
  $my_query = new WP_Query($args);
  if( $my_query->have_posts() ) {
    while ($my_query->have_posts()) : $my_query->the_post(); ?>
      <p><a href="<?php the_permalink() ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>"><?php the_title(); ?></a></p>
      <?php
    endwhile;
  }
}wp_reset_query();
?>

That was only an example of what can happen when forgetting to reset a query inside the loop.
In fact, most of the WordPress hacks loop through posts and you must make sure they end with the wp-reset-query() function call, otherwise strange things might happen..

Topics:   |