One part of WordPress that I’ve never been overly impressed with is archives. This isn’t so much a WordPress problem as it an archive problem, archives are inherently boring. As a result of this revelation I’ve spent some time thinking up new ways to present the information. My latest idea was adding charts to represent some of the data from the archives. This is a fairly simple function to output the info and style it as a chart.

If you want to use a flash or javascript chart, scroll to the bottom for a different function.

chart

The Chart

After looking for a lightweight flash or javascript charting solution, I decided for an archives page just plain CSS charts would be the way to go at first. So the output we are going for is something like this:

<dl class="barGraph 2008">
	<dt style="" class="label"><a href="">Jun</a></dt>
	<dd title="Jun" style="height: 200px;" class="bar Jun">6</dd>

	<dt style="left: 55px;" class="label"><a href="">Jul</a></dt>
	<dd title="Jul" style="height: 66.6667px; left: 55px;" class="bar Jul">2</dd>

	<dt style="left: 110px;" class="label"><a href="">Aug</a></dt>
	<dd title="Aug" style="height: 100px; left: 110px;" class="bar Aug">3</dd>

	<dt style="left: 165px;" class="label"><a href="">Sep</a></dt>
	<dd title="Sep" style="height: 133.333px; left: 165px;" class="bar Sep">4</dd>

	<dt style="left: 220px;" class="label"><a href="">Oct</a></dt>
	<dd title="Oct" style="height: 166.667px; left: 220px;" class="bar Oct">5</dd>

	<dt style="left: 275px;" class="label"><a href="">Nov</a></dt>
	<dd title="Nov" style="height: 100px; left: 275px;" class="bar Nov">3</dd>

	<dt style="left: 330px;" class="label"><a href="">Dec</a></dt>
	<dd title="Dec" style="height: 66.6667px; left: 330px;" class="bar Dec">2</dd>
</dl>

The Code

The code in the function is essentially a Frankenstein of the wp_get_archives function from the WordPress core, and this tutorial on creating vertical bar graphs. It pulls the year, month and number of posts out of the database, then formats them into a list suitable for styling into a CSS chart.

<?php
function ch_archive_graph($args = ''){
	global $wpdb, $wp_locale;

	//template tag defaults
	$defaults = array(
		'graphYear' => '2007',
		'limit' => '13',
		'graphHeight' => '200',
		'xIncrement' => '55'
	);

	$maxHeight = 1;
	$scale = 1;

	$r = wp_parse_args( $args, $defaults );
	extract( $r, EXTR_SKIP );

	if ( '' != $limit ) {
		$limit = absint($limit + 1);
		$limit = ' LIMIT '.$limit;
	}

	$where = apply_filters('getarchives_where', "WHERE post_type = 'post' AND post_status = 'publish'", $r );

	$query = "SELECT YEAR(post_date) AS `year`, MONTH(post_date) AS `month`, count(ID) as posts FROM $wpdb->posts $where GROUP BY YEAR(post_date), MONTH(post_date) ORDER BY post_date DESC $limit";
	$key = md5($query);
	$cache = wp_cache_get( 'ch_archive_graph' , 'general');

	$output = '<dl class="barGraph '.$graphYear.'">';

	if ( !isset( $cache[ $key ] ) ) {
		$arcresults = $wpdb->get_results($query);
		$cache[ $key ] = $arcresults;
		wp_cache_add( 'ch_archive_graph', $cache, 'general' );
	} else {
		$arcresults = $cache[ $key ];
	}
	if ( $arcresults ) {

		//Loop through to find the highest number of posts
		foreach ( (array) $arcresults as $arcresult ) {
			//number of posts in a month
			$total = $arcresult->posts;
			if($maxHeight < $total) $maxHeight = $total;
		}

		//Reverse the months
		$arcresults = array_reverse($arcresults);
		foreach ( (array) $arcresults as $arcresult ) {
			//Limit to one year
			if($arcresult->year == $graphYear){
				//Get month name, then appreviate, delete the second line if you want full month names
				$month = sprintf(__('%1$s'), $wp_locale->get_month($arcresult->month));
				$month = sprintf(__('%1$s'), $wp_locale->get_month_abbrev($month));
				//Get archive link
				$url = get_month_link( $arcresult->year, $arcresult->month );
				//Number of posts in the month
				$num_posts = $arcresult->posts;

				//Determine the scale and the height of the bar
				$scale = $graphHeight / $maxHeight;
				$height = ($arcresult->posts * $scale);

				//Put it all together
				$output .= "<dt class='label' style='left: ".$xOffset."px;'><a href=".$url.">".$month."</a></dt>";
				$output .= "<dd class='bar ".$month."' style='height: ".$height."px; left: ".$xOffset."px;' title=".$month.">".$num_posts."</dd>";

				//Increase the offset for the next bar
				$xOffset = $xOffset + $xIncrement;
			}
		}
	}	

	$output .= "</dl>";
	echo $output;

}

