SEO & Digital Marketing Consultant » Technical » How to Build a Custom XML Sitemap in WordPress

How to Build a Custom XML Sitemap in WordPress

WordPress Custom Sitemap

XML sitemaps are important for SEO, it’s like feeding a baby with a spoon full of food and Google’s the baby… They give their spiders a list of pages to crawl and it helps them understand your architecture and index content/URLs.

There are plugins out there such as Yoast SEO that can generate them automatically but there might be certain cases where you need to build a custom sitemap. For example, you might have hosting restrictions, specific URL requirements, or using a reverse proxy.

This guide explains how to create a custom XML sitemap in WordPress particulary for a reverse proxy use case but can be adapted for other cases too…


Step 1: Intercept Sitemap Requests

Intercept requests for custom sitemap URLs (e.g., /custom-sitemap_index.xml) and generate the required XML directly. Use the init hook to catch the requests early.

add_action('init', function () {
    if (isset($_SERVER['REQUEST_URI'])) {
        $custom_sitemaps = [
            '/custom-sitemap_index.xml' => 'index',
            '/custom-post-sitemap.xml' => 'post',
            '/custom-page-sitemap.xml' => 'page',
            '/custom-category-sitemap.xml' => 'category',
            '/custom-author-sitemap.xml' => 'author',
        ];

        foreach ($custom_sitemaps as $path => $type) {
            if (strpos($_SERVER['REQUEST_URI'], $path) === 0) {
                if ($type === 'index') {
                    generate_custom_sitemap_index();
                } else {
                    generate_custom_sitemap($type);
                }
                exit;
            }
        }
    }
});

This ensures WordPress processes the correct XML before default templates or redirects interfere.


Step 2: Generate the Sitemap Index

The sitemap index acts as a directory for individual content sitemaps (e.g., posts, pages, categories).

function generate_custom_sitemap_index() {
    $sitemaps = [
        'custom-post-sitemap.xml' => '2025-01-31T15:44:00+00:00',
        'custom-page-sitemap.xml' => '2024-12-27T14:33:00+00:00',
        'custom-category-sitemap.xml' => '2025-01-31T15:44:00+00:00',
        'custom-author-sitemap.xml' => '2025-01-27T15:53:00+00:00',
    ];

    header('Content-Type: application/xml; charset=utf-8');
    echo '<?xml version="1.0" encoding="UTF-8"?>';
    echo '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';

    foreach ($sitemaps as $slug => $lastmod) {
        $url = site_url($slug);  
        echo "<sitemap>";
        echo "<loc>$url</loc>";
        echo "<lastmod>$lastmod</lastmod>";
        echo "</sitemap>";
    }

    echo '</sitemapindex>';
    exit;
}

Step 3: Create Content-Specific Sitemaps

For each content type (e.g., posts, pages), generate a corresponding XML file. Replace the domain in URLs when needed, such as for reverse proxies.

function generate_custom_sitemap($type) {
    global $wpdb;

    header('Content-Type: application/xml; charset=utf-8');
    echo '<?xml version="1.0" encoding="UTF-8"?>';
    echo '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';

    $site_url = get_site_url();  

    switch ($type) {
        case 'post':
            $posts = $wpdb->get_results("SELECT ID, post_modified_gmt FROM {$wpdb->posts} WHERE post_status = 'publish' AND post_type = 'post'");
            foreach ($posts as $post) {
                $url = str_replace($site_url, 'https://proxy-domain.com', get_permalink($post->ID));
                $lastmod = gmdate('Y-m-d\TH:i:s+00:00', strtotime($post->post_modified_gmt));
                echo "<url><loc>$url</loc><lastmod>$lastmod</lastmod></url>";
            }
            break;

        case 'page':
            $pages = $wpdb->get_results("SELECT ID, post_modified_gmt FROM {$wpdb->posts} WHERE post_status = 'publish' AND post_type = 'page'");
            foreach ($pages as $page) {
                $url = str_replace($site_url, 'https://proxy-domain.com', get_permalink($page->ID));
                $lastmod = gmdate('Y-m-d\TH:i:s+00:00', strtotime($page->post_modified_gmt));
                echo "<url><loc>$url</loc><lastmod>$lastmod</lastmod></url>";
            }
            break;

        // Additional cases for categories and authors...
    }

    echo '</urlset>';
    exit;
}

Step 4: Prevent Trailing Slash Issues

To avoid WordPress redirecting sitemap URLs to versions with trailing slashes, disable canonical redirects for sitemap paths.

add_filter('redirect_canonical', function ($redirect_url, $requested_url) {
    $sitemap_paths = [
        'custom-sitemap_index.xml',
        'custom-post-sitemap.xml',
        'custom-page-sitemap.xml',
        'custom-category-sitemap.xml',
        'custom-author-sitemap.xml',
    ];

    foreach ($sitemap_paths as $path) {
        if (strpos($requested_url, $path) !== false) {
            return false; // Disable redirect
        }
    }

    return $redirect_url;
}, 10, 2);

Step 5: Add Rewrite Rules

Register custom rewrite rules to make WordPress recognise sitemap URLs.

function add_custom_sitemap_rewrite_rules() {
    add_rewrite_rule('^custom-sitemap_index\.xml$', 'index.php?custom_sitemap=index', 'top');
    add_rewrite_rule('^custom-post-sitemap\.xml$', 'index.php?custom_sitemap=custom-post-sitemap.xml', 'top');
    add_rewrite_rule('^custom-page-sitemap\.xml$', 'index.php?custom_sitemap=custom-page-sitemap.xml', 'top');
    add_rewrite_rule('^custom-category-sitemap\.xml$', 'index.php?custom_sitemap=custom-category-sitemap.xml', 'top');
    add_rewrite_rule('^custom-author-sitemap\.xml$', 'index.php?custom_sitemap=custom-author-sitemap.xml', 'top');
}
add_action('init', 'add_custom_sitemap_rewrite_rules');

Flush the rewrite rules after activation by visiting Settings > Permalinks and clicking Save Changes.


Testing

Once the plugin is activated, verify the following URLs:

  • /custom-sitemap_index.xml
  • /custom-post-sitemap.xml
  • /custom-page-sitemap.xml

Check the <loc> tags in the XML files to ensure the URLs are correct, especially if a reverse proxy is in use.

Straightforward. No fluff. Just XML sitemaps.




Leave a Reply

Your email address will not be published. Required fields are marked *

let’s collaborate.

From bespoke and user-centered SEO strategies, agile high-impact PPC campaign management, to a modern high-performance website-the list of options is limitless.

helpful SEO & digital marketing tips.

recent articles.

Read in-depth articles, guides and case studies to help you learn how to DIY (do it yourself).