解析 WordPress `is_gutenberg_page()` 函数的源码:如何判断当前页面是否为 Gutenberg 编辑器。

各位观众,晚上好!今天咱们来聊聊 WordPress 里一个挺重要的函数,is_gutenberg_page()。这玩意儿关乎你 WordPress 站点编辑体验,以及插件、主题对 Gutenberg 编辑器的兼容性。 别看名字挺长,理解了它背后的逻辑,就能让你在自定义 WordPress 时少走很多弯路。

一、Gutenberg 编辑器是啥?

首先,咱们得先搞清楚 Gutenberg 是个啥。简单来说,Gutenberg 是 WordPress 5.0 版本引入的块编辑器,它彻底改变了 WordPress 的内容编辑方式。以前咱们用的是经典编辑器(TinyMCE),就像用 Word 写文章一样。但 Gutenberg 把文章内容拆分成一个个独立的“块”,比如段落块、图片块、标题块等等。你可以像搭积木一样,自由组合这些块来创建页面和文章。

二、is_gutenberg_page() 函数的作用

is_gutenberg_page() 的作用,就是判断当前页面是否正在使用 Gutenberg 编辑器。这个判断对于插件开发者尤其重要。比如,你的插件可能需要根据用户使用的编辑器类型,加载不同的 CSS 样式或 JavaScript 代码。

三、源码解析:is_gutenberg_page() 究竟做了什么?

废话不多说,咱们直接上代码,扒一扒 is_gutenberg_page() 的源码。(以下代码基于 WordPress 6.x 版本)

<?php
/**
 * Checks if the current page is using the Gutenberg editor.
 *
 * @since 5.0.0
 *
 * @global string $pagenow The filename of the current screen.
 * @global WP_Screen $current_screen The current screen.
 *
 * @return bool True if the current page is using the Gutenberg editor, false otherwise.
 */
function is_gutenberg_page() {
    global $pagenow, $current_screen;

    if ( ! function_exists( 'use_block_editor_for_post_type' ) ) {
        require_once ABSPATH . 'wp-admin/includes/post.php';
    }

    // Avoid errors when processing AJAX requests or running cron.
    if ( ! isset( $current_screen ) ) {
        return false;
    }

    // Allow the use of the block editor, regardless of user settings,
    // if the user has the 'edit_posts' capability and the query string
    // contains 'force-reusable-blocks-editor'.
    if (
        current_user_can( 'edit_posts' ) &&
        ! empty( $_GET['force-reusable-blocks-editor'] )
    ) {
        return true;
    }

    $block_editor = false;

    // Gutenberg is not available for the 'site-health' tool.
    if ( 'site-health.php' === $pagenow ) {
        return false;
    }

    if ( 'post.php' === $pagenow || 'post-new.php' === $pagenow ) {
        $post_type = $current_screen->post_type;
        if ( use_block_editor_for_post_type( $post_type ) ) {
            $block_editor = true;
        }
    } elseif ( 'widgets.php' === $pagenow ) {
        $block_editor = true;
    } elseif ( 'site-editor.php' === $pagenow ) {
        $block_editor = true;
    } elseif ( 'themes.php' === $pagenow && isset( $_GET['gutenberg-edit-site'] ) ) {
        $block_editor = true;
    } elseif ( 'wp-login.php' === $pagenow ) {
        $block_editor = false;
    }

    /**
     * Filters whether the current page is using the Gutenberg editor.
     *
     * @since 5.0.0
     *
     * @param bool $block_editor Whether the current page is using the Gutenberg editor.
     */
    return apply_filters( 'use_block_editor_for_post', $block_editor );
}

