剖析 WordPress `WP_Screen` 类的源码:它如何管理后台页面的上下文,如 `id`、`base` 和 `action`。

各位同学,大家好!今天咱们来聊聊 WordPress 后台界面的“幕后英雄”——WP_Screen 类。别看它名字有点技术范儿,其实它就像个经验丰富的管家,负责管理 WordPress 后台每个页面的上下文信息,比如 ID、Base、Action 等等。有了它,WordPress 才能清楚地知道现在你正在哪个页面,需要加载哪些资源,执行哪些操作。

那么,这个管家到底是怎么工作的呢? 咱们这就开始“扒”它的源码,看看它到底藏着哪些秘密。

一、WP_Screen 类:后台页面的“身份证”

首先,我们得知道 WP_Screen 是个什么东西。简单来说,它就是一个类,用来表示 WordPress 后台的一个屏幕(也就是一个页面)。每个后台页面都会有一个对应的 WP_Screen 对象,这个对象包含了这个页面的所有关键信息。

WP_Screen 类的定义在 wp-admin/includes/class-wp-screen.php 文件中。 我们先来看一下这个类的一些主要属性:

属性名 类型 描述
$id string 屏幕的 ID,例如 edit-postdashboard 等。 这是最关键的标识符,用于唯一标识一个后台页面。
$taxonomy string 如果是分类法(taxonomy)页面,则该属性保存分类法的名称。例如,categorypost_tag
$post_type string 如果是文章类型(post type)页面,则该属性保存文章类型的名称。例如,postpage
$base string 屏幕的基本 ID,通常是 $id 的一部分,用于构建 CSS 类名和其他标识符。 例如,editoptions
$action string 当前屏幕正在执行的动作,例如 addedit。 用于区分同一页面上的不同操作。
$parent_base string 父屏幕的基本 ID,用于构建菜单结构。
$parent_file string 父菜单文件的路径,用于确定当前页面在菜单中的位置。
$screen_icon string 屏幕的图标,通常是一个 HTML 字符串。
$is_network bool 是否是网络管理后台的页面。
$is_user bool 是否是用户管理后台的页面。
$in_admin bool 是否在管理后台。
$in_theme bool 是否在主题定制器中。
$columns array 列(columns)的配置信息,用于列表页面。
$_options array 屏幕选项,用于保存用户对当前页面的个性化设置。

这些属性就像一个人的身份证信息,有了它们,WordPress 就能准确地识别出当前页面,并进行相应的处理。

二、WP_Screen::get( $hook_name = '' ):获取 WP_Screen 对象

那么,我们怎么才能拿到一个页面的 WP_Screen 对象呢? WP_Screen 类提供了一个静态方法 get(),专门用来获取当前屏幕的 WP_Screen 对象。

/**
 * Get the current screen object.
 *
 * @since 3.1.0
 *
 * @global WP_Screen $current_screen
 *
 * @param string $hook_name Optional. A hook name.
 * @return WP_Screen|null WP_Screen object. Null if not in admin.
 */
public static function get( $hook_name = '' ) {
    global $current_screen;

    if ( ! is_admin() ) {
        return null;
    }

    if ( ! isset( $current_screen ) ) {
        _deprecated_argument( __FUNCTION__, '3.3.0', sprintf(
            /* translators: 1: WP_Screen::get_current_screen(), 2: WP_Screen */
            __( 'Use %1$s instead to retrieve the current screen object. See %2$s.' ),
            '<code>WP_Screen::get_current_screen()</code>',
            '{@see WP_Screen}'
        ) );

        self::init();
    }

    return $current_screen;
}

这段代码很简单,首先判断是不是在管理后台 (is_admin()),如果不是,直接返回 null。 然后,它会检查全局变量 $current_screen 是否存在,如果不存在,就调用 self::init() 方法来初始化 $current_screen 对象。 最后,返回 $current_screen 对象。

注意,这里用到了一个全局变量 $current_screen。 这个变量非常重要,它保存了当前页面的 WP_Screen 对象。 WordPress 在加载后台页面的时候,会根据当前页面的 URL 和其他信息,创建一个 WP_Screen 对象,并把它赋值给 $current_screen 变量。

