How to Build the Perfect WordPress Sitemap

I was recently asked how I built the sitemap on Binary Moon so I thought I would share the code. The sitemap layout is actually one of the many custom page templates available in my WordPress theme, Elemental – however the code is very loosly based upon that in the original SRG Clean Archives plugin (before it was taken over by Geek With a Laptop).

Perfect WordPress Sitemap

Sitemaps are a single page that allows you to view every single post on a site. Perfect for Google to spider all of your content, and for users to quickly find old posts that they are looking for.

When making the sitemap I wanted to list all of the posts, and also to link to the monthly archives for each post – that way I would get maximum exposure for my sitemap – and it has a page rank of 6 (at the time of writing) so I must be doing something right.

The process is relatively simple:

  1. Grab all the months and years from the database
  2. Loop through the list of dates and grab the posts from each month, displaying them as you go

Easy right? The code, that you would add to your functions.php – would look something like the function below:

function bm_displayArchives() {
	global $month, $wpdb, $wp_version;

	// a mysql query to get the list of distinct years and months that posts have been created
	$sql = 'SELECT
			DISTINCT YEAR(post_date) AS year,
			MONTH(post_date) AS month,
			count(ID) as posts
		FROM ' . $wpdb->posts . '
		WHERE post_status="publish"
			AND post_type="post"
			AND post_password=""
		GROUP BY YEAR(post_date),
		ORDER BY post_date DESC';

	// use get_results to do a query directly on the database
	$archiveSummary = $wpdb->get_results($sql);

	// if there are any posts
	if ($archiveSummary) {
		// loop through the posts
		foreach ($archiveSummary as $date) {
			// reset the query variable
			unset ($bmWp);
			// create a new query variable for the current month and year combination
			$bmWp = new WP_Query('year=' . $date->year . '&monthnum=' . zeroise($date->month, 2) . '&posts_per_page=-1');

			// if there are any posts for that month display them
			if ($bmWp->have_posts()) {
				// display the archives heading
				$url = get_month_link($date->year, $date->month);
				$text = $month[zeroise($date->month, 2)] . ' ' . $date->year;

				echo get_archives_link($url, $text, '', '<h3>', '</h3>');
				echo '<ul class="postspermonth">';

				// display an unordered list of posts for the current month
				while ($bmWp->have_posts()) {
					echo '<li><a href="' . get_permalink($bmWp->post) . '" title="' . wp_specialchars($text, 1) . '">' . wptexturize($bmWp->post->post_title) . '</a></li>';

				echo '</ul>';

Note that I am using the wp_query object (as detailed in my post “10 query_posts tips you probably don’t know“) throughout this example to stop the main query_posts instance from being ruined

To use the function above you would then need to create a custom page template (as detailed in the custom page template tutorial here). You can then call the function from within the new template.

Was it good/ useful/ a load of old rubbish? Let me know on Mastodon, or BlueSky (or Twitter X if you must).

Link to this page

Thanks for reading. I'd really appreciate it if you'd link to this page if you mention it in your newsletter or on your blog.

WordPress News

The latest WordPress updates from the WPBriefs Podcast.

Related Posts

30 Jun 2007

WordPress tips and tricks – Custom Page Templates

Some time ago I posted the first of my tips and tricks for WordPress, and I thought it was about time I posted some more so, to start things off, here is a short tutorial on custom page templates in...
30 Mar 2010

10 WordPress query_posts tips you probably don’t know

I have written a really brief query_post tutorial before, and it did quite well, but both WordPress and my own skills, have advanced considerably since then. So I thought it would be interesting to revisit the query_posts command and see...
28 May 2010

WordPress caching, Part 2

As I mentioned in WordPress caching part 1, WordPress has built-in caching that can be hooked into by plugins such as W3 Total Cache and Batcache (developed by Andy Skelton who is employed by Automattic).In this article I am going...
27 May 2013

WordPress: 10 Years Young, What Does The Future Hold?

WordPress is now 10 years old. I started using wordpress 9 years ago – which means I joined the WordPress community early on. The reason I chose WordPress is simply because of the fabled 5 minute install process – I...