Code Snippets to Customize WordPress Sitemaps (Complete Guide)
By now most have heard about the WP Sitemaps feature introduced in WordPress version 5.5. From what I’ve read most existing sites that needed a sitemap already had one via one of the many free sitemap plugins. But for new WordPress sites going forward, having all the sitemap code in the WordPress core now means that new sites have the option of rolling with the default WordPress sitemaps, or use a dedicated plugin to do the job. This post is aimed at folks using the WordPress sitemaps, and shows how to customize the output however is required.
Contents
- Why customize sitemaps?
- Before diving in..
- Default sitemap functionality
- Code snippets to customize sitemaps
- Disable all WP sitemaps completely
- Disable the users sitemap
- Disable post-type sitemap
- Disable taxonomy sitemap
- Exclude specific pages from sitemap
- Exclude specific posts from sitemap
- Exclude posts based on meta fields
- Bonus: Check if WP Sitemaps are enabled
- Bonus: Exclude sitemap rule from robots.txt
- Something at the end
Why customize sitemaps?
For those going with the sitemaps provided by WordPress, you may find that some customization is required to suit your site’s specific needs. Some reasons why you may want to customize your the default, one-size-fits-all WP Sitemaps:
Tighten security
By default, WordPress sitemaps display usernames of every user who is the author of any post, page, or custom post type. Yes really. It happens because of the way that WordPress includes the username in author archive URLs. For example here is my own author archive link at Perishable Press:
https://perishablepress.com/author/perish/
Where “perish” is the username originally registered for my WP profile. And so now as of WP 5.5, that URL (and username) is included in the sitemap by default. This is true for all WordPress sites running version 5.5 and better. The usernames of all post authors are included and publicly available via WP Sitemaps.
// Example of user sitemap
https://example.com/author/jane-doe/
https://example.com/author/john-joe/
https://example.com/author/sallymcsally/
https://example.com/author/pat-somebody/
.
.
.
// For all users who are post authors..
For some sites this is not a big deal. But for many other sites, username sitemaps may be considered a bit of a security risk. Why? Because they enable bad actors to obtain all of that juicy username information, which can then be used to fashion all sorts of nefarious attacks (e.g., phishing, brute-force login attempts, etc.). As explained in my video course on securing WordPress, limiting exposure of sensitive information (like usernames) greatly improves site security.
Improve SEO
Improving SEO is another good reason to customize your sitemap. For example, many e-commerce sites make use of all sorts of action-specific pages. Like the checkout page, payment-success page, payment-failure page, members pages, error pages, and other dynamic pages that don’t really do anything or display any content unless the user is taking some context-specific action (like making a purchase).
Here is an example of a payment-success page from my pro-plugin site Plugin Planet, basically an empty page unless you are making a purchase. You don’t want to include those types of pages in your sitemap, as they are useless and make no sense to typical site visitors, bots, and so forth. By excluding such pages from your sitemap, you help to avoid “thin” content and “soft 404” errors encountered by the search engines.
Keep sitemaps focused
Another reason to customize sitemaps is to minimize redundancy and keep things as focused as possible. Send a clear, strong signal on all fronts. Even the sitemap.
For example, at my found-images site, I exclude the category archive link from the sitemap. At that site, all posts are categorized as “Uncategorized” because I use only tags to organize content. And so it doesn’t make sense for the sitemap to include a link to the category archive, because it contains all the same posts that are included via the “posts” sitemap and collective “tags” sitemaps.
So for that site, excluding the category sitemap helps to minimize redundancy and keep things as focused as possible.
Bottom line
There are many reasons why you may want to customize the output of your WordPress-generated sitemaps. In general, the one-size-fits-all sitemaps generated by WordPress may not suit your site’s security and SEO goals. With a little customizing, you can tighten security, focus link equity, and keep things optimized. This post shows you how to do it using some choice code snippets. All very easy to implement with little to no editing required.
Before diving in..
This post is all about customizing the automatic sitemap feature introduced in WordPress 5.5. Most people probably will use a plugin for this, many SEO plugins now integrate nicely with WordPress Sitemaps and offer options for customizing and so forth. If that’s not the case, somebody let me know and I’ll build a plugin that can do it, or maybe integrate some options into my free plugin, Disable WP Sitemaps.
So that’s why we’re here: to use some simple code snippets to customize the output of WordPress Sitemaps. If you’re not familiar with the sitemaps feature, check out this article to learn more about it.
Default sitemap functionality
Currently, by default the WP Sitemap generates sitemaps for any/all of the following items (if they exist):
- Users (includes links to author-archive view for all post authors)
- Post Types (including Posts, Pages, and any other public Custom Post Types)
- Taxonomies (Including Categories, Tags, and any Custom Taxonomies)
This post explains how to exclude each of these sitemaps as needed. It also shows you how to exclude specific users, post types, and taxonomies. So basically you can customize just about anything using some easy copy/paste code snippets.
Code snippets to customize sitemaps
Now let’s get into some code. Below you will find copy/paste code examples, useful for customizing WordPress sitemaps (available in WP version 5.5 and better). To make things easier, here is a quick-jump menu:
- Disable all WP sitemaps completely
- Disable the users sitemap
- Disable post-type sitemap
- Disable taxonomy sitemap
- Exclude specific pages from sitemap
- Exclude specific posts from sitemap
- Exclude posts based on meta fields
- Bonus: Check if WP Sitemaps are enabled
- Bonus: Exclude sitemap rule from robots.txt
Disable all WP sitemaps completely
I wrote a plugin to disable WP Sitemaps completely. You can learn more and download at the WP Plugin Directory. The plugin is very simple and includes only one line of code.
So you can use the plugin to disable all sitemaps, or you can add the same line of code to your theme template, or even better child theme, via the functions.php
file. Here is the magic snippet:
add_filter('wp_sitemaps_enabled', '__return_false');
All we’re doing here is returning a value of false
to the filter hook, wp_sitemaps_enabled
. It’s simple by design, one of the things that makes WP so easy to customize and make your own.
Older version of the code
If you see this code in a tutorial somewhere, it may work but from what I understand it’s from an older version.
remove_action('init', 'wp_sitemaps_get_server');
Don’t use that code, instead use the latest recommended technique described above. It is included here only for completeness.
Disable the users sitemap
As explained in the rambling Why Customize? section above, for most sites it’s probably a good idea to exclude/disable the entire users sitemap to help improve security. Here is the plug-&-play code to make it happen:
// disable users sitemap
function shapeSpace_disable_sitemap_users($provider, $name) {
return ($name == 'users') ? false : $provider;
}
add_filter('wp_sitemaps_add_provider', 'shapeSpace_disable_sitemap_users', 10, 2);
No editing is required for this snippet. Simply add to your WordPress theme functions and done.
Disable post-type sitemap
By default, the WordPress sitemap includes sitemaps for each of your (non-empty) post types. So for typical WordPress sites this means that your sitemap will include links to the following sitemaps:
URL
https://example.com/wp-sitemap-posts-post-1.xml
https://example.com/wp-sitemap-posts-page-1.xml
.
.
As well as any custom post types:
.
.
https://example.com/wp-sitemap-posts-movie-1.xml
https://example.com/wp-sitemap-posts-book-1.xml
.
.
So to exclude any of the “post” type sitemaps, add the following code to your theme (or simple plugin):
// disable post type sitemap
function shapeSpace_disable_sitemap_post_types($post_types) {
unset($post_types['page']); // can be post, page, or any post type
return $post_types;
}
add_filter('wp_sitemaps_post_types', 'shapeSpace_disable_sitemap_post_types');
As written, that code disables the page
post type. So you can change that to whichever post type you would like to exclude. Just replace the page
with the name of your post type (e.g., post
, movie
, book
, etc.). Save changes and done.
Disable taxonomy sitemap
By default, the WordPress sitemap includes sitemaps for each of your (non-empty) taxonomies. For typical WordPress sites this means that your sitemap will include links to the following sitemaps:
URL
.
.
https://example.com/wp-sitemap-taxonomies-category-1.xml
https://example.com/wp-sitemap-taxonomies-post_tag-1.xml
As well as any custom taxonomies:
.
.
https://example.com/wp-sitemap-taxonomies-color-1.xml
https://example.com/wp-sitemap-taxonomies-shape-1.xml
.
.
So to exclude any of the “taxonomy” sitemaps, add the following code to your theme (or simple plugin):
// disable taxonomy sitemap
function shapeSpace_disable_sitemap_taxonomy($taxonomies) {
unset($taxonomies['post_tag']); // can be post_tag, category, post_format, or any taxonomy
return $taxonomies;
}
add_filter('wp_sitemaps_taxonomies', 'shapeSpace_disable_sitemap_taxonomy');
As written, that code disables the post_tag
taxonomy. So you can change that to whichever taxonomy you would like to exclude. Just replace the post_tag
with the name of your taxonomy (e.g., category
, post_format
, color
, book
, etc.). Save changes and done.
Exclude specific pages from sitemap
To exclude specific pages from the WordPress sitemap, apply the following code technique:
// disable specific page
function shapeSpace_disable_sitemap_specific_page($args, $post_type) {
if ('page' !== $post_type) return $args;
$args['post__not_in'] = isset($args['post__not_in']) ? $args['post__not_in'] : array();
$args['post__not_in'][] = 2; // exclude page with ID = 2
return $args;
}
add_filter('wp_sitemaps_posts_query_args', 'shapeSpace_disable_sitemap_specific_page', 10, 2);
Notice the first line within the function, where it checks if the $post_type
is page
. This tells the function not to do anything unless the current post type is “page”. So to exclude posts from other post types, change page
to the name of whatever post type you are targeting.
The second line within the function checks to make sure the post__not_in
variable is set. Then the third line is where the action happens. As written the code is excluding the page with ID equal to 2. So you can change that ID to whatever page ID you want to exclude from the sitemaps.
To exclude multiple pages, the above technique would be the same, but with addition of more “exclude” lines:
// disable specific pages
function shapeSpace_disable_sitemap_specific_pages($args, $post_type) {
if ('page' !== $post_type) return $args;
$args['post__not_in'] = isset($args['post__not_in']) ? $args['post__not_in'] : array();
$args['post__not_in'][] = 2; // exclude page with ID = 2
$args['post__not_in'][] = 3; // exclude page with ID = 3
$args['post__not_in'][] = 4; // exclude page with ID = 4
$args['post__not_in'][] = 5; // exclude page with ID = 5
$args['post__not_in'][] = 6; // exclude page with ID = 6
return $args;
}
add_filter('wp_sitemaps_posts_query_args', 'shapeSpace_disable_sitemap_specific_pages', 10, 2);
There may be a shorter way of writing this, but I’m presenting it as-is for clarity.
Exclude specific posts from sitemap
Similar to the previous technique, to exclude a specific post from the automatically generated WordPress sitemaps:
// disable specific post
function shapeSpace_disable_sitemap_specific_post($args, $post_type) {
if ('post' !== $post_type) return $args;
$args['post__not_in'] = isset($args['post__not_in']) ? $args['post__not_in'] : array();
$args['post__not_in'][] = 1; // exclude post with ID = 1
return $args;
}
add_filter('wp_sitemaps_posts_query_args', 'shapeSpace_disable_sitemap_specific_post', 10, 2);
Same deal as before. Only here notice in the first line within the function that we are checking if the $post_type
is equal to post
. Then the magic happens in the third line, where we are excluding the post with ID equal to 1 (the famous “Hello World” post). So change that ID to whatever post you want to exclude and done.
To exclude multiple posts, the above technique would be the same, but with addition of more “exclude” lines:
// disable specific posts
function shapeSpace_disable_sitemap_specific_posts($args, $post_type) {
if ('post' !== $post_type) return $args;
$args['post__not_in'] = isset($args['post__not_in']) ? $args['post__not_in'] : array();
$args['post__not_in'][] = 1; // exclude post with ID = 1
$args['post__not_in'][] = 2; // exclude post with ID = 2
$args['post__not_in'][] = 3; // exclude post with ID = 3
$args['post__not_in'][] = 4; // exclude post with ID = 4
$args['post__not_in'][] = 5; // exclude post with ID = 5
return $args;
}
add_filter('wp_sitemaps_posts_query_args', 'shapeSpace_disable_sitemap_specific_posts', 10, 2);
It’s all very straightforward, thanks to the core WordPress developers who give us a very flexible API that is east to customize. Thank you core devs!
Exclude posts based on meta fields
It’s also possible to exclude specific posts based on its attached meta data. For example, if your posts have a meta field named sitemap
. And you want to include only posts for which sitemap
value is 1
. Add the following code to make it happen:
// disable post based on meta field
function shapeSpace_disable_sitemap_post_meta($args, $post_type) {
if ('post' !== $post_type) return $args; // can be any post type
$args['meta_query'] = isset($args['meta_query']) ? $args['meta_query'] : array();
$args['meta_query'][] = array(
'key' => 'sitemap', // can be any meta key
'value' => '1', // can be any meta value
'compare' => '=', // can use any comparison
);
return $args;
}
add_filter('wp_sitemaps_posts_query_args', 'shapeSpace_disable_sitemap_post_meta', 10, 2);
For this technique we again are using the wp_sitemaps_posts_query_args
filter hook. The technique can be modified to match virtually any set of posts. Check out the Meta API to get a better idea of what’s possible. Powerful stuff.
Bonus: Check if WP Sitemaps are enabled
As explained earlier, WordPress makes it easy to disable/enable its sitemaps feature. So if you are customizing things, it may be useful to know if WP Sitemaps are enabled on the site. Here is the code to do it:
if (wp_sitemaps_get_server()->sitemaps_enabled()) {
// sitemaps enabled
} else {
// sitemaps not enabled
}
This code uses wp_sitemaps_get_server() to call the sitemaps_enabled
method, which returns a value of true
if sitemaps are enabled, or false
if not. Learn more about WP_Sitemaps at WordPress.org.
Bonus: Exclude sitemap rule from robots.txt
When sitemaps are enabled, WordPress automatically adds the following rule to your site’s virtual dynamically generated robots.txt file:
Sitemap: https://example.com/wp-sitemap.xml
That line tells search engines and bots where to find your sitemap and is a good thing. But there are reasons why you would want to customize the robots sitemap rule or even disable it completely. So if you need to do it, here is the code to exclude the sitemap rule from robots.txt
:
// do not add sitemap rule to robots.txt
function shapeSpace_disable_sitemap_robots($wp_sitemaps) {
remove_filter('robots_txt', array($wp_sitemaps, 'add_robots'));
}
add_action('wp_sitemaps_init', 'shapeSpace_disable_sitemap_robots');
No changes are necessary, simply grab, gulp and go. As to be expected, the wp_sitemaps_init hook fires when the Sitemaps object is initialized. Good times.
Something at the end
In the tradition of concluding substantial posts with some sort of conclusion, here it is. I trust the article is self-explanatory, and that you’ll let me know if any questions or feedback. You can do so via the comments below (if they are open when you read this), or can always send an email. As always thanks for reading :)
Also: here is the site’s current sitemap.
2 responses to “Code Snippets to Customize WordPress Sitemaps (Complete Guide)”
Thank you for expanding on this and providing an explanation for what the code is doing. I found this while trying to figure out how to exclude specific pages from the sitemap. Thought I’d share the shorter way to exclude multiple pages from the sitemap.
You could declare the
$args[ 'post__not_in' ]
variable like so, instead of adding each one on a different line.Nice! Thank you :)