三、WP_Screen::init():初始化 WP_Screen 对象

WP_Screen::init() 方法负责初始化 $current_screen 对象。 这个方法会根据当前页面的 URL 和其他信息,设置 $current_screen 对象的各种属性。 我们来看一下 WP_Screen::init() 方法的代码:

/**
 * Initialize the current screen object.
 *
 * @access private
 * @since 3.1.0
 */
private static function init() {
    global $current_screen, $pagenow, $hook_suffix;

    $current_screen = new WP_Screen();

    // Populate admin menu related properties.
    _wp_menu_output();

    // Get the hook name.
    $hook_name = get_plugin_page_hookname( $pagenow, '' );
    if ( false !== $hook_name ) {
        $hook_name = sanitize_title( $hook_name );
    }

    if ( ! empty( $hook_suffix ) ) {
        $hook_name .= $hook_suffix;
    }

    $current_screen->id = $hook_name;
    $current_screen->base = $pagenow;
    $current_screen->action = isset( $_GET['action'] ) ? $_GET['action'] : '';

    // Set up the post type and taxonomy, if applicable.
    if ( isset( $_GET['post_type'] ) ) {
        $current_screen->post_type = sanitize_key( $_GET['post_type'] );
    }

    if ( isset( $_GET['taxonomy'] ) ) {
        $current_screen->taxonomy = sanitize_key( $_GET['taxonomy'] );
    }

    // ... (省略了部分代码) ...
}

这段代码做了以下几件事:

  1. 创建了一个新的 WP_Screen 对象,并赋值给 $current_screen 变量。
  2. 调用 _wp_menu_output() 函数,生成后台菜单。 这个函数会根据当前用户的权限和已经注册的菜单项,生成 HTML 代码,显示在后台菜单中。
  3. 调用 get_plugin_page_hookname() 函数,获取当前页面的 hook name。 hook name 是一个字符串,用于唯一标识一个后台页面。
  4. 根据 $pagenow$_GET['action']$_GET['post_type']$_GET['taxonomy'] 等参数,设置 $current_screen 对象的 idbaseactionpost_typetaxonomy 等属性。

从这段代码可以看出,WP_Screen::init() 方法的核心任务就是根据当前页面的 URL 和其他信息,设置 $current_screen 对象的各种属性。 这些属性将作为后续操作的依据。

四、WP_Screen 对象的属性:idbaseaction

前面我们提到,WP_Screen 对象的属性非常重要,它们包含了当前页面的关键信息。 其中,idbaseaction 这三个属性尤其重要,我们来详细地看一下它们的作用。

  • $id:页面的唯一标识符

    $id 属性是页面的唯一标识符,用于唯一标识一个后台页面。 WordPress 使用 $id 属性来加载对应的 CSS、JavaScript 文件,以及执行对应的操作。

    $id 属性的值通常由 get_plugin_page_hookname() 函数生成。 get_plugin_page_hookname() 函数会根据 $pagenow 和其他参数,生成一个唯一的字符串作为 hook name。

    例如,当你在编辑一篇文章时,$id 属性的值可能是 edit-post。 当你在管理评论时,$id 属性的值可能是 edit-comments

  • $base:构建 CSS 类名的基础

    $base 属性是屏幕的基本 ID,通常是 $id 属性的一部分。 $base 属性主要用于构建 CSS 类名和其他标识符。

    例如,如果 $id 属性的值是 edit-post,那么 $base 属性的值可能是 edit。 WordPress 会使用 $base 属性来构建 CSS 类名,例如 edit-phpedit-post-php 等。 这些 CSS 类名可以用来定制后台页面的样式。

  • $action:当前正在执行的动作

    $action 属性表示当前屏幕正在执行的动作。 $action 属性的值通常从 $_GET['action'] 参数中获取。

    例如,当你在添加一篇新文章时,$action 属性的值可能是 add。 当你在编辑一篇已有的文章时,$action 属性的值可能是 edit

    $action 属性可以用来区分同一页面上的不同操作。 例如,在文章列表页面,你可以通过 $action 属性来判断用户是正在查看文章列表,还是正在删除一篇文章。

