yoast seo

HTML Sitemap for WordPress

HTML Sitemap for WordPress

February 08th, 2011 – 63 Comments

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.

Optimize your site for search & social media and keep it optimized with Yoast SEO Premium »

Yoast SEO for WordPress pluginBuy now » Info

HTML sitemap for wordpress, as shown on YoastThere’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 advice 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 id="authors">Authors</h2>
<ul>
<?php
wp_list_authors(
  array(
    'exclude_admin' => false,
  )
);
?>
</ul>

<h2 id="pages">Pages</h2>
<ul>
<?php
// Add pages you'd like to exclude in the exclude here
wp_list_pages(
  array(
    'exclude' => '',
    'title_li' => '',
  )
);
?>
</ul>

<h2 id="posts">Posts</h2>
<ul>
<?php
// Add categories you'd like to exclude in the exclude here
$cats = get_categories('exclude=');
foreach ($cats as $cat) {
  echo "<li><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();
    // Only display a post link once, even if it's in multiple categories
    if ($category[0]->cat_ID == $cat->cat_ID) {
      echo '<li><a href="'.get_permalink().'">'.get_the_title().'</a></li>';
    }
  }
  echo "</ul>";
  echo "</li>";
}
?>
</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:

foreach( get_post_types( array('public' =&amp;gt; true) ) as $post_type ) {
  if ( in_array( $post_type, array('post','page','attachment') ) )
    continue;

  $pt = get_post_type_object( $post_type );

  echo '&amp;lt;h2&amp;gt;'.$pt-&amp;gt;labels-&amp;gt;name.'&amp;lt;/h2&amp;gt;';
  echo '&amp;lt;ul&amp;gt;';

  query_posts('post_type='.$post_type.'&amp;amp;posts_per_page=-1');
  while( have_posts() ) {
    the_post();
    echo '&amp;lt;li&amp;gt;&amp;lt;a href=&amp;quot;'.get_permalink().'&amp;quot;&amp;gt;'.get_the_title().'&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;';
  }

  echo '&amp;lt;/ul&amp;gt;';
}

Read more: ‘Why you should buy Yoast SEO Premium’ »


63 Responses to HTML Sitemap for WordPress

  1. Jojo Joson
    By Jojo Joson on 4 March, 2011

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

  2. shrinidhi
    By shrinidhi on 2 March, 2011

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

  3. Anand Kumar
    By Anand Kumar on 1 March, 2011

    Thank for such an awesome tutorial! I did it.

  4. MattCNS
    By MattCNS on 28 February, 2011

    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
      By Cindy on 10 March, 2011

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

  5. Jamie
    By Jamie on 24 February, 2011

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

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

  6. Valerie
    By Valerie on 24 February, 2011

    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
    By Bruce on 23 February, 2011

    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
      By Ron Mahon on 2 March, 2011

      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
    By Tom Wazynski on 21 February, 2011

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

  9. Flyer
    By Flyer on 19 February, 2011

    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
      By Flyer on 19 February, 2011

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

  10. Dustin
    By Dustin on 18 February, 2011

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

  11. Nate Talbot
    By Nate Talbot on 17 February, 2011

    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
    By walidmrealtor on 15 February, 2011

    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
    By Joanne Fennell on 15 February, 2011

    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
    By Joanne Fennell on 15 February, 2011

    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
    By cuma satu on 14 February, 2011

    Nice post, keep share

  16. Bill Bennett
    By Bill Bennett on 14 February, 2011

    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
      By Lou Lynch on 14 February, 2011

      Thanks for the help Bill

  17. Lou Lynch
    By Lou Lynch on 14 February, 2011

    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
    By Martijn Reintjes on 13 February, 2011

    @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
      By Andy Max Jensen on 14 February, 2011

      That worked for me too.

      • Lou Lynch
        By Lou Lynch on 14 February, 2011

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

        • Andy Max Jensen
          By Andy Max Jensen on 14 February, 2011

          Ok …can’t post the cod here …

        • Andy Max Jensen
          By Andy Max Jensen on 14 February, 2011

          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
    By Tim Chalk on 12 February, 2011

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

  20. Veki
    By Veki on 12 February, 2011

    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
    By Cindi on 12 February, 2011

    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
    By Christopher Roberts on 11 February, 2011

    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
    By Sean Phillips on 11 February, 2011

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

    http://www.riverwoodphotography.com/sitemap

    • Sean Phillips
      By Sean Phillips on 11 February, 2011

      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
    By Lou Lynch on 10 February, 2011

    @Andy. I got the same thing.

  25. Andy Max Jensen
    By Andy Max Jensen on 10 February, 2011

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

    :-) Andy

  26. coloring dude
    By coloring dude on 10 February, 2011

    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
    By Josh Fialkoff on 10 February, 2011

    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

  28. Amit
    By Amit on 10 February, 2011

    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
    By Joost de Valk on 10 February, 2011

    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
    By amor en linea on 10 February, 2011

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

  31. Lou Lynch
    By Lou Lynch on 10 February, 2011

    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
      By Cindi on 10 February, 2011

      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
    By Simon on 10 February, 2011

    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
    By Danny van Kooten on 9 February, 2011

    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
      By Danny van Kooten on 9 February, 2011

      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
    By Bill Bennett on 9 February, 2011

    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().”“;

  35. Good Gift Ideas
    By Good Gift Ideas on 9 February, 2011

    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
    By Cindi on 9 February, 2011

    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
    By Zibbi on 9 February, 2011

    Thank you
    Zibbi

  38. Lance Curtis
    By Lance Curtis on 8 February, 2011

    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
    By Ron Mahon on 8 February, 2011

    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
    By Edyta Exceed Photography on 8 February, 2011

    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
    By Tim on 8 February, 2011

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

  42. Joe
    By Joe on 8 February, 2011

    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
    By TradiArt on 8 February, 2011

    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
    By Herman dailybits on 8 February, 2011

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

  45. Foomandoonian
    By Foomandoonian on 8 February, 2011

    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
    By Herman dailybits on 8 February, 2011

    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/


Check out our must read articles about Technical SEO