Wednesday 22 December 2010

Drupal: Collapsible blog archive (similar to Wordpress / Blogger) using Views

I was really surprised that after a lot of digging, I could not find any pre-built solution to this seemingly popular problem. Surely all big CMSs should have this functionality. It turns out it's not that hard to build something similar to the Blogger archive block on your own using Views. You can see mine in action at the bottom of the sidebar on this page. It will have the following structure (with collapsible months):
▼ December 2010
   Article 1
   Article 2
   Article 3
► November 2010
► October 2010
1) Create a new View
Give it a name and type=node and create a new block display

2) Fields
Add 2 fields; Node:PostDate (no label, and with custom format "F Y"), Node:Title (no label, and check "link field to it's node")

3) Filters
Add a filter on Node:Type and select the type(s) of nodes you want to include (e.g. Blog). Also add one on Node:Published (and select yes)

4) Sort Criteria
Add one on Node:PostDate and select descending

5) Basic Settings
Click style and select "HTML List", then click settings and group by post date. Now click CSS class and add your own custom class name which we will use later (I used jack-archive-block)

At this point you should save, and click preview. If you have 3 months of blog posts, then you should see 3 Month-Year titles, each with their own list of article links.

6) Block Settings
Admin name: what we will use to select it on the blocks page (I used "Jack Archive")

7) Tweaks
Now go back into the Node:PostDate field and click "hide from display" as we dont want it for every node, only for every group. Also check "re-write output" and enter the following:

 [created]

This will prefix each of the section titles (dates) with a little collapse icon, which we will manipulate later with jQuery. That should be it for coding up your View. So save, and go to the blocks admin page and whack it in your sidebar.

8) Style
Next, we style it. Here's the CSS I used:

div.jack-archive-block h3 {
 cursor: pointer;
 margin: 0;
 font-size: 1em;
 font-weight: normal;
 padding: 6px 0;
}
div.jack-archive-block ul {
 padding: 0 0 0 10px;
 list-style: none;
}
div.jack-archive-block ul li {
 background: none;
 line-height: 130%;
 padding: 3px 0 5px;
}

The first block deals with the dates; it says if you mouse over, it should look like you're hovering over a link. The second and third blocks remove any default list styling you may have, so you dont get any random bullet point graphics.

9) jQuery
Finally, the jQuery that makes the magic happen:

$(document).ready(function()
{ 
 // init: collapse all groups except for the first one
 $(".jack-archive-block ul").each(function(i)
 {
  if (i==0) $(this).siblings("h3").children(".collapse-icon").text("▼");
  else $(this).hide();
 });
 
 // click event: toggle visibility of group clicked (and update icon)
 $(".jack-archive-block h3").click(function()
 {
  var icon = $(this).children(".collapse-icon");
  $(this).siblings("ul").slideToggle(function()
  {
   (icon.text()=="▼") ? icon.text("►") : icon.text("▼");
  });
 });
});

That should be it. You should be able to click the dates, and have the relevant articles appear or disappear as desired, and have the nice little icon change accordingly. The next step would be another tier to the hierarchy, so you can collapse by year, and then by month... but I haven't got that far yet. Suggestions welcome.

REFERENCES
http://drupal.org/node/825052