好,咱们一行行来解读:

  1. 全局变量引入:

    global $pagenow, $current_screen;

    这行代码引入了两个全局变量:$pagenow$current_screen

    • $pagenow:表示当前页面的文件名,比如 post.php(编辑文章页面)、post-new.php(新建文章页面)等。
    • $current_screen:是一个 WP_Screen 类的实例,包含了当前屏幕的信息,比如 post type(文章类型)、base(页面基础名)等。
  2. use_block_editor_for_post_type() 函数检查:

    if ( ! function_exists( 'use_block_editor_for_post_type' ) ) {
        require_once ABSPATH . 'wp-admin/includes/post.php';
    }

    这段代码首先检查 use_block_editor_for_post_type() 函数是否存在。如果不存在,就引入 wp-admin/includes/post.php 文件,这个文件定义了该函数。use_block_editor_for_post_type() 函数用于判断指定的文章类型是否启用了 Gutenberg 编辑器。

  3. 避免 AJAX 和 Cron 错误:

    if ( ! isset( $current_screen ) ) {
        return false;
    }

    在 AJAX 请求或 Cron 任务中,$current_screen 可能未被设置,为了避免出现错误,直接返回 false

  4. 强制启用 Gutenberg 编辑器 (通过查询字符串):

    if (
        current_user_can( 'edit_posts' ) &&
        ! empty( $_GET['force-reusable-blocks-editor'] )
    ) {
        return true;
    }

    如果当前用户有编辑文章的权限,并且 URL 查询字符串中包含 force-reusable-blocks-editor 参数,则强制启用 Gutenberg 编辑器,并返回 true.

  5. $block_editor 变量初始化:

    $block_editor = false;

    初始化一个 $block_editor 变量,默认值为 false,表示默认情况下不使用 Gutenberg 编辑器。

  6. 针对特定页面的判断:

    // Gutenberg is not available for the 'site-health' tool.
    if ( 'site-health.php' === $pagenow ) {
        return false;
    }
    
    if ( 'post.php' === $pagenow || 'post-new.php' === $pagenow ) {
        $post_type = $current_screen->post_type;
        if ( use_block_editor_for_post_type( $post_type ) ) {
            $block_editor = true;
        }
    } elseif ( 'widgets.php' === $pagenow ) {
        $block_editor = true;
    } elseif ( 'site-editor.php' === $pagenow ) {
        $block_editor = true;
    } elseif ( 'themes.php' === $pagenow && isset( $_GET['gutenberg-edit-site'] ) ) {
        $block_editor = true;
    } elseif ( 'wp-login.php' === $pagenow ) {
        $block_editor = false;
    }

    这部分代码是核心逻辑,它根据不同的 $pagenow 值,判断是否使用 Gutenberg 编辑器。

    • site-health.php:站点健康工具页面,禁用 Gutenberg 编辑器。
    • post.phppost-new.php:编辑和新建文章页面。首先获取当前文章类型 $post_type,然后调用 use_block_editor_for_post_type() 函数判断该文章类型是否启用了 Gutenberg 编辑器。
    • widgets.php:小工具页面,使用 Gutenberg 编辑器(块小工具编辑器)。
    • site-editor.php: 站点编辑器页面(古腾堡全站编辑),使用 Gutenberg 编辑器。
    • themes.php: 主题页面,需要get参数gutenberg-edit-site 存在时,使用 Gutenberg 编辑器。
    • wp-login.php: 登录页面,禁用 Gutenberg 编辑器。
  7. apply_filters() 过滤器:

    return apply_filters( 'use_block_editor_for_post', $block_editor );

    最后,使用 apply_filters() 函数,允许开发者通过 use_block_editor_for_post 过滤器来修改 $block_editor 的值。这提供了极大的灵活性,开发者可以根据自己的需求,自定义 Gutenberg 编辑器的启用逻辑。

四、use_block_editor_for_post_type() 函数

上面提到了 use_block_editor_for_post_type() 函数,咱们也简单看一下它的实现:

<?php
/**
 * Determines whether the block editor is enabled for the given post type.
 *
 * @since 5.0.0
 *
 * @param string $post_type The post type to check.
 *
 * @return bool True if the block editor is enabled for the given post type, false otherwise.
 */
function use_block_editor_for_post_type( $post_type ) {
    if ( ! post_type_exists( $post_type ) ) {
        return false;
    }

    /**
     * Filters whether the block editor is enabled for the given post type.
     *
     * @since 5.0.0
     *
     * @param bool   $use_block_editor Whether the block editor is enabled.
     * @param string $post_type        The post type being checked.
     */
    return apply_filters(
        'use_block_editor_for_post_type',
        post_type_supports( $post_type, 'editor' ),
        $post_type
    );
}

这个函数主要做了两件事:

  1. 判断文章类型是否存在:

    if ( ! post_type_exists( $post_type ) ) {
        return false;
    }

    如果指定的文章类型不存在,直接返回 false

  2. 判断文章类型是否支持 editor 特性:

    return apply_filters(
        'use_block_editor_for_post_type',
        post_type_supports( $post_type, 'editor' ),
        $post_type
    );

    调用 post_type_supports() 函数,判断指定的文章类型是否支持 editor 特性。如果支持,则返回 true,否则返回 false。同时,使用 apply_filters() 函数,允许开发者通过 use_block_editor_for_post_type 过滤器来修改返回值。

五、post_type_supports() 函数

post_type_supports() 函数用于检查文章类型是否支持某个特性,例如 editorthumbnail 等。

<?php
/**
 * Checks if a post type supports a given feature.
 *
 * @since 3.0.0
 *
 * @global array $_wp_post_type_features An array of post type features.
 *
 * @param string       $post_type The post type to check.
 * @param string|false $feature   The feature to check for.
 * @return bool True if the post type supports the feature, false otherwise.
 */
