0

I noticed in Google Search Console that pages are increasingly getting removed from the index due to their canonical. For some reason — it points to the home page for some articles.

After some digging, I found out that the canonical is essentially derived from the permalink stored in the wp_yoast_indexable table. It's this line from the plugin's source:

    public function find_by_id_and_type( $object_id, $object_type, $auto_create = true ) {
        $indexable = $this->query()
            ->where( 'object_id', $object_id )
            ->where( 'object_type', $object_type )
            ->find_one();
        // ...

It pulls out the object from the database and if I run execute $indexable->permalink, I get "/".

I opened the table in phpMyAdmin and the record indeed had permalink set to / there. Other posts had normal permalinks. So it seems that the database was messed up by something.

The actual WordPress post does not have a custom permalink. However, if I set one and remove it — the record in the database is refreshed, the permalink in wp_yoast_indexable is no longer /, and the canonical is as expected.

Do you have an idea what could have possibly set the permalinks to /?

1 Answer 1

1

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='/';
SQL;

$result = $wpdb->get_results($query, ARRAY_A);
$ids = array_column($result, 'object_id');

foreach ($ids as $id) {
    wp_update_post(['ID' => $id]);
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.