HTML Sitemap for WordPress

An HTML sitemap (as opposed to an XML sitemap) is often mentioned as being useful for SEO. They certainly are if you use them wisely (and especially Bing seems to like them at times), but I like them even more for the fact that users like them a lot.

HTML sitemap for wordpress, as shown on Yoast

There’s plenty of plugins out there that will help you make an HTML sitemap. It’s not a feature in my WordPress SEO plugin just yet, but it might become one. The issue is though, that in most cases, you’ll want to do specific things with your sitemaps, include or exclude certain pages / post types, show certain taxonomies, etc. That’s why I tend to advise people to create a Sitemap Page template in their theme and use that.

In fact, I advise you to use a theme partial, so you can reuse your HTML sitemap template on your WordPress 404 error pages too. To do that, follow these steps: first of all, create a partials folder within your theme folder. In that partials folder, create a file called sitemap.php.

Paste the following code into that file and adapt as needed for your site:

<h2>Authors</h2>
<ul>
<?php wp_list_authors( array(
  'exclude_admin' => false
) ); ?>
</ul>

<h2>Pages</h2>
<ul>
<?php
wp_list_pages( array( 
  'exclude' => '',
  'title_li' => '',
) ); ?>
</ul>

<h2>Posts</h2>
<?php 
$cats = get_categories('exclude=');
foreach ($cats as $cat) {
  echo '<h3>' . $cat->cat_name . '</h3>';
  echo '<ul>';
  query_posts('posts_per_page=-1&cat=' . $cat->cat_ID);
  while(have_posts()) {
    the_post();
    $category = get_the_category();
    if ($category[0]->cat_ID == $cat->cat_ID) {
      echo '<li><a href="' . get_permalink() . '">' . get_the_title() . '</a></li>'; 
    }
  }
  echo '</ul>';
}

Now, wherever you need that HTML sitemap “bit” in your WordPress theme, use this:

<?php get_template_part('/partials/sitemap'); ?>

HTML Sitemap WordPress Page Template

You could do this, for instance, for a sitemap page template. To create a sitemap page template using this code, duplicate your page.php file and rename it to page-sitemap.php. Now open it, and below the call to the_content(); that’s in there, add the get_template_part() bit mentioned above. Now go to the first line of the file, and after the opening <?php (but before get_header()), add this comment:

/*
Template Name: Sitemap Page
*/

That’ll make WordPress recognize it as an HTML Sitemap template. This will allow you to write some introductory text for your HTML sitemap, after which the full sitemap shows.

Add Custom Post Types to your HTML Sitemap

Update: If you need custom post types in your HTML sitemap too, add this code underneath the other code:

<?php
foreach( get_post_types( array('public' => true) ) as $post_type ) {
  if ( in_array( $post_type, array('post','page','attachment') ) ) {
    continue;
  }
  
  $pt = get_post_type_object( $post_type );

  echo '<h2>' . $pt->labels->name . '</h2>';
  echo '<ul>';
  query_posts('post_type=' . $post_type . '&posts_per_page=-1');
  while( have_posts() ) {
    the_post();
    echo '<li><a href="' . get_permalink() . '">' . get_the_title() . '</a></li>';
  }
  echo '</ul>';
}
?>

Read more: Why you should buy Yoast SEO Premium »

Coming up next!


