Spring Sale! Save 30% on all books w/ code: PLANET24
Web Dev + WordPress + Security

Code Snippets to Customize WordPress Sitemaps (Complete Guide)

Code Snippets for WP Sitemaps

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.

Just here for snippets? Skip the lengthy discussion and jump to the code snippets.

Contents

Disable Sitemaps? If you want to use a dedicated plugin for sitemaps, or use the sitemap functionality provided by one of your existing plugins (like an SEO plugin for example), then you should disable the new WordPress sitemap feature, to avoid issues with duplicate sitemaps. To do it, you can use the code technique provided below, or just grab the free disable sitemap plugin (by yours truly).

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:

Return to main menu ↑

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.

Note: If you update the WordPress General settings to discourage search engines from indexing your site, sitemaps will be disabled automatically. So in that case, there is no need to use any plugin or code to disable. WordPress is smart and takes care of it for you.

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.

Important: All of this sitemaps functionality is available ONLY in WordPress 5.5 and beyond. So if you are developing for any plugin or theme, make sure to use conditional checks and suitable fallbacks for any older WP versions.

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.

Note: the robots.txt sitemap rule is *not* added when search engines are “discouraged” from visiting the site (as determined by WP General setting “Search engine visibility”). So the above code is not needed when that setting is enabled.

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.

Update: New redirection technique for WP Sitemaps, added to my tutorial, Bulletproof Sitemap Redirects via .htaccess.

About the Author
Jeff Starr = Designer. Developer. Producer. Writer. Editor. Etc.
Banhammer: Protect your WordPress site against threats.

2 responses to “Code Snippets to Customize WordPress Sitemaps (Complete Guide)”

  1. 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.

    $args[ 'post__not_in' ] = array( 1, 2, 3 );
Comments are closed for this post. Something to add? Let me know.
Welcome
Perishable Press is operated by Jeff Starr, a professional web developer and book author with two decades of experience. Here you will find posts about web development, WordPress, security, and more »
The Tao of WordPress: Master the art of WordPress.
Thoughts
I live right next door to the absolute loudest car in town. And the owner loves to drive it.
8G Firewall now out of beta testing, ready for use on production sites.
It's all about that ad revenue baby.
Note to self: encrypting 500 GB of data on my iMac takes around 8 hours.
Getting back into things after a bit of a break. Currently 7° F outside. Chillz.
2024 is going to make 2020 look like a vacation. Prepare accordingly.
First snow of the year :)
Newsletter
Get news, updates, deals & tips via email.
Email kept private. Easy unsubscribe anytime.