skip to main | skip to sidebar

Blogger Data APIOn this post I gonna walk you through the code behind my new widget [A Smarter Related Posts widget for Blogger].

If you just want to install the widget on your blog, go to A Smarter Related Posts widget for Blogger.

To see the widget in action, Scroll down to the end of this post. also hover on links to see relevancy score.

Google Data APIs provide a simple standard protocol for reading Blogger content in the form of feeds. and jQuery makes it very easy to work with.
These REST-style APIs are based on the Atom Publishing Protocol (AtomPub), using the standard Atom syndication format to represent data and HTTP to handle communication. The Google Data API protocol also extends AtomPub for processing queries, authentication, batch requests, and providing alternate output formats (JSON, RSS).
Many Google services support the Google Data API protocol. This time I will work with the Blogger Data API to aggregate blog feeds in JSON format. And will also use jQuery to handle JSON feeds of each related tag to build the related posts widget.

First go to Project page to download the JavaScript file.

Now, I'll describe how that widget works in order of execution (which looks like the reverse order of functions definitions)

1- you call the class and pass your options, Class constructor sets default options and use jQuery extend method to overwrite it with user preferences.
var op = { ...
   'blogURL':''
};
op = $.extend({}, op, userOp);


2- Check if user didn't specify a container selector then it create placeholder div by document.write to place it where script was called
if (!op.containerSelector) {
   document.write('<div id="related-posts" />');
   op.containerSelector = '#related-posts';
}


3- Attach initialization function to on window-load event or on document-ready
if(op.onLoad) $(window).load(initRelatedPosts);
else $(document).ready(initRelatedPosts);


4- 'initRelatedPosts' is called on window-load or on document-ready and checks if user specified a container selector to append placeholder div to it.
if(op.containerSelector != '#related-posts'){
   var container = $(op.containerSelector);
   if (container.length!=1) return;
   div = $('<div id="related-posts"/>').appendTo(container);
}


5- Find tags anchors in the body of current post if it wasn't preset by user. by selecting all links with attribute rel='tag'.
op.tags = [];
$('a[rel="tag"]:lt('+op.maxTags+')').each(function () {
   var tag= $.trim($(this).text().replace(/\n/g,''));
   if($.inArray(tag,op.tags)==-1) op.tags[op.tags.length]=tag;
})


6- Append Recent Posts title or Related Posts title in H2 element.
7- Appned Loading text if any.
8- Append ul with CSS class of loading if user provided one.
9- Get JSON feeds for recent posts
$.ajax({url:op.blogURL+'/feeds/posts/summary/'
   ,data:{'max-results':op.maxPostsPerTag,'alt':'json-in-script'}
   ,success:tagLoaded
   ,dataType:'jsonp'
   ,cache:true })


10- Or get JSON feeds for each tag. you can notice that it calls the summary feeds cause we don't need waste bandwidth on getting full feeds since all is needed is post title and URL.
Query string contains variables like: Category=Tag, max-results=maxPostsPerTag. for more info on available parameters check protocol reference.
for(var t=0; t<op.tags.length;t++)
   $.ajax({url:op.blogURL+'/feeds/posts/summary/'
   ,data:{'category':op.tags[t],'max-results':op.maxPostsPerTag,'alt':'json-in-script'}
   ,success:tagLoaded
   ,dataType:'jsonp'
   ,cache:true })

After reading the reference you may ask yourself; we could pass all tags with 'or' and return all related posts one shot. But Blogger doesn't support this yet ): although it is in the API protocol reference! So I have to aggregate each tag feed and calculate score of each post based on number of common tags.

11- 'tagLoaded' function is called on load of every JSON feed. Then it loops entries to add links to the list by calling addPost function.
for (var i=0; i<json.feed.entry.length; i++) {
   var entry = json.feed.entry[i];
   var url='';
   for (var k=0; k<entry.link.length; k++) {
      if(entry.link[k].rel=='alternate') {
         url = entry.link[k].href;
         break;
      }
   }
   var title = entry.title.$t;
   if(location.href.toLowerCase()!= url.toLowerCase()) addPost(url,title);
}

and when all tags are loaded it remove loading text and loading class on ul.

