I noticed that all problematic posts had their wp_yoast_indexable
row updated a few months ago which exactly matched with when I ran a script to update all existing posts. It was something like this:
$posts = get_posts($args);
foreach ($posts as $i => $post) {
$post_data = array(
'ID' => $post->ID,
// other stuff
);
wp_update_post($post_data);
}
The problem was that I ran the script from the CLI, where $_SERVER['HTTP_HOST']
is not set.
Apparently, when you run wp_update_post()
, Yoast SEO runs and updates its own tables. If HTTP_HOST
is missing, the updated permalink turns to something like http:///the-post-slug/
. That’s what I saw in the debugger. My guess is that it gets sanitized at some point and finally turns to /
.
To fix this, all I had to do was to run an empty wp_update_post()
on all problematic posts while HTTP_HOST
is set:
<?php
$_SERVER['HTTP_HOST'] = 'example.com';
require '/opt/bitnami/wordpress/wp-load.php';
global $wpdb;
$query = <<<SQL
SELECT object_id
FROM wp_yoast_indexable
WHERE permalink="https://wordpress.stackexchange.com/";
SQL;
$result = $wpdb->get_results($query, ARRAY_A);
$ids = array_column($result, 'object_id');
foreach ($ids as $id) {
wp_update_post(['ID' => $id]);
}