63 Responses to HTML Sitemap for WordPress

  1. Jojo Joson
    Jojo Joson  • 13 years ago

    Thank you Joost :) It was an awesome idea :) and I will donate for your WordPress SEO plugin soon.

  2. shrinidhi
    shrinidhi  • 13 years ago

    Thanks for the post Yoast…nice work …….will start on this one..

  3. Anand Kumar
    Anand Kumar  • 13 years ago

    Thank for such an awesome tutorial! I did it.

  4. MattCNS
    MattCNS  • 13 years ago

    Thanks! This was exactly what I was looking for. I even managed to hack the code to display my custom post types in the site map.

    • Cindy
      Cindy  • 13 years ago

      Hey Matt,
      Would you mind sharing your code??
      Thanks!

  5. Jamie
    Jamie  • 13 years ago

    I am still having the loop issue. Any help would be great:

    http://blog.firstusahomeloans.info/sitemap/

  6. Valerie
    Valerie  • 13 years ago

    Thanks for the great tip. It made short work of giving me exactly what I wanted in a site map. I created a shortcode with the code you provided for the template, then just used that in the body of a new page, no new template necessary.


    // Call Sitemap Data
    add_shortcode('sitemap','getsitemap');
    function getsitemap() {
    echo
    get_template_part('/partials/sitemap');
    ;
    }

  7. Bruce
    Bruce  • 13 years ago

    Hi all,

    Has anyone tried Unlimited Sitemap Generator?
    http://www.xml-sitemaps.com/standalone-google-sitemap-generator.html

    I’m debating HTML Sitemap for WordPress vs. Unlimited Sitemap Generator. USG seem less troubling. Optional extras along with XML and HTML include: images, video, mobile and news sitemap.

    • Ron Mahon
      Ron Mahon  • 13 years ago

      Bruce
      After reading you post I tried it. The him him XML site maps are excellent. In a mu sites using WordPress SCO I was unable to get a sitemap for each of the subdomains. XML – Sitemaps handle that with flying colors.

      The HTML site maps suck!

      regards
      Ron

  8. Tom Wazynski
    Tom Wazynski  • 13 years ago

    Thanks this has really helped, as has many of your other articles.

  9. Flyer
    Flyer  • 13 years ago

    great post joost!
    i tried creating shortcode, but it’s not working for soe reason
    code of page is
    <?php
    function anime_list() {
    $cats = get_categories('exclude=156');
    foreach ($cats as $cat) {
    echo '’;
    echo ‘‘.$cat->cat_name.’‘;
    query_posts(‘posts_per_page=-1&cat=’.$cat->cat_ID);
    while(have_posts()) {
    the_post();
    $category = get_the_category();
    // Only display a post link once, even if it’s in multiple categories
    if ($category[0]->cat_ID == $cat->cat_ID) {
    echo ‘‘.get_the_title().’‘;
    }
    }
    }
    }

    add_shortcode(‘anime-list’, ‘anime_list’);
    ?>
    so, i tried inserting shortcode [anime-list] into created page, but it’s not showing what it should. it’s just showing [anime-list] on page. hope some one can help me with this one

    • Flyer
      Flyer  • 13 years ago

      i somehow managed to make shortcode work. now, how can be posts and categories sorted by alphabet?

  10. Dustin
    Dustin  • 13 years ago

    What if you have like 5000+ pages? Is it still a good idea to create a html sitemap?

  11. Nate Talbot
    Nate Talbot  • 13 years ago

    I’ve had the infinite loop problem too. I’m trying to learn PHP coding, and understand the loop statement is causing the infinite loop, but I’m sure it was added there for a reason. So what’s missing to stop the loop?

  12. walidmrealtor
    walidmrealtor  • 13 years ago

    Thanks for the post Yoast. I’ll keep an eye out for your plugin and the html function, I’d really like to see it function.

  13. Joanne Fennell
    Joanne Fennell  • 13 years ago

    Sorry I entered the wrong code in the my last post. The code in the sitemap.php file is –

    Authors

    false,
    )
    );
    ?>

    Pages

    ”,
    ‘title_li’ => ”,
    )
    );
    ?>

    Posts

    <?php
    // Add categories you'd like to exclude in the exclude here
    $cats = get_categories('exclude=');
    foreach ($cats as $cat) {
    echo "”.$cat->cat_name.””;
    echo “”;
    query_posts(‘posts_per_page=-1&cat=’.$cat->cat_ID);
    while(have_posts()) {
    the_post();
    $category = get_the_category();
    // Only display a post link once, even if it’s in multiple categories
    if ($category[0]->cat_ID == $cat->cat_ID) {
    echo ‘”.get_the_title().”;‘;
    }
    }
    echo “”;
    echo “”;
    }
    ?>

    And the code in the page-sitemap.php file is –

    <div id="post-“>

    <?php the_content('Read the rest of this page’); ?>

    Pages: ‘, ‘after’ => ”, ‘next_or_number’ => ‘number’)); ?>

  14. Joanne Fennell
    Joanne Fennell  • 13 years ago

    I’m a complete wordpress newbie and not sure what I’m doing wrong but I don’t have a sitemap – am I missing something really obvious? What location should I put the sitemap.php file in? Your help would be very much appreciated. Below are the steps I’ve taken.

    1. created partials folder under the images folder
    2. created sitemap.php file and put this file in the partials folder with the code below:
    Authors

    false,
    )
    );
    ?>

    Pages

    ”,
    ‘title_li’ => ”,
    )
    );
    ?>

    Posts

    <?php
    // Add categories you'd like to exclude in the exclude here
    $cats = get_categories('exclude=');
    foreach ($cats as $cat) {
    echo "”.$cat->cat_name.””;
    echo “”;
    query_posts(‘posts_per_page=-1&cat=’.$cat->cat_ID);
    while(have_posts()) {
    the_post();
    $category = get_the_category();
    // Only display a post link once, even if it’s in multiple categories
    if ($category[0]->cat_ID == $cat->cat_ID) {
    echo ‘”.get_the_title().”;‘;
    }
    }
    echo “”;
    echo “”;
    }
    ?>

    3. Created the sitemap.php file and code below

    Authors

    false,
    )
    );
    ?>

    Pages

    ”,
    ‘title_li’ => ”,
    )
    );
    ?>

    Posts

    <?php
    // Add categories you'd like to exclude in the exclude here
    $cats = get_categories('exclude=');
    foreach ($cats as $cat) {
    echo "”.$cat->cat_name.””;
    echo “”;
    query_posts(‘posts_per_page=-1&cat=’.$cat->cat_ID);
    while(have_posts()) {
    the_post();
    $category = get_the_category();
    // Only display a post link once, even if it’s in multiple categories
    if ($category[0]->cat_ID == $cat->cat_ID) {
    echo ‘”.get_the_title().”;‘;
    }
    }
    echo “”;
    echo “”;
    }
    ?>

  15. cuma satu
    cuma satu  • 13 years ago

    Nice post, keep share

  16. Bill Bennett
    Bill Bennett  • 13 years ago

    I got this working just fine.

    You can see my sitemap here: http://billbennett.co.nz/sitemap/

    and download the code from:

    http://shorttext.com/cmk9hzzinwg

    • Lou Lynch
      Lou Lynch  • 13 years ago

      Thanks for the help Bill

  17. Lou Lynch
    Lou Lynch  • 13 years ago

    Removing the WHILE statement throws an error. If someone has successful removed it and stopped the loop problem, please post entire syntax … I would greatly appreciate it.

  18. Martijn Reintjes
    Martijn Reintjes  • 13 years ago

    @yoast thanks for this cool snippit. Just added it to the WP template I use for our webshop. Am curious about the results!

    @all About the infinite loop thingy: make sure you remove the WHILE loop from sitemap page. That takes care of the loop problem.

    • Andy Max Jensen
      Andy Max Jensen  • 13 years ago

      That worked for me too.

      • Lou Lynch
        Lou Lynch  • 13 years ago

        @Andy, can you post the code with the WHILE statement removed? Still throwing an error for me.

        • Andy Max Jensen
          Andy Max Jensen  • 13 years ago

          Ok …can’t post the cod here …

        • Andy Max Jensen
          Andy Max Jensen  • 13 years ago

          You have to remove the “while” and “endwhile” lines …they look something like this:

          And:

          They can look a little different depending on your theeme.

          Then insert the codeblock and theme-name comment as described in the article.

          If you use the theme TwentyTen …youwould end up with a file called “page-sitemap.php” with the following code:

          <div class="post" id="post_”>

          <a href="/”> »

          <?php the_content(__('Read the rest of this page »’,’arthemia’)); ?>

          Skribenter

          false,
          )
          );
          ?>

          Sider

          ”,
          ‘title_li’ => ”,
          )
          );
          ?>

          Indlæg

          <?php
          // Add categories you'd like to exclude in the exclude here
          $cats = get_categories('exclude=');
          foreach ($cats as $cat) {
          echo "”.$cat->cat_name.””;
          echo “”;
          query_posts(‘posts_per_page=-1&cat=’.$cat->cat_ID);
          while(have_posts()) {
          the_post();
          $category = get_the_category();
          // Only display a post link once, even if it’s in multiple categories
          if ($category[0]->cat_ID == $cat->cat_ID) {
          echo ‘‘.get_the_title().’‘;
          }
          }
          echo “”;
          echo “”;
          }
          ?>

  19. Tim Chalk
    Tim Chalk  • 13 years ago

    I’m having the same infinite loop problem as Andy and Lou. Does anyone know how to solve this?

  20. Veki
    Veki  • 13 years ago

    Great stuff again.

    1. Why there is not a link on categories?
    2. Is there any best praxis to nofollow link to the Sitemap page or No-index this page?

  21. Cindi
    Cindi  • 13 years ago

    Does anyone know how to modify this code so that the category hierarchy is maintained? Some of my categories look out of place without the parent category shown as a parent.

    Example:
    Category 1
    post
    post
    Category 2
    Category child 1
    post
    post
    Category child 2
    post
    post

  22. Christopher Roberts
    Christopher Roberts  • 13 years ago

    I emailed you about this a while ago Joost, and its nice to see you have acted on my comments :-) I am going to implement this on my philosophy blog very soon, the server is playing up at the moment not :-(

    Thanks Joost, very useful!

  23. Sean Phillips
    Sean Phillips  • 13 years ago

    I tried to implement this using a partial and just get a completely blank page. Any thoughts?

    http://www.riverwoodphotography.com/sitemap

    • Sean Phillips
      Sean Phillips  • 13 years ago

      I got it to work using a template instead of a partial. Not sure what I was doing wrong, but oh well, it’s working now.

  24. Lou Lynch
    Lou Lynch  • 13 years ago

    @Andy. I got the same thing.

  25. Andy Max Jensen
    Andy Max Jensen  • 13 years ago

    Hi …I’ve got a (almost) infinite loop problem with this one …am I the only one?

    :-) Andy

  26. coloring dude
    coloring dude  • 13 years ago

    Great post, certainly saves time having to hand code the pages in there, would also be good to have max pages featured and as a wishlist, to have so you could only feature certain catagories. Still very handy!!

  27. Josh Fialkoff
    Josh Fialkoff  • 13 years ago

    Hi Joost,
    I’ve been using this plugin for several years. It is customizable and easy to use (easier than straight coding for me):

    http://www.dagondesign.com/articles/sitemap-generator-plugin-for-wordpress/

    I’d love to get your feedback.

    Thanks for your advice!

    -Josh

    • Joost de Valk

      does it still include a link back to it’s own plugin page on the generated sitemap?

      • Josh Fialkoff
        Josh Fialkoff  • 13 years ago

        Yes. Here is an example:

        http://fialkoffconsulting.com/sitemap/

        • Josh Fialkoff
          Josh Fialkoff  • 13 years ago

          I agree Joost! I will give your method a shot. ;-)

        • Joost de Valk

          That’s a reason for not using it right there. I hate plugins that do that.

  28. Amit
    Amit  • 13 years ago

    I hit your sitemap page quite a bit a couple of weeks ago so I could implement it in the new site we launched, funny you come out with it now :)

    I’ve noticed you didn’t use any titles in the links, any reason for that?

  29. Joost de Valk

    For those of you having problems: I just updated the code in the post to use the right quotes around get_the_title. Thanks to everyone who noticed!

  30. amor en linea
    amor en linea  • 13 years ago

    Great contribution! The truth is that it simplifies the accessibility to the search engines. Thank you Joost

  31. Lou Lynch
    Lou Lynch  • 13 years ago

    Yeah … I am getting the same error as Bill Bennett and Cindi. @Bill or Cindi, if you come up with the fix, please re-post. Thanks.

    • Cindi
      Cindi  • 13 years ago

      Copy the second line of my post above over the one that looks just like it. I changed some ” to ‘.
      Here’s the adjusted code:
      echo ''.get_the_title().'';It is hard to see the difference, but they are different. Works great for me. Thanks Yoast. A few little adjustments with CSS and I have a wonderful sitemap.

  32. Simon
    Simon  • 13 years ago

    Question: I was thinking about creating an archives page for my blog. Would having an HTML sitemap along with the archives be bad for SEO, perhaps viewed as duplicate content? I’m not sure.

  33. Danny van Kooten
    Danny van Kooten  • 13 years ago

    Good post Joost, I like the partial idea for easy reuse. :-) One small note: it seems that you forgot to escape the ” where you echo the list item.


    echo "".get_the_title()."";

    • Danny van Kooten
      Danny van Kooten  • 13 years ago

      Ah, now I see that i’m not the first one who brought this up and that comment code isn’t properly encoded. :-)

  34. Bill Bennett
    Bill Bennett  • 13 years ago

    I’m getting a similar error:

    Parse error: syntax error, unexpected T_CONSTANT_ENCAPSED_STRING, expecting ‘,’ or ‘;’ in

    public_html/wp-content/themes/Raupo/partials/sitemap.php on line 39

    the line is:
    echo ““.get_the_title().”“;

    • Bill Bennett
      Bill Bennett  • 13 years ago

      Cutting and pasting the code didn’t work. Trying again with the code command.

      echo "".get_the_title()."";

  35. Good Gift Ideas
    Good Gift Ideas  • 13 years ago

    Nice post, Joost. I just implemented this in my Thematic template. =) I’d been using Dagon Sitemap for a while, but I prefer this much more.

    Awesome.

  36. Cindi
    Cindi  • 13 years ago

    I had to make some adjustments to the code. I was getting unexpected T_CONSTANT_ENCAPSED_STRING error.
    echo "".get_the_title()."";

    I’m not a coder, but this worked for me.
    echo ''.get_the_title().'';

  37. Zibbi
    Zibbi  • 13 years ago

    Thank you
    Zibbi

  38. Lance Curtis
    Lance Curtis  • 13 years ago

    Thanks for this post Yoast!
    I used the pages piece of your code to create a WP shortcode that I placed in a WP page called ‘Sitemap’.

    // jlc 2011.02.08 | Shortcodes for HTML Sitemap
    if ( ! function_exists( ‘sitemap_page’ ) ) {
    function sitemap_page() {
    // Add social bookmarking URL with button
    echo ”;
    echo ”;
    // Add pages you’d like to exclude in the exclude here
    wp_list_pages(
    array(
    ‘exclude’ => ”,
    ‘title_li’ => ”,
    )
    );
    echo ”;

    // Close the
    echo ”;
    echo ”;

    }
    }
    add_shortcode(‘sitemap’, ‘sitemap_page’);
    //

  39. Ron Mahon
    Ron Mahon  • 13 years ago

    Yost
    You continually amaze me with amount of content you turn out with out sacrificing quality.

    I’ve had a chance to try this yet but I’m using a multi-site setup using sub-domains.my question is do you think this will automatically search through all the subdomains? Or is there a way to modify the program make it go deep.?

    I am using your WP SCO plug-in but not having any luck with the generate XML site part.

    Thanks a lot for your country continuing contributions.
    best regards
    Ron

  40. Edyta Exceed Photography
    Edyta Exceed Photography  • 13 years ago

    It is all new for me, but thank you so much for sharing. I am looking forward to learn more about SEO and your plugin.

  41. Tim
    Tim  • 13 years ago

    Appreciate your posts as always! And I’m enjoying your SEO plugin for WP.

  42. Joe
    Joe  • 13 years ago

    Thanks for the post Yoast! Im using Headway as a theme and found it very touchy. Do you know if I’m better off using a Plugin or can I still create this file? Really looking forward to your plug-in.

  43. TradiArt
    TradiArt  • 13 years ago

    Thanks for considering our suggestion.

    http://wordpress.org/support/topic/plugin-wordpress-seo-by-yoast-suggestion-sitemap-page

    By the way, we consider crucial for any website to have a sitemap page. Also for SEO, helps to have indexed all pages for site, which is not bad :)

  44. Herman dailybits
    Herman dailybits  • 13 years ago

    Indeed, I had the same problems. I have just pasted the sitemap-code in my page-sitemap.php (after the div content).

  45. Foomandoonian
    Foomandoonian  • 13 years ago

    Sadly, this doesn’t seem to work for me. Any ideas what could be going wrong?

    I can use the page-sitemap as a template and build my sitemap page, but it doesn’t bring in the actual sitemap. I absolutely do have get_template_part below the_content.

  46. Herman dailybits
    Herman dailybits  • 13 years ago

    Good post. I had some difficulties to get it in a page, but I managed to create my own html-sitemap for my blog: http://www.dailybits.be/about/sitemap/