34 comments:

  1. How do you post JQuery in Drupal? Im new to Drupal.

    ReplyDelete
  2. Add a line like this to the end of your theme's template.php: drupal_add_js('sites/all/scripts/collapsible-archive-block.js','core');

    Be sure to update the path to point to your jQuery file.

    ReplyDelete
  3. Hello,

    If you are drupal expert please help me. your tutorial is fine. I just use it in multi user blog site.

    If someone visit in blog/1, he/she only show archive only blog/1, if go for user blog/2, blog/3, and so on, those will different for particular blog..

    How I can do it??

    ReplyDelete
  4. Excellent! Thank you very much. I found your post from the conversation at http://drupal.org/node/825052#comment-3100228.

    One additional thing you might mention is to set 'Items to display' to Unlimited.

    I'm also seeing an abrupt end to the jQuery slider, where the last 20% or so drops instantly. It's probably a conflict on my site, though.

    http://blogs.atomiclearning.com/

    ReplyDelete
  5. Followup to above: The jumping container problem is outlined here: http://stackoverflow.com/questions/2512011/jquery-slidetoggle-and-unknown-height. It simply took a width declaration on the UL element.

    Thanks again!

    ReplyDelete
  6. Thanks so much! This freakin' rules, dude! Cheers!

    ReplyDelete
  7. This comment has been removed by the author.

    ReplyDelete
  8. Just what I was looking for...NICE WORK!!! Ok, I followed the steps above and got everything to work. My question now, Do you have a follow up to " The next step would be another tier to the hierarchy, so you can collapse by year, and then by month..."

    ReplyDelete
  9. @TimmayTech thanks. I'm afraid I have not had time to develop this any further, and it is very unlikely that I will in the near future. But please post here if you do find a solution.

    ReplyDelete
  10. @Jack, Thanks! If I find anything I diffidently will post.

    ReplyDelete
  11. Maybe i am just stupid but i cant get this to work. I have imputed everything in. However for some reason the styles are not being implemented by views. Idk what the problem is. if someone has any ideas that would be very help full.

    ReplyDelete
  12. I notice you have now got the blog archive block with collapsing year. Is that something you will share?

    ReplyDelete
  13. @dannyboy I'm afraid this is not a drupal site - it's just Blogger, and it has that functionality built in.

    ReplyDelete
  14. Have followed above twice and still grouping by post date not working for me (see below). Strange. Any ideas appreciated.

    June 2011
    • Test Blog Entry 3
    June 2011
    • Test Blog Entry 4
    June 2011
    • Test Blog Entry 5

    ReplyDelete
  15. Rick, you're missing the 2nd half of the first sentence of step 5. "then click settings and group by post date"
    Settings is the gear icon next to HTML list.

    I missed it the first time through too.

    ReplyDelete
  16. Thanks so much for this. It worked great and I learned something about adding jQuery magic to Views.

    One hint that might help beginners: After you change the template.php file, be sure to clear your cache or you won't see that change.

    ReplyDelete
  17. Hello, im still stuck at number 9.
    where to put the jQuery script.
    as i read at the second comment, i still dont know where.

    ReplyDelete
  18. Hi there, now i understand the number 9.

    1st create new file and name it as
    collapsible-archive-block.js (or anything)

    copy the script and paste into that file.

    now put the file into your drupal directory, and add this line into the end of your theme's template.php:

    drupal_add_js('sites/all/scripts/collapsible-archive-block.js','core');

    change the path acording to your newly created js file.

    ReplyDelete
  19. ok 2nd question.. how can i put a number of article in that month like this.

    ▼ December 2010 (3)
    Article 1
    Article 2
    Article 3
    ► November 2010 (10)
    ► October 2010 (8)

    ReplyDelete
  20. Hello,
    Im stuck at point 7. I did copy the text but now I see this error message : Display "Block" uses fields but there are none defined for it or all are excluded.

    What did I do wrong on Drupal 7 with Views3.

    Roelof

    ReplyDelete
  21. This is great. Thanks!

    except this line gives me issues:
    (icon.text()=="▼") ? icon.text("►") : icon.text("▼"); 

    The down arrow is not recognized and that line fails.
    You didnt have to escape it or use special html entity codes? (on that note I couldnt find entity codes for ▼ and ► )

    ReplyDelete
  22. Hi Jack,

    Thanks for nice tutorial.I am using drupal 6.24 and I need to create an archive block like your Blog Archive block :
    > 2008
       > january
       > fabruary
       ...
    >2009
       > january
       ...

    Can I create it using this tutorial ?

    Thanks in advance.

    ReplyDelete
  23. Had the same problem as Rick above using a custom date field instead of the Posted Date in the tutorial. The solution was to disable the RDF module:
    http://groups.drupal.org/node/40356#comment-625459 
    http://drupal.org/node/1253562#comment-4886998 

    ReplyDelete
  24. AMAZING. Finally, someone made this happen. Thank you so very much. Bingo. Worked in D6.

    ReplyDelete
  25. Brilliant. Used this plus a few alterations and this was good on Drupal 7.

    ReplyDelete
  26. It works on my site! thanks for sharing this!

    ReplyDelete
  27. Hi Jack can I share this article on my site and refer to your site, I need this for documentation. Thanks

    ReplyDelete
  28. try this: (icon.text()=="\u25BC") ? icon.text("\u25BA") : icon.text("\u25BC"); if you add "\u" to "25BC" it's the down arrow and if you change the "C" in that code to an "A" its the right arrow.

    ReplyDelete
  29. where you put the h3? i am trying to change the background and i cand find the class for this

    ReplyDelete
  30. Thank you very much for this article, Mr. O'Connor. I've found it useful twice now, and I've written a version for Drupal 7 based on your work. It can be found here for those who are interested: http://tinyurl.com/drupal7-archive

    ReplyDelete
  31. Step #9. I had a few issues with this but I found a work around.

    1.theme's .info
    - copy ;scripts[] = js/script.js from the add JS section

    - paste right below the js/script.js file then remove the ;(semi-colon)

    - replace js/script.js with where you JS file is located (ex. js/archive.js

    Should look like this:


    ;scripts[] = js/script.js
    scripts[] = js/archive.js

    2.Go into your js file then copy and paste this over your current code.

    /**
    * @file
    * A JavaScript file for the theme.
    *
    * In order for this JavaScript to be loaded on pages, see the instructions in
    * the README.txt next to this file.
    */

    // JavaScript should be made compatible with libraries other than jQuery by
    // wrapping it with an "anonymous closure". See:
    // - http://drupal.org/node/1446420
    // - http://www.adequatelygood.com/2010/3/JavaScript-Module-Pattern-In-Depth
    (function ($, Drupal, window, document, undefined) {

    Drupal.behaviors.jenny = {
    attach: function(context, settings) {

    jQuery(document).ready(function($) {
    // init: collapse all groups except for the first one
    $("div.collapsible-archive ul").each(function(i) {
    if (i==0) {
    $(this).siblings("h3").children(".collapse-icon").text("▼");
    } else {
    $(this).hide();
    }
    });

    // click event: toggle visibility of group clicked (and update icon)
    $("div.collapsible-archive h3").click(function() {

    var icon = $(this).children(".collapse-icon");

    $(this).siblings("ul").slideToggle(function() {
    (icon.text()=="▼") ? icon.text("►") : icon.text("▼");
    });
    });
    });

    }
    };

    })(jQuery, Drupal, this, this.document);

    3. Find and replace

    .jenny (which is your theme's name) and put in your own theme name

    div.collapsible-archive ul (replace with whatever your div is named.

    div.collapsible-archive h3 (replace with your div name)

    4.save, clear cache, and refresh browser. Hopefully that works.

    ReplyDelete
  32. but where is arguments?

    ReplyDelete
  33. I want to display only post title , I dont want to display month and year. I need Just a flat list without any year and month a flat list should contain all the post tittles. How to do that?

    ReplyDelete
  34. Thank you very much for the tutorial, it helped me save precious time!

    ReplyDelete