五、WP_Screen 对象的应用场景

了解了 WP_Screen 类的基本原理,我们来看一下它在实际开发中的应用场景。

  • 加载自定义 CSS 和 JavaScript 文件

    我们可以使用 admin_enqueue_scripts 钩子,根据 $current_screen->id 属性的值,加载自定义的 CSS 和 JavaScript 文件。

    function my_admin_enqueue_scripts( $hook ) {
        global $current_screen;
    
        if ( 'edit-post' == $current_screen->id ) {
            wp_enqueue_style( 'my-edit-post-style', plugin_dir_url( __FILE__ ) . 'css/edit-post.css' );
            wp_enqueue_script( 'my-edit-post-script', plugin_dir_url( __FILE__ ) . 'js/edit-post.js', array( 'jquery' ), '1.0', true );
        }
    }
    add_action( 'admin_enqueue_scripts', 'my_admin_enqueue_scripts' );

    这段代码会在编辑文章的页面加载 edit-post.cssedit-post.js 文件。

  • 添加自定义的 metabox

    我们可以使用 add_meta_boxes 钩子,根据 $current_screen->id 属性的值,添加自定义的 metabox。

    function my_add_meta_boxes( $post_type, $post ) {
        global $current_screen;
    
        if ( 'post' == $post_type && 'edit-post' == $current_screen->id ) {
            add_meta_box(
                'my_meta_box',
                __( 'My Meta Box', 'my-plugin' ),
                'my_meta_box_callback',
                $post_type,
                'side',
                'high'
            );
        }
    }
    add_action( 'add_meta_boxes', 'my_add_meta_boxes', 10, 2 );

    这段代码会在编辑文章的页面添加一个名为 "My Meta Box" 的 metabox。

  • 定制后台页面的样式

    我们可以使用 admin_body_class 钩子,根据 $current_screen->id$current_screen->base 属性的值,添加自定义的 CSS 类名到 <body> 标签上。

    function my_admin_body_class( $classes ) {
        global $current_screen;
    
        if ( 'edit-post' == $current_screen->id ) {
            $classes .= ' my-edit-post-class';
        }
    
        return $classes;
    }
    add_filter( 'admin_body_class', 'my_admin_body_class' );

    这段代码会在编辑文章的页面的 <body> 标签上添加 my-edit-post-class 类名。 然后,我们就可以使用 CSS 来定制这个页面的样式。

  • 根据 $action 属性执行不同的操作

    我们可以根据 $current_screen->action 属性的值,执行不同的操作。

    function my_admin_action() {
        global $current_screen;
    
        if ( 'edit-post' == $current_screen->id && 'add' == $current_screen->action ) {
            // 在添加文章的时候执行一些操作
            echo '<div class="notice notice-success"><p>You are adding a new post!</p></div>';
        } elseif ( 'edit-post' == $current_screen->id && 'edit' == $current_screen->action ) {
            // 在编辑文章的时候执行一些操作
            echo '<div class="notice notice-info"><p>You are editing an existing post!</p></div>';
        }
    }
    add_action( 'admin_notices', 'my_admin_action' );

    这段代码会在添加文章的页面显示一个成功的提示信息,在编辑文章的页面显示一个信息的提示信息。

六、总结

WP_Screen 类是 WordPress 后台界面的核心组件之一。 它负责管理后台页面的上下文信息,包括 ID、Base、Action 等等。 通过 WP_Screen 类,我们可以轻松地获取当前页面的信息,并根据这些信息来加载自定义 CSS 和 JavaScript 文件,添加自定义的 metabox,定制后台页面的样式,以及执行不同的操作。

理解 WP_Screen 类的原理和应用场景,对于开发 WordPress 后台插件和主题非常重要。 希望今天的讲解能够帮助大家更好地理解 WP_Screen 类,并在实际开发中灵活运用它。

好了,今天的讲座就到这里。 感谢大家的聆听! 如果大家还有什么问题,欢迎提问。

发表回复

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