How To Add a Dynamic HTML Sitemap in WordPress Without a Plugin

WordPress HTML sitemap.In this tutorial, I will show you how to dynamically display an HTML sitemap for your WordPress blog without the need of a plugin. Dynamically means that the sitemap updates automatically with every new post and other blog changes. Yes, there are plugins that add an HTML sitemap to your blog. But I encourage you to read my previous post about unnecessarily adding plugins to your theme. Also in many cases, you add specific things to your sitemap that are not supported in a plugin. You really don´t need a plugin for such a simple task.

What is an HTML sitemap?

An HTML sitemap provides a mechanism to display the blog´s structure, the list of posts and pages, and other sections, so that users will get a quick overview of the content. An HTML sitemap primarily focus on helping your users easily navigate your blog.

Some WordPress themes natively support a sitemap template file. In this case, you if your WordPress theme already has a built-in sitemap page template, then all you have to do is create a new page in your WordPress dashboard, choose the sitemap page template, and then click Publish. And you´re done!

Why should you Use a sitemap Page?

Most bloggers don´t have a sitemap page and this is a mistake. An HTML sitemap is designed for your visitors.

An HTML sitemap acts as a directory that helps your users find their way around. It shows all your pages, posts, archives, categories and authors in one convenient location.

An HTML sitemap improves the navigation of your blog, where visitors can quickly find a specific post and get a quick overview about the blog´s content.

An HTML sitemap not only help your visitors find more information but also keep them on your blog longer.

An HTML sitemap is user-friendly, enhances the user experience and Web usability.

Demo of the HTML sitemap for this Blog | Final Result

To see how the sitemap page looks like, after implementing the code below, check out the HTML sitemap of this blog.

Features of My “HTML sitemap” Code

The code has the following features:

  1. Displays the list of Authors with the number of posts per author. An author with no posts will not be listed.
  2. Displays the list of Pages. You have the option to exclude pages as you wish.
  3. Displays the list of Posts. Posts, along with the post date and number of comments per post, are listed under their respective categories.
  4. Displays a post once, even if it listed in multiple categories (or subcategories).
  5. You have the option to Exclude categories (or subcategories).
  6. An empty category will not be listed.
  7. Displays the list of Monthly Archives.
  8. The code is tested to work properly with all major browsers.
  9. The code is tested to work properly with WordPress Version 3.2.1 but it will work with earlier versions.
  10. The code is XHTML valid.
  11. The code is dynamic, the sitemap page automatically updates with any new changes to the blog.
  12. However; the code does NOT support Custom Post types. This feature will be added in a later tutorial: Add Sitemap For Custom Post Types in WordPress.

Dynamic HTML sitemap Code | How To Create your sitemap Page

Here are the 5 steps required to create a dynamic HTML sitemap for your WordPress blog:

Step 1. Locate to your WordPress theme folder and make a copy of the page.php file, rename the new file to page-sitemap.php

Step 2. Open page-sitemap.php with your preferred editor or in the WordPress dashboard.

Step 3. Add the following code (CODE-1) to the top of page-sitemap.php file:

CODE-1:

<?php
/*
Template Name: HTML Sitemap Page
*/
?>

Step 4. Replace the_content(); tag and the code around it as necessary with the following code (CODE-2):

CODE-2:

<!-- 
/***************************************************************************
* @Author: Boutros AbiChedid 
* @Date:   October 30, 2011
* @Websites: http://bacsoftwareconsulting.com/ ; http://blueoliveonline.com/
* @Description: Code that dynamicaly generates an HTML sitemap for your Blog.
* @Tested on: WordPress version 3.2.1 (but it works on earlier versions.)
****************************************************************************/ 
-->
<div class="html-sitemap">
    <h2>Author(s):</h2>
    <ul class="sitemap-authors">
    <?php 
       //http://codex.wordpress.org/Function_Reference/wp_list_authors
       wp_list_authors('exclude_admin=1&optioncount=1');
    ?>
    </ul>
        
    <h2>Pages:</h2>
    <ul class="sitemap-pages">
    <?php
      //http://codex.wordpress.org/Function_Reference/wp_list_pages
      wp_list_pages('exclude=889&title_li='); //***Exclude page Id, separated by comma. I excluded the sitemap of this blog (page_ID=889).
    ?>
    </ul> 
     
    <h2>Posts:</h2>
    <ul>
    <?php
    //http://codex.wordpress.org/Function_Reference/get_categories
	$cats = get_categories('exclude='); //***Exclude categories by ID, separated by comma if you like.
    
	foreach ($cats as $cat) {
      echo '<li class="category">'."\n".'<h3><span class="grey">Category: </span>'.$cat->cat_name.'</h3>'."\n";
      echo '<ul class="cat-posts">'."\n";
      
      //http://codex.wordpress.org/Function_Reference/query_posts
	  query_posts('posts_per_page=-1&cat='.$cat->cat_ID); //-1 shows all posts per category. 1 to show most recent post.
        
      //http://us3.php.net/while ; http://codex.wordpress.org/The_Loop ; http://codex.wordpress.org/The_Loop_in_Action
	  //http://codex.wordpress.org/Function_Reference/the_time ;  http://codex.wordpress.org/Function_Reference/the_permalink 
      //http://codex.wordpress.org/Function_Reference/the_title ; http://codex.wordpress.org/Function_Reference/comments_number
	  while(have_posts()): the_post(); 
	  	 //http://codex.wordpress.org/Function_Reference/get_the_category
         $category = get_the_category();
         //Display a post once, even if it is in multiple categories/subcategories. Lists the post in the first Category displayed.
         if ($category[0]->cat_ID == $cat->cat_ID) {?>
            <li><?php the_time('M d, Y')?> &raquo; <a href="<?php the_permalink() ?>"  title="Permanent Link to: <?php the_title(); ?>">
			<?php the_title(); ?></a> (<?php comments_number('0', '1', '%'); ?>)</li>
       <?php } //endif
	    endwhile; //endwhile
	   ?>
      </ul> 
      </li>
    <?php } ?>
    </ul>
    <?php 
	//http://codex.wordpress.org/Function_Reference/wp_reset_query
	wp_reset_query(); 
	?>   
    <h2>Archives:</h2>   
    <ul class="sitemap-archives">   
    <?php 
	  //http://codex.wordpress.org/Function_Reference/wp_get_archives
	  wp_get_archives('type=monthly&show_post_count=true'); 
	?>   
    </ul>     
</div>

CODE-2 Notes:

The idea of choosing page.php is to preserve your blog´s layout (header, sidebar, footer) and style. In other themes, other files might be a better starting point. It all depends on your theme.

For instance, for the Clear Line theme, I started with the right_sidebar.php file as a basis (since my blog has a right sidebar only).

On line 23 of the code, I excluded the sitemap page of this blog from showing up in the “Pages:” list. Of course, your HTML Sitemap Page ID is different. If you don´t know how to find the page ID, read my previous tutorial on How To Find the Page ID.

CODE-2 was tested to work on WordPress 3.0 and above. But I hope that you will upgrade to the latest WordPress version.

You can customize the code to fit your blog!

Code References:

Step 5. Login to your WordPress dashboard. In your Administration Screens, and on the Left Panel, go to Pages -> Add new. This will create a new page as shown in the image below:

Create the new HTML Sitemap Page in WordPress dashboard.

In the Page Attributes box, choose the HTML Sitemap Page template and then click Publish. And that´s it!

Real Example | Where to Add the HTML SiteMap Code

To give you a real example. One of the themes I am using for this blog is the Emplode theme. Below is the original code of the page.php file.

Original page.php file | Emplode Theme

<?php get_header(); ?>

	<?php if (have_posts()) : ?>
		<?php while (have_posts()) : the_post(); ?>
		<div class="post" id="post-<?php the_ID(); ?>">
			<div class="post_title"><h2><?php the_title(); ?></h2></div>
			<?php edit_post_link('Edit this page', '<div class="post_date">', '</div>'); ?>
			
            <div class="post_body">
				<?php the_content('<p class="serif">Read the rest of this page &raquo;</p>'); ?>

				<div class="clearer">&nbsp;</div>
			</div>

			<?php wp_link_pages(array('before' => '<div class="post_meta archive_pagination"><strong>Pages:</strong> ', 'after' => '</div>', 'next_or_number' => 'number')); ?>

		</div>		
		<?php endwhile; ?>

	<?php else : ?>
		<h2>Not Found</h2>
		<p>Sorry, but you are looking for something that isn't here.</p>
		<?php get_search_form(); ?>

	<?php endif; ?>	