function post_type_supports( $post_type, $feature ) {
    global $_wp_post_type_features;

    if ( ! isset( $_wp_post_type_features[ $post_type ] ) ) {
        return false;
    }

    if ( ! isset( $_wp_post_type_features[ $post_type ][ $feature ] ) ) {
        return false;
    }

    return true;
}

这个函数依赖于全局变量 $_wp_post_type_features,它是一个多维数组,存储了每个文章类型支持的特性。如果 $post_type$feature 都存在于该数组中,则返回 true,否则返回 false

六、总结:is_gutenberg_page() 的判断逻辑

现在,咱们可以总结一下 is_gutenberg_page() 的判断逻辑了:

  1. 首先,判断当前页面文件名 ($pagenow)。
  2. 然后,根据 $pagenow 的值,进行不同的判断:
    • 如果是编辑或新建文章页面 (post.phppost-new.php),则调用 use_block_editor_for_post_type() 函数,判断当前文章类型是否启用了 Gutenberg 编辑器。
    • 如果是小工具页面 (widgets.php),则默认使用 Gutenberg 编辑器。
    • 如果是站点编辑器页面 (site-editor.php),则默认使用 Gutenberg 编辑器。
    • 如果是主题页面 (themes.php) 且 URL 中包含 gutenberg-edit-site 参数,则使用 Gutenberg 编辑器。
    • 如果是站点健康工具或登录页面,则禁用 Gutenberg 编辑器。
  3. 最后,通过 apply_filters() 函数,允许开发者自定义 Gutenberg 编辑器的启用逻辑。

用表格总结如下:

页面文件名 ($pagenow) 判断逻辑
post.php, post-new.php 调用 use_block_editor_for_post_type($current_screen->post_type)
widgets.php 使用 Gutenberg 编辑器
site-editor.php 使用 Gutenberg 编辑器
themes.php 只有当URL参数包含 gutenberg-edit-site 时,使用 Gutenberg 编辑器
site-health.php, wp-login.php 不使用 Gutenberg 编辑器
其他 默认不使用 Gutenberg 编辑器,但可以通过 use_block_editor_for_post 过滤器进行修改

七、如何使用 is_gutenberg_page()

在你的插件或主题代码中,你可以像这样使用 is_gutenberg_page() 函数:

<?php
if ( is_gutenberg_page() ) {
    // 当前页面正在使用 Gutenberg 编辑器
    wp_enqueue_style( 'my-plugin-gutenberg-style', plugin_dir_url( __FILE__ ) . 'css/gutenberg.css' );
} else {
    // 当前页面正在使用经典编辑器或其他页面
    wp_enqueue_style( 'my-plugin-classic-style', plugin_dir_url( __FILE__ ) . 'css/classic.css' );
}

这段代码会根据当前页面使用的编辑器类型,加载不同的 CSS 样式。

八、利用过滤器自定义 Gutenberg 编辑器的启用逻辑

正如我们前面提到的,is_gutenberg_page() 函数使用了 use_block_editor_for_post 过滤器,允许开发者自定义 Gutenberg 编辑器的启用逻辑。

例如,你可以这样禁用所有文章类型的 Gutenberg 编辑器:

<?php
add_filter( 'use_block_editor_for_post', '__return_false' );

或者,你可以只针对特定文章类型禁用 Gutenberg 编辑器:

<?php
add_filter( 'use_block_editor_for_post_type', 'my_disable_gutenberg_for_my_post_type', 10, 2 );
function my_disable_gutenberg_for_my_post_type( $use_block_editor, $post_type ) {
    if ( 'my_post_type' === $post_type ) {
        return false;
    }
    return $use_block_editor;
}

这段代码会禁用 my_post_type 文章类型的 Gutenberg 编辑器。

九、注意事项

  • 缓存: 在某些情况下,is_gutenberg_page() 的结果可能会被缓存。如果你发现它的返回值不正确,可以尝试清除缓存。
  • 主题兼容性: 某些主题可能会修改 WordPress 的默认行为,导致 is_gutenberg_page() 的返回值不准确。在开发插件或主题时,需要注意与其他主题的兼容性。
  • 第三方插件: 某些第三方插件也可能会影响 Gutenberg 编辑器的启用状态。在开发插件时,需要注意与其他插件的兼容性。

十、总结

is_gutenberg_page() 是一个非常有用的函数,它可以帮助你判断当前页面是否正在使用 Gutenberg 编辑器。通过理解它的源码和使用方法,你可以更好地控制 WordPress 的编辑体验,并开发出更兼容 Gutenberg 编辑器的插件和主题。记住,灵活运用过滤器,可以让你自定义 Gutenberg 编辑器的启用逻辑,满足各种需求。

好了,今天的讲座就到这里。希望大家能从中学到一些东西。 咱们下期再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注