Conflict between Custom 404 plugin and Yoast SEO with certain permalink settings

Hi!

I encountered a conflict between Themeco’s Custom 404 plugin and Yoast SEO. I’ve spent a few hours investigating it and found a few different workarounds. It seems like the conflict is due to a WordPress bug, or at least some WordPress behavior that I don’t understand. But I’m posting it here to see what you think. One of the workarounds involves a small change to the Custom 404 plugin’s behavior.

Steps to reproduce:

  1. Create a new WordPress site.
  2. Install Pro and Pro – Child Theme. Activate the latter.
  3. Install and activate Custom 404.
  4. Install and activate Yoast SEO.
  5. Create and configure a custom 404 page.
  6. Go to Settings > Permalinks > Common Settings. Choose Custom Structure. Set it to something like /blog/%postname%/.
  7. Try to visit a path that doesn’t match that structure, such as /asfgd789gua89g/.

Expected result:
The <title> tag on the 404 page contains title of the custom 404 page.

Actual result:
The <title> tag on the 404 page contains title of the most recent blog post.

Here’s what I found while investigating.

  • WordPress compares the requested path (for example, /asfgd789gua89g/) to a list of regular expressions generated by $wp_rewrite->wp_rewrite_rules(). (See wp-includes/class-wp.php line 227.)

  • The requested path doesn’t match any of the rules, so $this->query_vars['error'] gets set to the default $error value, which is '404'. (See wp-includes/class-wp.php lines 166 and 379.)

  • WordPress should know that it’s impossible to find the requested path, but it still calls $wp_query->get_posts() as usual while preparing its response. It ends up executing a query to find all $queried_post_types. By default, this is equal to array( 'post' ), so it does a query for all blog posts. (See wp-includes/class-wp-query.php line 2555.) This seems like a bug to me, but maybe there’s a reason for it? It then sets $wp_query->posts and $wp_query->post as usual. (See wp-includes/class-wp-query.php line 3326.)

    • If the path had matched one of the rewrite rules, but $wp_query->get_posts() hadn’t found a corresponding post in the database, $wp_query->posts would have been empty, and $wp_query->post would have been NULL.
  • The Custom 404 plugin replaces $post and some attributes of $wp_query with values appropriate for the 404 page. But notably, it does not change $wp_query->post. (See tco-custom-404/views/site/custom-404.php lines 46 through 56.)

  • Before Yoast SEO tries to get the SEO title, it calls wp_reset_query() “to ensure we actually have the current page”. (See wordpress-seo/src/memoizers/meta-tags-context-memoizer.php line 95.) This function calls $wp_query->reset_postdata(), which sets $GLOBALS['post'] = $this->post, but only if $this->post isn’t empty. (See wp-includes/class-wp-query.php line 4570.) So the title it fetches is the title of the original $wp_query->post result, not the 404 page specified by Custom 404.

Workarounds

Pick one:

  1. Change the Permalinks setting to Post Name so that arbitrary paths match a rewrite rule. (Not ideal because it changes the URLs of existing pages.)

  2. Add a posts_results filter that returns an empty array if $GLOBALS['wp_query']->query['error'] === '404'. (I haven’t tested this thoroughly for side-effects.)

  3. Add a line in tco-custom-404/views/site/custom-404.php that sets $wp_query->post equal to $post. This will prevent $wp_query->reset_postdata() from changing $GLOBALS['post'] to something other than the 404 page. (But is there a reason why you didn’t include this line in the first place?)

    • This workaround can also be accomplished by adding a 404_template filter that runs after tco_custom_404_filter_template() and sets $GLOBALS['wp_query']->post = $GLOBALS['post'].

Please let me know if you need any more information.

Thanks!

PHP 8.0.20
WordPress 6.0.1
Pro 5.1.5
Yoast SEO 19.5.1

1 Like

Hey @fundibu,

Thank you for reporting and providing instructions on how to reproduce it, including the workarounds. What we could do is post this issue in our internal tracker so that this case will be queued to be investigated by our development team.

For now, you can use your workarounds as we do not have a solution.

Thanks.

Hi @christian!

So as far as you know, there’s not a specific reason why Custom 404 doesn’t change $wp_query->post, and using Workaround 3 shouldn’t cause additional problems?

Thanks!

Hey @fundibu,

We currently don’t know the reason. This needs deeper investigation by our development team.

The only way to know if your workaround will not cause additional problems is to test it in a staging site and try different use cases that you think might break it. If it passes your test, there’s a high chance it won’t break.

Please just note that we cannot guarantee a fix for 3rd party plugin conflicts.

Thank you for understanding.

Got it! Thanks again!

You’re welcome.

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.