<?php get_sidebar(); ?>
<?php get_footer(); ?>

Now, to create the HTML sitemap page for this blog. First, I made a copy of the page.php file, and renamed page-sitemap.php. Second, I added (CODE-1 and CODE-2) to the page-sitemap.php file. Notice that: CODE-1 is added at the top of the file, and the get_header()), get_sidebar() and get_footer() tags are preserved and also the page layout is preserved.

Below is the source code of the page-sitemap.php file for the Emplode Theme that I used for this blog.

page-sitemap.php file | Emplode Theme

<?php
/*
 Template Name: HTML Sitemap Page
*/
?>
<?php get_header(); ?>

<div class="post_body"> 
<!-- 
/***************************************************************************
* @Author: Boutros AbiChedid 
* @Date:   October 30, 2011
* @Websites: http://bacsoftwareconsulting.com/ ; http://blueoliveonline.com/
* @Description: Code that dynamicaly generates an HTML sitemap for the Blog.
* @Tested on: WordPress version 3.2.1 (but it works on earlier versions.)
****************************************************************************/ 
-->
<div class="html-sitemap">
    <h2>Author(s):</h2>
    <ul class="sitemap-authors">
    <?php 
       //http://codex.wordpress.org/Function_Reference/wp_list_authors
       wp_list_authors('exclude_admin=1&optioncount=1');
    ?>
    </ul>
     
    <h2>Pages:</h2>
    <ul class="sitemap-pages">
    <?php
      //http://codex.wordpress.org/Function_Reference/wp_list_pages
      wp_list_pages('exclude=889&title_li='); //***Exclude page Id, separated by comma. I excluded the sitemap of this blog (page_ID=889).
    ?>
    </ul>  
    <h2>Posts:</h2>
    <ul>
    <?php
    //http://codex.wordpress.org/Function_Reference/get_categories
	$cats = get_categories('exclude='); //***Exclude categories by ID, separated by comma if you like.
    
	foreach ($cats as $cat) {
      echo '<li class="category">'."\n".'<h3><span class="grey">Category: </span>'.$cat->cat_name.'</h3>'."\n";
      echo '<ul class="cat-posts">'."\n";
      
      //http://codex.wordpress.org/Function_Reference/query_posts
	  query_posts('posts_per_page=-1&cat='.$cat->cat_ID); //-1 shows all posts per category. 1 to show most recent post.
        
      //http://us3.php.net/while ; http://codex.wordpress.org/The_Loop ; http://codex.wordpress.org/The_Loop_in_Action
	  //http://codex.wordpress.org/Function_Reference/the_time ;  http://codex.wordpress.org/Function_Reference/the_permalink 
      //http://codex.wordpress.org/Function_Reference/the_title ; http://codex.wordpress.org/Function_Reference/comments_number
	  while(have_posts()): the_post(); 
	  	 //http://codex.wordpress.org/Function_Reference/get_the_category
         $category = get_the_category();
         //Display a post once, even if it is in multiple categories/subcategories. Lists the post in the first Category displayed.
         if ($category[0]->cat_ID == $cat->cat_ID) {?>
            <li><?php the_time('M d, Y')?> &raquo; <a href="<?php the_permalink() ?>"  title="Permanent Link to: <?php the_title(); ?>">
			<?php the_title(); ?></a> (<?php comments_number('0', '1', '%'); ?>)</li>
       <?php } //endif
	    endwhile; //endwhile
	   ?>
      </ul> 
      </li>
    <?php } ?>
    </ul>
    <?php 
    //http://codex.wordpress.org/Function_Reference/wp_reset_query
    wp_reset_query(); 
    ?>
    
    <h2>Archives:</h2>   
    <ul class="sitemap-archives">   
    <?php 
	  //http://codex.wordpress.org/Function_Reference/wp_get_archives
	  wp_get_archives('type=monthly&show_post_count=true'); 
	?>   
    </ul>     
</div>
</div>
  
<?php get_sidebar(); ?>
<?php get_footer(); ?>

Notice that I not only replaced the the_content() tag but I also removed the loop. The point to keep in mind is that you need to keep the header, sidebar and footer tags and also preserve the page look as your blog´s.

Styling the HTML sitemap | style.css

Finally we need to style the HTML Sitemap Page with CSS. The following code is what I used for this blog. The code should be added to your theme´s CSS file (called style.css). Change it to fit your blog´s design.

/***********************************************************
* @Author: Boutros AbiChedid
* @Date:   October 30, 2011
* @Websites: blueoliveonline.com ; bacsoftwareconsulting.com
* @Desc: Styling the Dynamic HTML Sitemap for WordPress.
************************************************************/
.html-sitemap h2{
padding-top: 10px;
}
.category {
list-style:none;
padding-bottom: 5px;
}
.grey {
color: #777;
background-color: inherit;
}
.cat-posts {
padding-bottom: 10px;
padding-top: 10px;	
}
.cat-posts li{
padding-bottom: 5px;
list-style:square;	
}
.sitemap-authors li, .sitemap-pages li, .sitemap-archives li{
padding-bottom: 5px;
}

Your Turn to Talk

You now have the choice to Create an Effective HTML sitemap Page for your WordPress Blog and customize it to fit your blog´s theme, without the need of a plugin.

How easy did you find this tutorial to implement? Do you have a hard time integrating the code into your WordPress theme? Do you have something to add or anything else to say? If so, please share your opinion or questions in the comments section. Your opinion matters, unless it is a Spam.

If you found this post useful, please consider: linking back to it, subscribing by email to future posts, or subscribing to the RSS feed to have new articles delivered to your feed reader, or feel free to donate. Thanks!

About the Author |
Boutros is a professional Drupal & WordPress developer, Web developer, Web designer, Software Engineer and Blogger. He strives for pixel perfect design, clean robust code, and user-friendly interface. If you have a project in mind and like his work, feel free to contact him. Connect with Boutros on Twitter, and LinkedIn.
Visit Boutros AbiChedid Website.

25 Responses to “How To Add a Dynamic HTML Sitemap in WordPress Without a Plugin”

  1. Raj says:

    Thanks, I really appreciate. Very nice, This code is working better than plugins.

  2. Pustakawan says:

    Hi.
    I really appreciate what you doing. I bet you spent a lot of time to make your codes work well.
    I’m new to WordPress software, so I don’t exactly what to do when something goes wrong.
    FYI, I still use Twenty Ten as my theme.
    After I implement your code, I notice that I have lost my sharing and rating buttons. I can’t figure out because I activated those buttons and still I can’t see them.
    Second, your code only read the parent category. For example in every post I use parent and child but only parent that show on the sitemap (maybe the child categories is playing out there somewhere, where your code can’t reach them).
    Because those two reason above, I’m no longer use it to show my sitemap.
    I wish you have more time to developed your code.
    Thanks for your attention.

  3. Viki says:

    Great tuts, i ask permission to use your code in my blog, many thanks :)

  4. Anand Kumar says:

    Thanks for the great post , i have been scouting the net for months to get something like this.

  5. Hi Boutros.
    I’ve many posts and how to make the paginate in this html sitemap?

  6. El de las zapatillas says:

    Hi!!! Nice piece of code. It works almost fine for me. “Almost” because there’s a little bug with my theme (I think this could be the reason): instead of showing a multicategories post just once, it doesn’t show multicategories posts at all. So, the almost 1300 posts written in three years get reduced to almost 100 posts. You can check in my sitemap. Is it happening only to me??

    Thanks for the answer…

    • Hi. Thanks for the feedback. I checked your sitemap and there is definitely many more than 100 links, not sure how many for posts (I can’t read spanish).
      Did you get it fixed?
      You have 1200 posts assigned to multiple categories?
      You are the first one to report this behavior. If it still does not work, take a look at my reply to @Sheshnath below, and see when you modify the code if it adds the same post for multicategories. Just for testing.
      Boutros.

      • Thanks a lot for checking my sitemap. I’d removed yesterday the lines 47 and 50 to show all posts. But now multicategories post appears with every category listed :-(

        I tried three or four different solutions, but without success. I am researching. If I find a solution, I’ll let you know.

        Thanks again…

  7. Sheshnath says:

    Hi, nice tips its really awesome…
    just wanted to ask a question how can I show all the post of a category in site map page, even if it is there in any other category. Please help.

    • Hi Sheshnath:

      The way the code is written right now is: If a post is assigned to multiple categories, then the sitemap displays the post only once in the first category.
      If you want to display the same post in every category that it is assigned to: For example you have PostA that is assigned to cat1, cat2 and cat3, and you want the sitemap to list PostA in cat1, cat2 and cat3.
      Then you need to remove (or comment out) two lines of CODE-2:
      line 47: if ($category[0]->cat_ID == $cat->cat_ID) {
      AND line 50: }

      Basically, you are removing the if statement that display the post once when assigned for multiple categories.
      Hope this helps.
      Boutros.

      • Sheshnath says:

        Hi Boutros AbiChedid:
        Thanks a lot, all done.

        • Sheshnath:

          For Your “How To Add Sitemap To Your WordPress Site” that you posted on 27 Feb, 2012 on your blog.
          You need to modify your post’s top and bottom content to add a citation of the source of your post (link to this post).
          AND also you need to add back the Authorship lines for both the main WordPress code for the sitemap and for the CSS code.
          You copied my code and you claimed it as yours.
          I detailed what needs to be done by commenting on your blog.
          This is plagiarism (content theft), and you can’t do that.

  8. putri says:

    how do I create categories and sub ​​categories on a regular basis?

    sample:

    categories one
    – sub categories one
    – post one
    – post two

    categories two
    – sub categories two
    – post three
    – post four

    I get my site is irregular http://www.nabit-ist.com/sitemap
    Do you have a solution?

    • You create Categories from the WordPress Dashboard on the left panel -> Categoties.
      (For WordPress 3.3.1, see Administration > Posts > Categories SubPanel.)
      You create a sub-category by assigning it a ‘parent’ category.
      Then you assign the post to either a cat. or a sub-cat.
      Then the HTML sitemap will display them in the order assigned in the dashboard.

      http://codex.wordpress.org/Manage_Categories_SubPanel

      Hope this helps.
      Boutros.

      • putri says:

        I mean is make a post by category in html sitemap. categories and sub ​​categories that I made are correct. the problem is the arrangement of sub-categories do not fit into the category.
        Posts:

        <?php $cats = get_categories('exclude=');
        foreach ($cats as $cat) {
        echo ''."\n".'Category: '.$cat->cat_name.''."\n";
        echo ''."\n";
        query_posts('posts_per_page=-1&cat='.$cat->cat_ID);
        $category = get_the_category();
        if ($category[0]->cat_ID == $cat->cat_ID) {?>
        » <a href="" title="Permanent Link to: ">


        The above code generates category in alphabetical order:
        categories A
        sub categories B
        - post B

        I really want is:
        categories B
        sub categories B
        - post B

        • The code right now, treat subcategories as separate categories. It doesn’t keep the Category hierarchy that you are looking for.
          If you link post A.1 to subcategory A.1 only WITHOUT the Parent Category A, then the post will show in Subcategory A.1.
          However, If you link post A.1 to the subcategory A.1 AND also to its Parent Category A, then the post will show in category A.

          You are right, the code does not maintain the Category — Subgategory tree like you are expecting.
          For the time being, I have no time to improve the code.
          If you find a solution and a better code for the Category section, please share it here so everybody else can learn from you.

          Note: For next time if you want to add a snippet of PHP code:
          use*:
          {php}
          Some code here….
          {/php}

          * Replace { with [ and replace } with ]

          Thanks.
          Boutros.

  9. Apriyanto says:

    Thanks for this tutorial, this is what I need. I will try it and remove the plugin I used for several years.

  10. msrosyidi says:

    Thanks, this is what I need. I will try it and remove the plugin I used for several years.

  11. johnny_n says:

    Nicely done! I like this version better than Yoast’s.

    Note — on some themes you’ll need to wp_reset_query(); after line 56 (of CODE-2)… I did. ;-)

  12. jennifer says:

    Hey…Great job …Wonderfully you explained the steps…Thanks a ton for sharing….i’ll definitely try…