Wednesday, October 14, 2009

Related post plugin for blogger


Since I started using blogger, I've always wondered why this feature is not present by default. To me having a list of related post is very important, because that's a nice way to put forward more relevant content to you dear reader ;)

So i've search on internet, and found a flurry of so called plugin or widget. The most common one seems to have been written by Hoctro. But none of those never really satisfied me.

As a result I decided to write my own using a bit of Ajax query to make everything smooth and nice. The result is a plugin that display on articles pages (not on the front page for now) a list of post related to the current one. It is relying on the post labels and the google API to display thoses.

And here it is:

<b:if cond='data:blog.pageType == &quot;item&quot;'>

<div class='similiar'>

 <div class='widget-content'>
  <div id='relatedPosts' /> <br/>
  <div expr:id='&quot;relatedPosts_&quot; + data:post.id'/> <br/>

  <script type='text/javascript'>

  var blogURL = &quot;<data:blog.homepageUrl/>&quot;;
  var maxNumberOfLabels = 10;
  var nPost = 0;
  var maxPosts = 5;
  var numLabel = 0;
  var receivedResult = 0;

  var outputDone = false;

  var txt = document.createTextNode(&quot;You may also want to read:&quot;); 
  var ul = document.createElement(&#39;ul&#39;);
  var labelRelatedPost = document.createElement(&#39;h3&#39;);
  labelRelatedPost.appendChild(txt);
  var postsFound = [];

  function listEntries(result, postID) 
  { 

   var json = JSON.parse(result);

   receivedResult = receivedResult+1;

   // calculate the number of remaining post to add to the list
   var RemainingPosts = (maxPosts - nPost);
   var nPostToParse = (json.feed.entry.length &lt;= RemainingPosts) ? json.feed.entry.length : RemainingPosts;

   for (var i = 0; i &lt; RemainingPosts; i++) {
    var entry = json.feed.entry[i];
    if(entry)
    { 
     var postURL;
     var title = entry.title.$t

     // parse the link array to find the post URL
     for (var k = 0; k &lt; entry.link.length; k++) {
      if (entry.link[k].rel == &#39;alternate&#39;) {
       postURL = entry.link[k].href;
       break;
      }
     }

     // check the post is not the same as the current post
     if (postURL != location.href) 
     {
      if (postAlreadyKnown(postURL) == false)
      {
       nPost++;

       //alert("Other post found "+nPost);
       var li = document.createElement(&#39;li&#39;);
       var a = document.createElement(&#39;a&#39;);
       var txt = document.createTextNode(entry.title.$t);
       a.href = postURL; 
       a.appendChild(txt);
       li.appendChild(a);
       ul.appendChild(li);   
      }


     }
    }

   }

   // check if everything's been received
   if (receivedResult == numLabel ) {
    if (outputDone == false &amp;&amp; nPost &gt; 0) 
    {
     outputDone = true;
     var relatedPostSection =  'relatedPosts_'+postID;
     var relatedDiv = document.getElementById('relatedPosts_'+postID);
     if (relatedDiv) {
      relatedDiv.appendChild(labelRelatedPost);
      relatedDiv.appendChild(ul);
      
      //
      var providedBy = document.createElement(&#39;h5&#39;);
      var em = document.createElement(&#39;em&#39;);
      var a = document.createElement(&#39;a&#39;);
      a.href = "http://xiuxixiuxi.blogspot.com/2009/10/related-post-plugin-for-blogger.html"
      var txt = document.createTextNode("Provided by XiuxiXiuxi");
      a.appendChild(txt);
      em.appendChild(a);
      providedBy.appendChild(em);
      relatedDiv.appendChild(providedBy);
     }
    }
   }

  }

  function postAlreadyKnown(postURL) {
   for(var i= 0; i &lt; postsFound.length;i++)
   {
    if(postsFound[i] == postURL) 
    {
     return true;
    }
   }
   postsFound[postsFound.length] = postURL;
   return false;
  }

  function searchQuery(query, label) {

   var script = document.createElement(&#39;script&#39;);


   var xhr = new XMLHttpRequest();
   xhr.onreadystatechange = function() {

    if (xhr.readyState == 4) {
     // Your callback code goes here
     listEntries(xhr.responseText, &quot;<data:post.id/>&quot;);
    }
   }
   xhr.open(&#39;GET&#39;, query+ &#39;feeds/posts/default/-/&#39; + label + &#39;?alt=json&#39; , true);
   xhr.send(null);
  }



  <b:if cond='data:post.labels'>
  <data:postLabelsLabel/>
  <b:loop values='data:post.labels' var='label'>
  var textLabel = &quot;<data:label.name/>&quot;
  //alert(textLabel);
  if (numLabel &lt; maxNumberOfLabels) {
   searchQuery(blogURL, textLabel);
   numLabel++;
  }
  </b:loop>
  </b:if>
  </script>
 </div>
</div>
</b:if>

Now where to put that code. You need to edit your blog layout.To do that, go to your blogger dashboard and click on "Layout", click on "Edit HTML", and click on "Expand Widget Templates". Now search for:

<data:post.body> 

and paste the code above just after that.

And your done.