12- 'addPost' function loops links list to find if link doesn't exist to add it. otherwise if link was found in some position:
- first increments link's score; Score is saved in an arbitrary attribute 'score' on each link.
- Loop links above it and compare their scores. so if the above links have lower score then current link is inserted before them.
var list = $('li',ul);
for(var i=0; i<list.length; i++) {
   var a= $('a', list.eq(i) );
   var sc = getScore(a);
   //Post exists ?
   if(a.attr('href')==url) {
      //Yes : Then increment score
      setScore(a,++sc);
      //Re-order : compare with prevoius li items
      for(var j=i-1; j>=0; j--){
         // find the item with higher score than current
         var jA= $('a', list.eq(j) );
         if (getScore(jA)>sc) {
            // re-order if only there are items in the middle to appear before
            if(i-j>1) list.eq(j).after(list.eq(i));
            return;
         }
      };
      // If no higher item then this one should go first
      if(i>0) list.eq(0).before(list.eq(i));
      return;
   }
}
//Add new post
ul.append('<li><a href="'+url+'" title="'+(op.relevantTip? op.relevantTip.replace('\d',1):'')+'">'+title+'</a></li>');


13- getScore function is used to get score from the arbitrary attribute 'score' on a link.
14- setScore function is used to set score on a link. also sets relevancy tip if required, for example '5 relevant tags!'.
And set link class based on relevancy if required to, for example 'related-post5'.

that's it. Hope that article was helpful for you on working with jQuery manipulation and aggregation of Blogger JSON feeds.

9 comments

  1. Swashata // July 24, 2009 at 1:30:00 AM GMT+10  

    Very useful! A must read tutorial for newbie programmers like me :)
    Thanks a lot for putting this in form of such a simple yet informative tutorial! Hats off to your hard work :)
    Thanks again Mike!

  2. Mike // July 24, 2009 at 9:47:00 AM GMT+10  

    @Swashata,
    You're most welcome

  3. Swashata // August 4, 2009 at 2:46:00 PM GMT+10  

    Hi Mike, I have a question out here! Like if we use this type of query http://www.intechgrity.com/feeds/posts/default/?category=Featured,News&max-results=2 then it returns posts having both the tags Featured AND News. Is there any way to call News OR Featured through the API??

  4. Mike // August 5, 2009 at 10:21:00 AM GMT+10  

    API says yes.. by setting [Category=Featured|News]
    But running that will return "Disjunctions not supported yet". A.K.A: "We 'Blogger Team' don't care about that yet!" :)
    So, I had to make a request per category and calculate top relevant posts..
    Which had led me to Use Google Blog Bar as related Posts widget cause then it can be done with one request, also it is not limited to Blogger blogs!

  5. Swashata // August 5, 2009 at 2:54:00 PM GMT+10  

    Ohk! So that was the reason! And one more thing! If we have no selector specified then the code writes on the document <div id="related-post"/> But when it do so, on the first step the html get messed! May because we can not self-close div tags! even after appending ul and li onto it, the page continues to look messy! I tried this on my blog and this caused my sidebar to come inside that div! Also writing <div id="related-post"> </div> solves the issue!

    Also can you tell me, while using jQuery selector, what is returned if the element was not found! like we search for an element var search = $('#myId') what is the value of the search returned when it was found and was not found :)

  6. Mike // August 6, 2009 at 10:34:00 AM GMT+10  

    @Swashata,
    Thanks for the note about self-close a div. which shouldn't be done on a tag that permits content. will fix it..

    Selector will return a jQuery object with .length=0 if no match!

  7. Dofollow Cool // December 16, 2009 at 9:05:00 AM GMT+11  

    Great widget, just what I was looking for. If you are not great at programming, how do you change the options? The options given in a table above? I found that in my blog http://dofollowcool.blogspot.com sometimes the widget does not show sufficient related links. I'd like at least 4-5 everytime. Thanks!

  8. Mike // December 16, 2009 at 12:03:00 PM GMT+11  

    @Dofollow Cool,
    You need to go to widget page Related Posts widget for Blogger, this post is for geeks :)

    About insufficient links, may be because your are using many tags on your blog with 1-3 posts each. you may narrow it down a little! or in this case increase 'maxPostsPerTag' option to be more than 5(default).

    If things are not clear yet, email me for more help..

  9. Samsul // March 31, 2010 at 10:44:00 AM GMT+11  

    Thanks, Mike. I'm using it and now I know how it's done behind the scene.

Post a Comment

Thank you for taking the time to comment..
* If you have a tech issue with one of my plugins, you may email me on mike[at]moretechtips.net

Mike

Mike MoreWeb developer, jQuery plugin author, social media fan and Technology Blogger.
My favorite topics are: jQuery , Javascript , ASP.Net , Twitter , Google..
<connect with="me"> </connect>

Subscribe by email

Enter your email address:

or via RSS