Skip to content

[Bug]: Plugin causes recursive call to 'replace_editor' Wordpress filter #23462

Description

@jvoosten

Prerequisites

  • I've read and understood the contribution guidelines.
  • I've searched for any related issues and avoided creating a duplicate issue.

Please give us a description of what happened

I have written a plugin that uses custom post types in WordPress. As there is no point in using the default WordPress editor I also wrote a custom editor for these post types. To enable this, I filter on 'replace_editor' and do all my stuff in there, including an include of 'wp-admin/admin-header.php'. This is clunky but apparently the way it's supposed to be done, see this ticket from the WordPress bugtracker.

This works fine until I install the Yoast SEO plugin. If I now go the the 'edit' page of my custom post types, somehow the contents of my editor appears twice, once in the middle of the HTML header and at the normal place. A dump of the callstack shows how this happens:

#0 /var/www/myproject/shop/wp-includes/class-wp-hook.php(341): arcade_filter_editor(false, Object(WP_Post))
#1 /var/www/myproject/shop/wp-includes/plugin.php(205): WP_Hook->apply_filters(false, Array)
#2 /var/www/myproject/shop/wp-admin/includes/class-wp-screen.php(312): apply_filters('...', false, Object(WP_Post))
#3 /var/www/myproject/shop/wp-content/plugins/wordpress-seo/admin/metabox/class-metabox.php(865): WP_Screen::get()
#4 /var/www/myproject/shop/wp-includes/class-wp-hook.php(341): WPSEO_Metabox->enqueue('...')
#5 /var/www/myproject/shop/wp-includes/class-wp-hook.php(365): WP_Hook->apply_filters(NULL, Array)
#6 /var/www/myproject/shop/wp-includes/plugin.php(522): WP_Hook->do_action(Array)
#7 /var/www/myproject/shop/wp-admin/admin-header.php(123): do_action('...', '...')
#8 /var/www/myproject/shop/wp-content/plugins/arcade/include/edit.php(136): require_once('...')
#9 /var/www/myproject/shop/wp-includes/class-wp-hook.php(341): arcade_filter_editor(false, Object(WP_Post))
#10 /var/www/myproject/shop/wp-includes/plugin.php(205): WP_Hook->apply_filters(false, Array)
#11 /var/www/myproject/shop/wp-admin/post.php(182): apply_filters('...', false, Object(WP_Post))

The culprit is the call to WP_Screen::get(), which internally looks if there a block editor active and therefor needs to know the current editor that is active, using the 'replace_editor' filter...

I fixed this internally by replacing the calls to WP_Screen::get() in my local copy of Yoast to get_current_screen(), which is what I think was needed in the first place. Whoever wrote that code probably thought calling WP_Screen::get() without a parameter was equivalent to get_current_screen(), but if you look at the implementation of both functions they are totally different.

I made a patch for Yoast that replaces WP_Screen::get() with get_current_screen(); the one drawback of get_current_screen() is that it can return null, so you have to check for that.

wordpress-seo-get_screen_fix.patch

I will admit that writing an editor for a custom post type in WordPress is a rather obscure edge case but for us it's now completely broken together with Yoast. I hope you will accept this fix. To be honest, I don't know the exact use case for WP_Screen::get() either, but get_current_screen() seems more logical, judging by the other uses of that function.

Step-by-step reproduction instructions

  1. Create a plugin, add a filter function like this:
add_filter ('replace_editor', 'arcade_filter_editor', 10, 2);

function arcade_filter_editor ($default_value, $post)
{
    $current_screen = get_current_screen ();
    if ($post && 'post' == get_post_type ($post) && $current_screen)
    {
       require_once ABSPATH . 'wp-admin/admin-header.php';
       print 'Custom Post Editor!';
       return true;
    }
    return $default_value;
}

  1. Edit a default WordPress post; you wil see the text 'Custom Post Editor!' instead of the regular editor.
  2. Install and enable Yoast SEO
  3. Edit a post again, see how the text 'Custom Post Editor' appears in the HTML header (you may need to use "view source").

Expected results

  1. No garbage in the HTML header.

Actual results

  1. Custom editor gets included twice.

Screenshots, screen recording, code snippet

No response

Which editor is affected (or editors)

  • Block Editor
  • Gutenberg Editor
  • Elementor Editor
  • Classic Editor
  • Other (please specify in additional info)

Which browser is affected (or browsers)

  • Chrome
  • Firefox
  • Safari
  • Other (please specify in additional info)

Device you are using

No response

Operating system

No response

PHP version

No response

WordPress version

6.8.3, 6.9.1

WordPress Theme

Custom

Yoast SEO version

28.0

Gutenberg plugin version (if relevant)

No response

Elementor plugin version (if relevant)

No response

Classic Editor plugin version (if relevant)

No response

Relevant plugins in case of a bug

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions