Each time I redesign my blog, I try to implement some cool, visually interesting feature. This time around, I decided to build a widget to display post archives, styled to look like a vertical bar chart:

Making this widget turned out to be a bit tricky, but fun. In this post, I’ll describe how to do it.

1. Lay Out the Widget

We’ll start with the HTML. I chose to use two lists: one for the boxes and one for the labels. I should note that this is not the most semantically accurate way of doing it (because the two lists contain essentially the same information). That said, I found it easier to style than the alternative.

Here’s the HTML:

<aside class="archives">
   <h3>archives</h3>
   <ul class="archive-boxes">
      <li class="archive-item-container"><a class="archive-box width-5" href="...">5</a></li>
      ....
      <li class="archive-item-container archive-no-box"></li>
   </ul>
   <ul class="archive-labels">
      <li class="archive-item-container"><a class="archive-month-label" href="...">Nov</a></li>
      ...
      <li class="archive-item-container archive-year-label">2012</li>
   </ul>
   </aside>

Each month/year is represented by a list item, which contains a link to show the box (archive-box) or the label (archive-month-label).

2. Style the Widget

Now that we have our layout, let’s style the widget. It’ll be helpful to define some variables to use in our styles:

$increment: 0.2;
$box-height: 30px;
$base-color: #d5d0cc;
$archive-separator-color: darken($base-color, 40%);
$pad-unit: 1em;

There are also a couple of generic styles to create, one for the archive container and one for individual li elements:

.archives {
float: right;
max-width: 100px;
margin-top: $pad-unit * -0.5;
}

.archive-item-container {
margin-bottom: 0;
height: $box-height + 2;
}

A couple of things to note:

Styling the Boxes

To make this widget look like a bar chart, we need to vary the width of each box depending on how many posts there are. We can define the width using the following formula where x is the number of posts:

width(x) = base-value * (1 + increment * x)

Using this formula, I created 12 classes: 11 to display months with 0 to 10 posts (width-*) and 1 to display months which exceed 10 posts (width--). I chose to cap it at 10 because I rarely exceed 10 posts in a given month. If you need more than that, feel free to define more classes.

.archive-boxes {
border-right: 2px solid $archive-separator-color;
padding-right: $pad-unit * 0.3;
float: left;

.width-0 { width: 0; }
.width-1 { width: $pad-unit; }
.width-2 { width: $pad-unit * (1 + $increment * 1); }
.width-3 { width: $pad-unit * (1 + $increment * 2); }
.width-4 { width: $pad-unit * (1 + $increment * 3); }
.width-5 { width: $pad-unit * (1 + $increment * 4); }
.width-6 { width: $pad-unit * (1 + $increment * 5); }
.width-7 { width: $pad-unit * (1 + $increment * 6); }
.width-8 { width: $pad-unit * (1 + $increment * 7); }
.width-9 { width: $pad-unit * (1 + $increment * 8); }
.width-10 { width: $pad-unit * (1 + $increment * 9); }
.width--- {
width: $pad-unit * (1 + $increment * 10);
border-left: 1px dashed darken($base-color, 10%) !important;
}
}

With widths taken care of, let’s focus on creating the key class of this widget, archive-box (as well as its boring sibling archive-no-box):

.archive-box {
background-color: darken($base-color, 5%);
border: 1px solid darken($base-color, 10%);
height: $box-height;
margin-right: $pad-unit/2;
float: right;
clear: both;
text-align: left;
font-size: $base-font-size * 0.7;
padding-left: $pad-unit/2;
color: darken($base-color, 40%);

&amp;:hover {
text-decoration: none;
background-color: darken($base-color, 15%);
border: 1px solid darken($base-color, 20%);
}
}

.archive-no-box {
float: right;
clear: both;
}

To make it look like a box, we need to set the height, border and background-color, as well as add some padding / margin. To ensure that the boxes sit flush against the right border, we need to float them right.

Styling the Labels

Styling the list of labels is significantly more straight forward:

.archive-labels {
float: right;
a {
font-size: $base-font-size * 0.8;
color: darken($primary-color, 20%);
}
}

.archive-month-label {
margin-bottom: 0;
}

.archive-year-label {
font-weight: 600;

&amp;:before {
content: "___";
margin-left: $pad-unit * -1.6;
margin-top: $pad-unit * -0.5;
float: left;
color: $archive-separator-color;
}
}

Probably the only notable thing here is that I’m using a :before selector to draw a tick mark in front of the year label.

3. Get The Archives

The last piece of the puzzle is a bit of php code to make the widget work. I should point out that WordPress already has a built-in way to get the archives via wp_get_archives(). Unfortunately, this function isn’t flexible enough for our purposes, so we’ll need to get the data directly from the database:

<php
get_header();

global $wpdb;

$query = "SELECT YEAR(post_date) AS 'year', MONTH(post_date) AS 'month', COUNT(ID) as post_count"
    ."FROM $wpdb->posts :
    ."WHERE post_type = 'post' AND post_status = 'publish' "
    ."GROUP BY month, year "
    ."ORDER BY post_date DESC"

$months = $wpdb->get_results($query);

This query returns a $months collection which contains a count of posts by month/year. Using this collection, we can build up the HTML we need:

$link = "";
$month_abbr = "";
$archive_boxes = "";
$archive_labels = "";

foreach($months as $month) {
    $link = get_month_link( $month->year, $month->month );
    $month_abbr = date('M', mktime(0,0,0,$month->month, 1, $month->year));
    $count_class_suffix = ($month->post_count > 10 ? '--' : $month->post_count);

    $archive_boxes .= "<li class=\"archive-item-container\"><a class=\"archive-box width-$count_class_suffix\" href=\"$link\">$month->post_count</a></li>";
    $archive_labels .= "<li class=\"archive-item-container\"><a class=\"archive-month-label\" href=\"$link\">$month_abbr</a></li>";

    // add row for year
    if ($month->month == 1) {
        $archive_boxes .='<li class="archive-item-container archive-no-box"></li>';
        $archive_labels .= "<li class=\"archive-item-container archive-year-label\">$month->year</li>";
    }
}

Finally, we can finally insert the archive widget in our page:

<aside class="archives">
   <h3>archives</h3>
   <ul class="archive-boxes no-bullets">
      <?php print $archive_boxes ?>
   </ul>
   <ul class="archive-labels no-bullets">
      <?php print $archive_labels ?>
   </ul>
</aside>

You may also like:

Did you love / hate / were unmoved by this post?
Then show your support / disgust / indifference by following me on Twitter!

Comments are closed.