Skip to content

Instantly share code, notes, and snippets.

@jordanmaslyn
Created January 6, 2022 23:33
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jordanmaslyn/7e28423ef43cdb6af068f5f192077746 to your computer and use it in GitHub Desktop.
Save jordanmaslyn/7e28423ef43cdb6af068f5f192077746 to your computer and use it in GitHub Desktop.
Fix Yoast sitemaps when working with headless WP
<?php
/*
* Replacing domain for rest api requests from Gutenberg editor if youre using
* WP headless and WP_SITEURL & WP_HOME are not the same domain
* (has nothing to do with yoast)
*/
add_filter('rest_url', function($url) {
$url = str_replace(home_url(), site_url(), $url);
return $url;
});
/*
* Replacing domain for stylesheet to xml if youre using WP headless
* and WP_SITEURL & WP_HOME are not the same domain
*/
function filter_wpseo_stylesheet_url( $stylesheet ) {
$home = parse_url(home_url());
$site = parse_url(site_url());
return str_replace($home, $site, $stylesheet);
};
add_filter( 'wpseo_stylesheet_url', 'filter_wpseo_stylesheet_url', 10, 1 );
@jordanmaslyn
Copy link
Author

When using the snippet above, you should visit /wp-admin/options-general.php in your WP dashboard, and change the Site Address (URL) to be the url of your front-end (e.g. http://localhost:3000 if developing locally).

@jordanmaslyn
Copy link
Author

If you are only providing the sitemap_index on your front-end and leaving the remaining generated sitemaps at the WP install, you can also use the following snippet. If you are providing all of the sitemaps through your front-end (using the same filenames generated by Yoast), the original Gist should be sufficient.

/*
 * Replacing domain for sitemap index if youre using WP headless 
 * and WP_SITEURL & WP_HOME are not the same domain
 */
function filter_wpseo_sitemap_index_links( $links ) {
  $home = parse_url(get_option('home'));
  $site = parse_url(get_option('siteurl'));
  foreach($links as $i => $link)
    $links[$i]['loc'] = str_replace($home, $site, $link['loc']);
  return $links; 
}; 
add_filter( 'wpseo_sitemap_index_links', 'filter_wpseo_sitemap_index_links', 10, 1 );

@danielenriquehoward
Copy link

danielenriquehoward commented Jan 7, 2022

@jordanmaslyn

I ran into some trouble setting the site url since we are using a multisite and its not available at /wp-admin/options-general.php. i had to change in DB, wp_options table. I changed siteurl to localhost and lost all styling in the wp backend, but then I saw this in the thread you got this solution from WP_SITEURL = Wordpress admin, WP_HOME = frontend. So I changed homeurl instead, which was ok, but then I had to change str_replace($home, $site, $stylesheet) to str_replace($site, $home, $stylesheet)

This is working for me now with the following

/*
 * Replacing domain for rest api requests from Gutenberg editor if youre using
 * WP headless and WP_SITEURL & WP_HOME are not the same domain
 * (has nothing to do with yoast)
 */
add_filter('rest_url', function($url) {
    $home = home_url();
    $site = site_url();
    $url = str_replace($site, $home, $url);
    return $url;
  });
  
  /*
   * Replacing domain for stylesheet to xml if youre using WP headless 
   * and WP_SITEURL & WP_HOME are not the same domain
   */
  function filter_wpseo_stylesheet_url( $stylesheet ) {
    $home = parse_url(get_option('home'));
    $site = parse_url(get_option('siteurl'));
    $filtered_url = str_replace($site, $home, $stylesheet);

    return $filtered_url;
  }; 
  add_filter( 'wpseo_stylesheet_url', 'filter_wpseo_stylesheet_url', 10, 1 );

However, in the course of figuring out I could just change the home url, I found this other solution:
Yoast/wordpress-seo#13603 (comment)

which I modified slightly to the following:

// add this filter if we are making sitemap for posts
add_filter('wpseo_build_sitemap_post_type', function ($type) {
    
    add_filter('home_url', 'set_frontend_url', 10, 2);

    return $type;
}, 10, 2);

// set home url to front end url, but only when we are making sitemap for posts
function set_frontend_url($url, $path)
{
    $faust_settings = get_option( 'faustwp_settings', array() );
    $replacementUrl = $faust_settings['frontend_uri'];
    if (empty($path) && is_class_function_in_call_stack('WPSEO_Post_Type_Sitemap_Provider', ['get_sitemap_links', 'get_parsed_home_url'])) {
        
        $home = home_url();
        return str_replace($home, $replacementUrl, $url);
    }

    return $url;
}

function is_class_function_in_call_stack($class_name, $function_names)
{
    foreach (debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 12) as $debug_backtrace) {
        if (isset($debug_backtrace['class']) && $debug_backtrace['class'] === $class_name && in_array($debug_backtrace['function'], $function_names)) {
            return true;
        }
    }

    return false;
}

but i was wondering what your thoughts are on this solution? I worry somewhat about the effect of changing the home_url for other plugins, so I thought this could perhaps be safer.

@jordanmaslyn
Copy link
Author

@danielenriquehoward Ah yes, WP's naming scheme between site and home URLs can be very confusing. I do wish they'd make that clearer, but alas, after being this way for so long, I am not hopeful about them changing it now.

As for which approach to take, I personally feel more confident about updating home_url and filtering the rest_url accordingly. Namely because it is a semantic use of that field, secondly we can see Automattic themselves take the same approach here : https://github.com/Automattic/vip-decoupled-bundle/blob/5b3bb95d7540893c8039fb14fc62ee583305274e/urls/urls.php, and thirdly because having to recur through a callstack feels MUCH more "hacky" to me personally. Ultimately though, go with the approach you feel more comfortable with.

@danielenriquehoward
Copy link

@jordanmaslyn

I see your point. Will update home_url, thanks for your help.

@danielenriquehoward
Copy link

Note: if you use migrateDB pro, changing home_url will break the default rewrites and then your .local will be redirected to .com backend. To fix, just add a custom rewrite rule.

@sbnoman01
Copy link

Hi, I'm facing one issue.
when i changed the Site address URL to the frontend url, My WordPress application stopped working properly, like i can't login or if i login then i can't log out, The issue i noticed. WordPress Login form action is set to the WordPress application URL. In this case what i can do.

@jordanmaslyn
Copy link
Author

jordanmaslyn commented Nov 30, 2023

@sbnoman01 Hmmm, I have not seen that behavior before. It sounds like you may have changed the wrong URL setting. If doing it from the WP Admin dashboard, make sure you are changing the setting titled "Site Address (URL)" or if you are changing it in code/the database, make sure you are changing home_url (not site_url). With that change and the rest_url filter above, you should be A-OK logging in and out of the WordPress dashboard like normal.

In the admin, "WordPress Address (URL)" and in code/database site_url should always reflect the URL to your WordPress installation.

@sbnoman01
Copy link

Hi @jordanmaslyn Thank you for your response, Basically, i changed "Site Address (URL)" from wp-admin/options-general.php then everything looks good but when I try to log in from any other browser or try to logout from right top corner it redirects me to the Frontend url with the required parameters.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment