Create an HTML sitemap for WordPress without any plugins

There are various ways to create an HTML sitemap for a WordPress website. Also, there are numerous plugins that you can use to create a sitemap. But I am not going to use any plugin at this moment because I know how to make it properly and style it exactly the way I want.

In this post, I will show you how to create a dynamic sitemap for a WordPress website without any plugins. I said “Dynamic” because this sitemap will update automatically after you create a new post or page.

Create a sitemap for your WordPress website without any plugin

Please note that you need a little developer-level experience to follow along with me. But you don’t have to be a guru. If you can create a new file in your theme folder, it should be okay.

Create a necessary file in your theme

In the first step, you need to create a file in your active theme. You can name it anything but I would suggest you name it “page-sitemap.php

If you name it something else, then you have to reference the “Template Name” and choose the template while creating the actual page. To avoid this hassle, name it exactly as I mentioned above.

Also, I suggest you create the file in a child theme if you’re using a third-party theme for example “Twenty Twenty-Three.” So you don’t have to create the same file every time after the theme is updated to a new version.

Write actual code for the HTML sitemap page

In this section, I will give you all the PHP code for the sitemap page and even all the styles you need. This single file contains everything you need (including the styles). All you have to do is replace the category slug/names with your actual blog post categories.

After you create the actual sitemap page using this template, your page will look like this sitemap. However, you can change the styles such as colors, background colors, etc if you wish.

Here is the full code for the entire HTML sitemap page:

