How to add a sitemap of your Pod Page to WordPress Yoast SEO

Usually if you wanted to add Pods pages to your sitemaps, you would add the Pods SEO plugin. But that recently stopped working with Yoast, due to Yoast's changes in the admin structure ( With sitemap configuration admin pages missing, the pods plugin had nowhere to show the options any longer )

So the next best thing was to just quickly create our own sitemap rules programmatically. Let's say we have a pod called cars and to access it, people can go to yourblogname.com/cars/{@permalink}.

Now when we go to yourblogname.com/sitemap.xml we want to not only see posts, pages, tags, categories, but also our cars section listed. And when you click on cars-sitemap.xml we want all cars listed there as well, with their image, and the last modification time.

The search for a solution was a long one in the start, as the general yoast kb entry only tells us about the filters that limit the number of items per page, or remove items from the sitemap – but we want to add our own sitemap to Yoast SEO.

There is a vague entry that we can add an external sitemap by using the wpseo_sitemap_index filter, but that's also not very helpful, as we want to generate the code for it – not just point to an existing file.

But it puts us on the right track of searching for examples based on wpseo_sitemap_index and eventually you would find this great gist from mohandere which tells you how to add a sitemap for a custom post type.

It's slightly outdated with pointers by other people in the comments, and in our case we don't need the WordPress Queries as we want to work with pods.

So here's the few changes we need to make to adjust it to our own use-case :

  • In the end we remove most of the custom logic, and just change it to Pods
  • Change the outdated method calls to the new method names
  • Move the filter priority to the end, so it wouldn't get overwritten by e.g. Pods SEO ( that was a big case that had me stumbling, as our sitemap data was seemingly ignored by wpseo_sitemap_index )
  • Make the sitemap header work with images

You could add this code to the functions.php file of your (child-)theme, or if you like to keep it clean, then save this as your_podname_sitemap.php in your theme directory, and then add a include('your_podname_sitemap.php'); inside the functions.php file.

We're assuming here that your cars pod has a modified field, which we can sort by, and that it has a picture field, which has one image attached to it.

<?php
/**
 *  Creates a new custom yoast seo sitemap based on your pod
 */

// only use this during development to disable sitemap caching :
// add_filter( 'wpseo_enable_xml_sitemap_transient_caching', '__return_false');

add_filter( 'wpseo_sitemap_index', 'add_cars_sitemap_to_index', 99 );
add_action( 'init', 'add_cars_sitemap_to_wpseo' );

// Add custom index
function add_cars_sitemap_to_index($smp){
    global $wpseo_sitemaps;

    $car = pods('cars', array("orderby" => "modified DESC", "limit" => 1));
    $date = $car->field('modified');

    $smp .= '<sitemap>' . PHP_EOL;
    $smp .= '<loc>' . site_url() .'/cars-sitemap.xml</loc>' . PHP_EOL;
    $smp .= '<lastmod>' . htmlspecialchars( $date ) . '</lastmod>' . PHP_EOL;
    $smp .= '</sitemap>' . PHP_EOL;

    return $smp;
}

function add_cars_sitemap_to_wpseo(){
    add_action( "wpseo_do_sitemap_car", 'generate_cars_sitemap');
}

function generate_cars_sitemap(){

    global $wpseo_sitemaps;

    $car = pods('cars', array("orderby" => "modified DESC", "limit" => -1) );

    $output = '';
    if( $car->total() > 0 ){

        $chf = 'weekly';
        $pri = 1.0;

        while ( $car->fetch() ) {
            $url = array();
            $url['mod'] = $car->field('modified');
            $url['loc'] = site_url() . '/car/' . $car->field('permalink');
            $url['chf'] = $chf;
            $url['pri'] = $pri;
            $image = [];
            if($car->field('picture.guid')) {
                $image["src"] = $car->field('picture.guid');
                $image["title"] = $car->field('name');
            }
            $url['images'] = [$image];
            $output .= $wpseo_sitemaps->renderer->sitemap_url( $url );
        }
    }

    //Build the full sitemap
    $sitemap  = '<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd http://www.google.com/schemas/sitemap-image/1.1 http://www.google.com/schemas/sitemap-image/1.1/sitemap-image.xsd" xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . PHP_EOL;
    $sitemap .= $output . '</urlset>';

    $wpseo_sitemaps->set_sitemap($sitemap);

}

/*********************************************************
 *  OR we can use $wpseo_sitemaps->register_sitemap( 'car', 'METHOD' );
 ********************************************************/

add_action( 'init', 'register_cars_sitemap', 99 );
/**
 * On init, run the function that will register our new sitemap as well
 * as the function that will be used to generate the XML. This creates an
 * action that we can hook into built around the new
 * sitemap name - 'wp_seo_do_sitemap_*'
 */
function register_cars_sitemap() {
    global $wpseo_sitemaps;
    if($wpseo_sitemaps) {
        $wpseo_sitemaps->register_sitemap( 'cars', 'generate_cars_sitemap' );
    }
}

add_action( 'init', 'init_do_sitemap_actions' );

function init_do_sitemap_actions(){
    add_action( 'wp_seo_do_sitemap_cars', 'generate_cars_sitemap' );
}

Make sure to clear your cache when testing your sitemaps. Now you should have your sitemap category listed when going to yoursite.com/sitemap.xml, and you should also have a yoursite.com/cars-sitemap.xml which would list all your items.