各位观众老爷们,早上好!今天咱来聊聊WordPress里一个低调但关键的家伙——WP_Post_Revisions
类,也就是文章修订版本的管理机制。说白了,就是WordPress怎么帮你存历史版本,万一你手抖改错了,还能找回来。
一、啥是修订版本?为啥要有它?
想象一下,你辛辛苦苦写了一篇文章,改了又改,突然灵光一闪,把最重要的部分删了!然后手一抖,点了“更新”。完了!欲哭无泪啊。
这时候,修订版本就来救场了。它就像一个时光机,能让你回到过去的某个版本。
更正式点说,修订版本就是文章、页面等内容在不同时间点的快照。每次你保存或自动保存文章,WordPress就会创建一个修订版本,记录下当时的内容、标题、作者等等信息。
二、WP_Post_Revisions
类在哪?它干啥的?
WP_Post_Revisions
类,顾名思义,就是专门用来处理修订版本的。它不是一个直接让你实例化的类,而是一堆静态方法,提供了一系列函数来操作修订版本。
这个类藏在 wp-includes/post.php
文件里。 记住,它是WordPress核心的一部分,不需要额外安装插件。
三、核心函数大揭秘:wp_save_post_revision()
这个函数是修订版本机制的灵魂人物。每次你保存文章,或者自动保存触发,它都会被调用。
/**
* Saves a post revision.
*
* @since 2.6.0
*
* @param int|WP_Post $post Post ID or WP_Post object.
* @param bool $autosave Optional. Whether this is an autosave. Default is false.
* @return int|false The ID of the revision or false if error.
*/
function wp_save_post_revision( $post, $autosave = false ) {
global $wpdb;
if ( is_object( $post ) ) {
$post = $post->ID;
}
$post = get_post( $post );
if ( ! $post ) {
return false;
}
if ( ! current_user_can( 'edit_post', $post->ID ) ) {
return false;
}
if ( 'revision' === $post->post_type ) {
return false;
}
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
if ( ! $autosave ) {
return false;
}
}
if ( wp_is_post_autosave( $post->ID ) ) {
return false;
}
if ( wp_is_post_revision( $post->ID ) ) {
return false;
}
$parent = $post;
$post = clone $parent;
$post->post_parent = $parent->ID;
unset( $post->ID );
$post->post_status = 'inherit';
$post->post_type = 'revision';
$post->comment_status = 'closed';
$post->ping_status = 'closed';
if ( $autosave ) {
$post->post_name = "{$parent->ID}-autosave-v1";
/* translators: Post revision title. %s: Time of revision. */
$post->post_title = sprintf( __( 'Auto Draft saved at %s' ), date( __( 'g:i a' ) ) );
} else {
$post->post_name = "{$parent->ID}-revision-v1";
/* translators: Post revision title. %s: Time of revision. */
$post->post_title = sprintf( __( 'Revision saved at %s' ), date( __( 'g:i a' ) ) );
}
$post_id = wp_insert_post( (array) $post );
if ( is_wp_error( $post_id ) ) {
return false;
}
/**
* Fires after a post revision is saved.
*
* @since 2.6.0
*
* @param int|WP_Post $post Post ID or WP_Post object.
*/
do_action( 'wp_save_post_revision', $post_id, $post );
return $post_id;
}
这个函数做了以下几件事:
- 安全检查: 验证用户是否有权限编辑文章。
- 类型判断: 确保不是在保存一个修订版本或者自动保存版本。
- 克隆文章: 创建一个原始文章的副本。
- 设置属性: 设置副本的
post_type
为revision
,post_status
为inherit
,表明这是一个修订版本,并且依附于原始文章。post_parent
设置为原始文章的ID。 - 插入修订版本: 使用
wp_insert_post()
函数将修订版本插入数据库。
重点: 修订版本实际上也是一个post
,只不过它的post_type
是revision
,并且post_parent
指向原始文章。这是一种非常巧妙的设计。
四、自动保存:wp_autosave_post()
自动保存是修订版本机制的重要组成部分。WordPress会定期自动保存你的文章,防止你因为浏览器崩溃或者断电而丢失数据。
/**
* Autosaves a post.
*
* @since 2.6.0
*
* @param array $data $_POST or $_GET data.
* @return int|WP_Error Post ID.
*/
function wp_autosave_post( $data ) {
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
}
// Non-existent nonce? Don't bother.
if ( ! isset( $data['autosave'] ) ) {
return;
}
$post_ID = (int) $data['post_ID'];
// Missing post ID? Bail.
if ( empty( $post_ID ) ) {
return;
}
// Is the user allowed to edit this post?
if ( ! current_user_can( 'edit_post', $post_ID ) ) {
return new WP_Error( 'autosave_error', __( 'Sorry, you are not allowed to edit this post.' ) );
}
// Gotta have some content to autosave.
if ( empty( $data['content'] ) ) {
return;
}
// Don't autosave if the form hasn't been submitted
if ( 'draft' == get_post_status( $post_ID ) && isset( $_REQUEST['action'] ) && 'editpost' != $_REQUEST['action'] ) {
return;
}
define( 'DOING_AUTOSAVE', true );
// Disable filters that modify content, excerpt, titles, etc.
remove_all_filters( 'content_save_pre' );
remove_all_filters( 'excerpt_save_pre' );
remove_all_filters( 'title_save_pre' );
// Expected $_POST values.
$post = array();
$post['ID'] = $post_ID;
$post['post_content'] = $data['content'];
$post['post_excerpt'] = $data['excerpt'];
$post['post_title'] = $data['title'];
// Typecast to array to avoid PHP 8.1+ deprecation notice.
$post = wp_kses_post( (array) $post );
// Attempt to write the autosave.
$post_id = wp_save_post_revision( $post['ID'], true );
if ( is_wp_error( $post_id ) ) {
return $post_id;
}
add_action( 'edit_form_advanced', 'wp_print_revision_js' );
add_action( 'edit_page_form', 'wp_print_revision_js' );
return $post_id;
}
这个函数主要做了:
- 权限验证: 验证用户是否有权限编辑文章。
- 数据准备: 从
$_POST
或$_GET
中获取文章内容、摘要、标题等数据。 - 调用
wp_save_post_revision()
: 调用wp_save_post_revision()
函数,并将$autosave
参数设置为true
,表明这是一个自动保存版本。
五、获取修订版本:wp_get_post_revisions()
有了保存,当然也要有读取。wp_get_post_revisions()
函数就是用来获取文章的修订版本的。
/**
* Retrieves post revisions.
*
* @since 2.6.0
*
* @param int|WP_Post $post Post ID or WP_Post object.
* @param array $args Optional. Arguments for retrieving revisions.
* See {@see WP_Query::parse_query()} for information on accepted arguments.
* Default empty array.
* @return WP_Post[] Array of revisions.
*/
function wp_get_post_revisions( $post, $args = array() ) {
$post = get_post( $post );
if ( ! $post ) {
return array();
}
$defaults = array(
'order' => 'DESC',
'orderby' => 'date ID',
'check_enabled' => true,
);
$args = wp_parse_args( $args, $defaults );
if ( $args['check_enabled'] && ! wp_revisions_enabled( $post ) ) {
return array();
}
$query_args = array(
'post_parent' => $post->ID,
'post_type' => 'revision',
'posts_per_page' => -1,
'post_status' => 'any',
'orderby' => $args['orderby'],
'order' => $args['order'],
);
$query = new WP_Query( $query_args );
return $query->posts;
}
这个函数主要做了:
- 参数处理: 处理传入的参数,例如排序方式、排序字段等。
- 构建查询: 构建一个
WP_Query
对象,查询post_parent
为原始文章ID,post_type
为revision
的所有文章。 - 返回结果: 返回查询到的所有修订版本。
六、启用/禁用修订版本:wp_revisions_enabled()
和 wp_revisions_to_keep()
WordPress允许你控制是否启用修订版本,以及保留多少个修订版本。这两个函数就是用来控制这些行为的。
/**
* Determines whether revisions are enabled.
*
* @since 2.6.0
*
* @param WP_Post|int $post Post object or ID.
* @return bool Whether revisions are enabled.
*/
function wp_revisions_enabled( $post = null ) {
if ( ! defined( 'WP_POST_REVISIONS' ) ) {
return true;
}
if ( false === WP_POST_REVISIONS ) {
return false;
}
if ( true === WP_POST_REVISIONS ) {
return true;
}
if ( is_numeric( WP_POST_REVISIONS ) ) {
return (int) WP_POST_REVISIONS > 0;
}
return true;
}
/**
* Determines how many revisions to keep.
*
* @since 2.6.0
*
* @return int Number of revisions to keep.
*/
function wp_revisions_to_keep() {
if ( ! defined( 'WP_POST_REVISIONS' ) ) {
return 0;
}
if ( is_numeric( WP_POST_REVISIONS ) ) {
return (int) WP_POST_REVISIONS;
}
return 0;
}
你可以在wp-config.php
文件中定义WP_POST_REVISIONS
常量来控制修订版本的行为:
define('WP_POST_REVISIONS', true);
:启用修订版本,保留所有修订版本。define('WP_POST_REVISIONS', false);
:禁用修订版本。define('WP_POST_REVISIONS', 3);
:启用修订版本,最多保留3个修订版本。
七、删除修订版本:wp_delete_post_revision()
这个函数用于删除指定的修订版本。
/**
* Deletes a post revision.
*
* @since 2.6.0
*
* @param int|WP_Post $revision Revision ID or WP_Post object.
* @return bool|WP_Error True on success, false or WP_Error on failure.
*/
function wp_delete_post_revision( $revision ) {
$revision = get_post( $revision );
if ( ! $revision ) {
return false;
}
if ( 'revision' !== $revision->post_type ) {
return false;
}
if ( ! current_user_can( 'delete_post', $revision->ID ) ) {
return new WP_Error( 'edit_others_posts', __( 'Sorry, you are not allowed to delete revisions on this post.' ) );
}
$result = wp_delete_post( $revision->ID, true );
return $result;
}
八、核心函数总结
为了方便大家记忆,我把这些核心函数整理成一个表格:
函数名 | 功能描述 |
---|---|
wp_save_post_revision() |
保存文章修订版本。 |
wp_autosave_post() |
自动保存文章。 |
wp_get_post_revisions() |
获取文章的修订版本。 |
wp_revisions_enabled() |
判断是否启用了修订版本。 |
wp_revisions_to_keep() |
获取最多保留多少个修订版本。 |
wp_delete_post_revision() |
删除指定的修订版本。 |
九、一些小技巧和注意事项
- 修订版本过多会影响性能: 过多的修订版本会占用数据库空间,并且在编辑文章时会增加加载时间。所以,建议根据实际情况设置
WP_POST_REVISIONS
常量,限制修订版本的数量。 - 可以使用插件来管理修订版本: 有很多插件可以帮助你更方便地管理修订版本,例如删除旧的修订版本、比较不同版本之间的差异等等。
- 自动保存是临时的: 自动保存版本不会永久保存,当你手动保存文章后,自动保存版本会被删除。
十、实战演练:如何自定义修订版本功能
虽然WordPress已经提供了强大的修订版本功能,但有时候我们可能需要根据自己的需求进行定制。
场景一:只为特定文章类型启用修订版本
默认情况下,修订版本对所有文章类型都是启用的。如果我们只想为post
类型的文章启用修订版本,可以在functions.php
文件中添加以下代码:
add_filter( 'wp_revisions_enabled', 'my_custom_revisions_enabled', 10, 2 );
function my_custom_revisions_enabled( $enabled, $post ) {
if ( $post->post_type == 'post' ) {
return $enabled; // 使用默认设置
} else {
return false; // 禁用其他文章类型的修订版本
}
}
场景二:根据用户角色设置修订版本数量
我们可以根据用户的角色来设置不同的修订版本数量。例如,管理员可以保留更多的修订版本,而普通用户则只能保留较少的修订版本。
add_filter( 'wp_revisions_to_keep', 'my_custom_revisions_to_keep' );
function my_custom_revisions_to_keep() {
if ( current_user_can( 'administrator' ) ) {
return 5; // 管理员保留5个修订版本
} else {
return 2; // 普通用户保留2个修订版本
}
}
场景三:在文章列表中显示修订版本数量
我们可以在文章列表中添加一列,显示每个文章的修订版本数量。
add_filter( 'manage_posts_columns', 'my_custom_posts_columns' );
add_action( 'manage_posts_custom_column', 'my_custom_posts_column_content', 10, 2 );
function my_custom_posts_columns( $columns ) {
$columns['revisions'] = 'Revisions';
return $columns;
}
function my_custom_posts_column_content( $column, $post_id ) {
if ( $column == 'revisions' ) {
$revisions = wp_get_post_revisions( $post_id );
echo count( $revisions );
}
}
十一、总结
WP_Post_Revisions
类是WordPress中一个非常重要的组成部分,它为我们提供了文章修订版本的管理机制,帮助我们避免了数据丢失的风险。通过理解这个类的核心函数和工作原理,我们可以更好地利用修订版本功能,并且可以根据自己的需求进行定制。
希望今天的讲解能够帮助大家更深入地了解WordPress的修订版本机制。下次再见!