各位观众,晚上好!欢迎来到今天的“WordPress源码解剖”节目。我是你们的老朋友,今天咱们要聊点儿实在的,扒一扒WordPress里负责管理文章类型的“管家”——WP_Post_Type
类,以及它背后的秘密武器:$wp_post_types
全局变量。
准备好了吗?咱们这就开始“解剖”!
第一幕:WP_Post_Type
类——文章类型的“身份证”
首先,咱们得认识一下主角WP_Post_Type
类。这哥们儿就像文章类型的“身份证”,里面记录了各种关于文章类型的重要信息。
<?php
/**
* Core class used to implement a post type object.
*
* @since 4.4.0
*
* @see register_post_type()
*/
class WP_Post_Type {
/**
* Post type key.
*
* @since 4.4.0
* @var string
*/
public $name;
/**
* Post type object properties.
*
* @since 4.4.0
* @var object
*/
public $labels;
/**
* Post type arguments.
*
* @since 4.4.0
* @var array
*/
public $args;
/**
* Constructor.
*
* @since 4.4.0
*
* @param string $post_type Post type key. Must not exceed 20 characters and may only contain lowercase alphanumeric characters, dashes, and underscores. See {@link register_post_type()}.
* @param array|string $args Optional. Array or string of arguments for registering a post type.
*/
public function __construct( $post_type, $args = array() ) {
$this->name = $post_type;
$this->set_props( $args );
}
/**
* Sets post type properties.
*
* @since 4.4.0
*
* @param array|string $args Array or string of arguments for registering a post type.
*/
protected function set_props( $args ) {
$args = wp_parse_args( $args );
$this->args = (object) $args;
$this->add_supports();
$this->set_labels();
}
/**
* Adds default support values.
*
* @since 4.7.0
*/
protected function add_supports() {
$supports = array();
if ( isset( $this->args->supports ) ) {
$supports = $this->args->supports;
if ( ! is_array( $supports ) ) {
$supports = array( $supports => true );
}
}
$this->supports = $supports;
unset( $this->args->supports ); // Prevent clashes with the property.
}
/**
* Sets the labels property for the post type based on the arguments passed.
*
* @since 4.4.0
*/
protected function set_labels() {
$labels = array();
if ( isset( $this->args->labels ) ) {
$labels = $this->args->labels;
unset( $this->args->labels ); // Prevent clashes with the property.
}
$this->labels = (object) _get_post_type_labels( (object) array( 'name' => $this->name ), $labels );
}
/**
* Gets an object containing the names for the post type labels property.
*
* @since 4.4.0
*
* @return object Object containing the names for the post type labels property.
*/
public function get_labels() {
return $this->labels;
}
/**
* Adds filter to allow taxonomy to be associated with the post type.
*
* @since 4.4.0
*/
public function add_rewrite_rules() {
add_filter( 'rewrite_rules_array', array( $this, 'rewrite_rules_filter' ) );
}
/**
* Remove filter to disallow taxonomy to be associated with the post type.
*
* @since 4.4.0
*/
public function remove_rewrite_rules() {
remove_filter( 'rewrite_rules_array', array( $this, 'rewrite_rules_filter' ) );
}
/**
* Filters the rewrite rules for the post type.
*
* @since 4.4.0
*
* @param array $rules Array of rewrite rules.
* @return array Array of rewrite rules.
*/
public function rewrite_rules_filter( $rules ) {
$post_rewrite = $this->rewrite_base();
if ( false === $post_rewrite ) {
return $rules;
}
$slug = $post_rewrite['slug'];
if ( ! isset( $post_rewrite['ep_mask'] ) ) {
$ep_mask = EP_PERMALINK;
} else {
$ep_mask = $post_rewrite['ep_mask'];
}
$new_rules = array();
if ( $this->query_var ) {
$new_rules[ $slug . '/?$' ] = 'index.php?' . $this->query_var . '=$matches[1]';
$new_rules[ $slug . '/([^/]+)/?$' ] = 'index.php?' . $this->query_var . '=$matches[1]';
} else {
$new_rules[ $slug . '/?$' ] = 'index.php?post_type=' . $this->name;
$new_rules[ $slug . '/([^/]+)/?$' ] = 'index.php?post_type=' . $this->name . '&name=$matches[1]';
}
return $new_rules + $rules;
}
/**
* Returns the base rewrite rule for the post type.
*
* @since 4.4.0
*
* @return array|false Array containing the rewrite base, or false if the post type should not be rewritten.
*/
protected function rewrite_base() {
if ( ! $this->public ) {
return false;
}
if ( ! $this->rewrite ) {
return false;
}
$rewrite = $this->rewrite;
if ( ! is_array( $rewrite ) ) {
return array( 'slug' => $this->name );
}
if ( ! isset( $rewrite['slug'] ) ) {
$rewrite['slug'] = $this->name;
}
return $rewrite;
}
/**
* Adds support for a feature to the post type.
*
* @since 4.4.0
*
* @param string $feature Post type support key.
*/
public function add_support( $feature ) {
$this->supports[ $feature ] = true;
}
/**
* Removes support for a feature from the post type.
*
* @since 4.4.0
*
* @param string $feature Post type support key.
*/
public function remove_support( $feature ) {
unset( $this->supports[ $feature ] );
}
/**
* Checks if the post type supports a given feature.
*
* @since 4.4.0
*
* @param string $feature Post type support key.
* @return bool True if the post type supports the feature, false otherwise.
*/
public function supports( $feature ) {
if ( isset( $this->supports[ $feature ] ) ) {
return $this->supports[ $feature ];
}
return false;
}
}
简单来说,WP_Post_Type
类主要负责:
- 存储文章类型的信息: 例如,文章类型的名称(
name
),标签(labels
),参数(args
)等等。 - 处理文章类型的相关操作: 例如,添加/移除对特定功能的支持(
add_support
,remove_support
),过滤重写规则(rewrite_rules_filter
)等等。
咱们来看个例子,假设我们要注册一个名为book
的文章类型:
$args = array(
'labels' => array(
'name' => '书籍',
'singular_name' => '书籍'
),
'public' => true,
'has_archive' => true,
'supports' => array( 'title', 'editor', 'thumbnail' )
);
$book_post_type = new WP_Post_Type( 'book', $args );
这段代码创建了一个WP_Post_Type
类的实例$book_post_type
,并将book
文章类型的相关信息存储在这个实例中。
第二幕:$wp_post_types
——文章类型的“户口登记处”
光有“身份证”还不行,还得去“户口登记处”登记一下,这样WordPress才能知道有这么个文章类型存在。这个“户口登记处”就是全局变量$wp_post_types
。
$wp_post_types
是一个全局数组,它的作用是将所有注册的文章类型的WP_Post_Type
对象存储起来。 就像一个大仓库,专门存放文章类型的信息。
在WordPress的wp-includes/post.php
文件中,你可以找到这个全局变量的定义:
global $wp_post_types;
$wp_post_types = array();
看到了吗?它就是一个简单的数组。
第三幕:register_post_type()
——注册文章类型的“窗口”
那么,如何把文章类型的“身份证”放到$wp_post_types
这个“户口登记处”呢?答案就是register_post_type()
函数。
register_post_type()
函数是WordPress提供的一个核心函数,用于注册文章类型。它的主要作用就是:
- 创建一个
WP_Post_Type
类的实例。 - 将这个实例存储到
$wp_post_types
全局变量中。
咱们来看一下register_post_type()
函数的简化版代码:
function register_post_type( $post_type, $args = array() ) {
global $wp_post_types;
// 1. 创建 WP_Post_Type 类的实例
$wp_post_types[ $post_type ] = new WP_Post_Type( $post_type, $args );
// 2. 返回 WP_Post_Type 类的实例
return $wp_post_types[ $post_type ];
}
可以看到,register_post_type()
函数首先创建了一个WP_Post_Type
类的实例,然后将这个实例以文章类型名称为键名,存储到$wp_post_types
全局变量中。
也就是说,当我们调用register_post_type( 'book', $args )
时,WordPress会创建一个WP_Post_Type
对象,然后将其存储到$wp_post_types['book']
中。
第四幕:get_post_type_object()
——获取文章类型的“查询机”
既然有了“户口登记处”,肯定也得有“查询机”,方便我们查询文章类型的信息。这个“查询机”就是get_post_type_object()
函数。
get_post_type_object()
函数的作用是根据文章类型名称,从$wp_post_types
全局变量中获取对应的WP_Post_Type
对象。
咱们来看一下get_post_type_object()
函数的简化版代码:
function get_post_type_object( $post_type ) {
global $wp_post_types;
if ( isset( $wp_post_types[ $post_type ] ) ) {
return $wp_post_types[ $post_type ];
}
return null;
}
可以看到,get_post_type_object()
函数首先检查$wp_post_types
全局变量中是否存在指定文章类型的WP_Post_Type
对象,如果存在,则直接返回该对象,否则返回null
。
例如,我们可以这样获取book
文章类型的WP_Post_Type
对象:
$book_post_type = get_post_type_object( 'book' );
if ( $book_post_type ) {
echo '文章类型名称:' . $book_post_type->name . '<br>';
echo '是否公开:' . ($book_post_type->public ? '是' : '否') . '<br>';
}
第五幕:get_post_types()
——获取所有文章类型的“花名册”
有时候,我们需要获取所有已注册的文章类型,而不是单个文章类型的信息。这时候,就需要用到get_post_types()
函数。
get_post_types()
函数的作用是获取所有已注册的文章类型的名称。它会遍历$wp_post_types
全局变量,然后返回一个包含所有文章类型名称的数组。
咱们来看一下get_post_types()
函数的简化版代码:
function get_post_types( $args = array(), $output = 'names' ) {
global $wp_post_types;
$names = array_keys( $wp_post_types );
return $names;
}
可以看到,get_post_types()
函数直接使用了array_keys()
函数,从$wp_post_types
全局变量中提取所有键名,也就是文章类型的名称。
例如,我们可以这样获取所有已注册的文章类型:
$post_types = get_post_types();
echo '所有文章类型:<br>';
foreach ( $post_types as $post_type ) {
echo $post_type . '<br>';
}
第六幕:unregister_post_type()
——注销文章类型的“销户窗口”
如果有一天,我们不再需要某个文章类型了,就可以使用unregister_post_type()
函数将其注销。
unregister_post_type()
函数的作用是从$wp_post_types
全局变量中移除指定文章类型的WP_Post_Type
对象。
咱们来看一下unregister_post_type()
函数的简化版代码:
function unregister_post_type( $post_type ) {
global $wp_post_types;
if ( isset( $wp_post_types[ $post_type ] ) ) {
unset( $wp_post_types[ $post_type ] );
return true;
}
return false;
}
可以看到,unregister_post_type()
函数直接使用了unset()
函数,从$wp_post_types
全局变量中删除指定键名的元素,也就是文章类型的WP_Post_Type
对象。
总结:WP_Post_Type
和$wp_post_types
的“二人转”
现在,咱们来总结一下WP_Post_Type
类和$wp_post_types
全局变量之间的关系:
角色 | 职责 |
---|---|
WP_Post_Type |
存储文章类型的具体信息,例如名称、标签、参数等等。 |
$wp_post_types |
存储所有已注册的文章类型的WP_Post_Type 对象,相当于一个文章类型的“户口登记处”。 |
register_post_type() |
注册文章类型,将WP_Post_Type 对象存储到$wp_post_types 中。 |
get_post_type_object() |
获取指定文章类型的WP_Post_Type 对象,从$wp_post_types 中查询。 |
get_post_types() |
获取所有已注册的文章类型名称,遍历$wp_post_types 。 |
unregister_post_type() |
注销文章类型,从$wp_post_types 中移除WP_Post_Type 对象。 |
它们之间的关系就像一对“二人转”演员,WP_Post_Type
负责提供“唱腔”(文章类型的信息),$wp_post_types
负责搭建“舞台”(存储和管理文章类型)。
实战演练:修改文章类型的标签
最后,咱们来个实战演练,演示如何通过$wp_post_types
全局变量修改文章类型的标签。
假设我们要修改post
文章类型的“文章”标签为“新闻”。我们可以这样做:
global $wp_post_types;
if ( isset( $wp_post_types['post'] ) ) {
$wp_post_types['post']->labels->name = '新闻';
$wp_post_types['post']->labels->singular_name = '新闻';
}
这段代码首先获取post
文章类型的WP_Post_Type
对象,然后直接修改其labels
属性的name
和singular_name
属性。
需要注意的是,这种方式修改文章类型的信息可能会导致一些问题,例如,一些插件或主题可能缓存了文章类型的信息,导致修改无效。因此,建议使用WordPress提供的register_post_type_args
过滤器来修改文章类型的信息,这样可以确保修改的兼容性。
结语
好了,今天的“WordPress源码解剖”节目就到这里了。希望通过今天的讲解,大家对WP_Post_Type
类和$wp_post_types
全局变量有了更深入的了解。
记住,掌握了这些知识,你就可以更好地管理WordPress的文章类型,定制出更符合自己需求的网站。
感谢大家的收看,咱们下期再见! 别忘了点个赞,关注一下,下次咱们继续聊点儿更有意思的!