Styling the Chart with CSS

Styling the chart is made easier by the definition list.

.barGraph {
	height: 200px;
	margin: 0;
	padding: 0;
	position: relative;
	}

.barGraph dt {
	bottom: 0;
	list-style:none;
	margin: 0;
	padding: 0;
	position: absolute;
	text-align: center;
	width: 54px;
	}

.barGraph dd {
	border: 1px solid #005559;
	bottom: 0;
	list-style:none;
	margin: 0 0 1.5em 0;
	padding: 0;
	position: absolute;
	text-align: center;
	width: 50px;
	background-color: #00868B;
	border-right: 5px solid #005559;
	color: #fff;
	font-weight: bold;
	}

	.barGraph dd:hover {
		border: 1px solid #FA8000;
		background-color: #F5BA52;
		border-right: 5px solid #FA8000;
		color: #000;
		}

How to use the Graph

The function works just like any other template tag. Add the above function to your functions.php file and the CSS to style.css. Then call the chart in your template like so: <?php ch_archive_graph(); ?>

The template tag also includes a few options to make customizing it easier:

  • graphYear‘ this is the year of the archive you want to display
  • xIncrement‘ this is the width of the bars in the chart
  • graphHeight‘ this is the height in pixels of the chart
  • limit‘ this is number of posts you want to display

Example:
<?php ch_archive_graph('graphYear=2007&xIncrement=40&graphHeight=400&limit=6'); ?>

Bonus: For Javascript Charts

If you need the output for a javascript based chart, you only need to alter things a bit to get a javascript array or months and number of posts, then plug them into whatever charting you want to use.

function ch_count_months_js_output($args = ''){
	global $wpdb, $wp_locale;

	$defaults = array(
		'limit' => '',
		'before' => ''
	);

	$r = wp_parse_args( $args, $defaults );
	extract( $r, EXTR_SKIP );


	$where = apply_filters('getarchives_where', "WHERE post_type = 'post' AND post_status = 'publish'", $r );
	$join = apply_filters('getarchives_join', "", $r);

	$query = "SELECT YEAR(post_date) AS `year`, MONTH(post_date) AS `month`, count(ID) as posts FROM $wpdb->posts $join $where GROUP BY YEAR(post_date), MONTH(post_date) ORDER BY post_date DESC $limit";
	$key = md5($query);
	$cache = wp_cache_get( 'ch_count_months_js_output' , 'general');

	if ( !isset( $cache[ $key ] ) ) {
		$arcresults = $wpdb->get_results($query);
		$cache[ $key ] = $arcresults;
		wp_cache_add( 'ch_count_months_js_output', $cache, 'general' );
	} else {
		$arcresults = $cache[ $key ];
	}
	if ( $arcresults ) {
		$arcresults = array_reverse($arcresults);
		$posts = array();
		$months = array();
		foreach ( (array) $arcresults as $arcresult ) {
			$month = sprintf(__('%1$s'), $wp_locale->get_month($arcresult->month));
			array_push($months, $month);
			array_push($posts, $arcresult->posts);
		}
	}	
	print_r($months);
	print_r($posts); 

	echo '<p type="text/javascript">'; 
	echo 'var months = ["', join($months,'","'), '"];'; 
	echo 'var posts = [', join($posts,','), ']';
	echo '</p>';
}

Let me know if you use it or improve it!