<?php get_header(); ?>
<style>.sitemap-banner,.sitemap-pages,.sitemap-posts{padding:90px 15px}.sitemap-posts ul li,.sitemap-posts ul li a{text-shadow:1px 1px 1px rgba(0,0,0,.4);font-size:1.3rem}.wrapper{max-width:1400px;margin:0 auto}.container{max-width:1000px;margin:0 auto}.sitemap-banner{background: #d8d8d8}.sitemap-pages{background-color:#dce8fc}.sitemap-pages ul{padding:0;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.sitemap-pages ul li{background-color:#c0d7fc;margin:10px;padding:15px;border:1px solid #4285f4;border-radius:4px;-webkit-transition:.3s ease-in;transition:.3s ease-in}.sitemap-pages ul li a{color:#8b3100;-webkit-transition:.5s ease-in;transition:.5s ease-in}.sitemap-pages ul li a:hover{color:#000;text-shadow:1px 1px 2px rgba(0,0,0,.4)}.sitemap-pages ul li:hover{background-color:#a4c6fc;-webkit-box-shadow:0 4px 8px 0 rgba(0,0,0,.2),0 6px 20px 0 rgba(0,0,0,.19);box-shadow:0 4px 8px 0 rgba(0,0,0,.2),0 6px 20px 0 rgba(0,0,0,.19)}.category-freelancing{background-color:#efffcf}.category-web-development{background-color:#fff7e3}.category-wordpress{background-color:#d4ffe0}.sitemap-posts ul{padding:0}.sitemap-posts ul li{line-height:2.4}.sitemap-posts ul li a{color:#000}.sitemap-posts ul li a:hover{text-decoration:underline}.sitemap-posts ul li:nth-child(odd),.sitemap-posts ul li:nth-child(odd) a{color:#8b3100}</style>
<section class="sitemap-banner">
  <div class="wrapper">
    <p><a href="<?php echo home_url('/'); ?>">Home</a> ↠ sitemap</p>
    <h1><?php the_title(); ?> - Find every necessary link/post/page that exists on this website and its hierarchy.</h1>
  </div>
</section> <!--.sitemap-banner-->
<section class="sitemap-pages">
  <div class="container">
  <h2>Pages</h2>
  <ul>
  <?php
  $pages = get_pages(array('sort_column' => 'menu_order', 'sort_order' => 'ASC'));
  $parents = array();
  $children = array();
  
  // Organize pages by parent/child relationship
  foreach ($pages as $page) {
    if ($page->post_parent) {
      $children[$page->post_parent][] = $page;
    } else {
      $parents[$page->ID] = $page;
    }
  }
  
  // Output parent pages and their children
  foreach ($parents as $parent) {
    $link = get_page_link($parent->ID);
    $title = $parent->post_title;
    echo "<li><a href='$link'>$title</a>";
    
    if (isset($children[$parent->ID])) {
      echo "<ul>";
      foreach ($children[$parent->ID] as $child) {
        $link = get_page_link($child->ID);
        $title = $child->post_title;
        echo "<li><a href='$link'>$title</a></li>";
      }
      echo "</ul>";
    }
    
    echo "</li>";
  }
  ?>
</ul>
  </div>
</section> <!-- .sitemap-pages -->
<section class="sitemap-posts category-web-development">
  <div class="container">
  <h2>Posts - Category: Category Name</h2>
  <p>A short description about the category. You can also delete it.</p>
  <ul>
  <?php
  $category = get_category_by_slug('category-slug-one');
  $posts = get_posts(array('category' => $category->term_id, 'numberposts' => -1));
  $serial = 1;
  foreach ($posts as $post) {
    $link = get_permalink($post->ID);
    $title = $post->post_title;
    echo "<li>$serial. <a href='$link'>$title</a></li>";
    $serial++;
  }
  ?>
</ul>
  </div>
</section>
<section class="sitemap-posts category-wordpress">
  <div class="container">
  <h2>Posts - Category: Category Name</h2>
  <p>A short description about the category. You can also delete it.</p>
  <ul>
  <?php
  $category = get_category_by_slug('category-slug-2');
  $posts = get_posts(array('category' => $category->term_id, 'numberposts' => -1));
  $serial = 1;
  foreach ($posts as $post) {
    $link = get_permalink($post->ID);
    $title = $post->post_title;
    echo "<li>$serial. <a href='$link'>$title</a></li>";
    $serial++;
  }
  ?>
</ul>
  </div>
</section>
<section class="sitemap-posts category-freelancing">
  <div class="container">
  <h2>Posts - Category: Category Name</h2>
  <p>A short description about the category. You can also delete it.</p>
  <ul>
  <?php
  $category = get_category_by_slug('category-slug-three');
  $posts = get_posts(array('category' => $category->term_id, 'numberposts' => -1));
  $serial = 1;
  foreach ($posts as $post) {
    $link = get_permalink($post->ID);
    $title = $post->post_title;
    echo "<li>$serial. <a href='$link'>$title</a></li>";
    $serial++;
  }
  ?>
</ul>
  </div>
</section>
<?php get_footer(); ?>

As mentioned earlier, replace the category slug/names with your actual categories. In this template, I have three categories. If you have less than three, remove the unnecessary category blocks. If you have more than three, copy & paste any existing block.

In this template, I have the following category slugs that you have to replace:

After you click any of your categories, you will find its slug on the URL.

Also, change the category name in the <h2> tag that is currently referred to as “Posts – Category: Category Name.”

Lastly, you have the option to write a little description about each category. Feel free to use or delete it. You’ll find it underneath each <h2> tag.

Create the actual sitemap page in your WordPress dashboard

Navigate to “Pages – Create New” to create a new page. Name the page “Sitemap and make sure the URL of the sitemap looks the same as this example: https://your-website.com/sitemap

The slug of your new sitemap page has to match with “sitemap”, otherwise, it will use the default template file for example “page.php.”

After you publish the page, you will see the new sitemap page includes all the pages (including the child pages with hierarchy) and posts (grouped by categories).

That’s it! This is how you can create an HTML sitemap page without any plugins.

What actually is an HTML sitemap?

One last thing I want to point out here. This HTML sitemap is different than the “sitemap.xml” which you create or generate for search engines or web crawlers or Google Search Console.

This HTML sitemap which I am referring to is human-readable and created especially for humans (and also for search engines).

In Google Search Central Blog, they said-

An HTML sitemap is intended for users of your site. Generally, this type of sitemap provides links to the pages in your site, and may provide descriptions of those pages.

Vanessa Fox, Google Search Central Blog
Google search central blog post highlighted sentences about HTML sitemap
Highlighted part in Google search central blog post about HTML sitemap

I hope this makes sense. Now create the sitemap for your WordPress website.

Conclusion

Now you know how to create an HTML sitemap page for your WordPress website and without any plugins. This sitemap may be a little hard to set up for the first time (for some of you). But once you made the implementation, you’re all set for the future. All the old and new pages & posts will be automatically added to the right spot (under the right category).