各位观众老爷,晚上好!我是你们的老朋友,人称“代码界的段子手”——阿码。今天咱要扒一扒 WordPress 里面一个“杀人不眨眼”的函数:wp_delete_post()
。别害怕,我说的“杀人”是杀帖子,而且是“杀”得干干净净的那种!
引子:故事从这里开始
话说江湖上流传着这么一句话:“WordPress 虽好,删帖要谨慎!” 为什么呢?因为 WordPress 的帖子可不是孤零零的存在,它像一个蜈蚣,身上挂满了元数据、评论、附件等等“小弟”。你要是直接用 SQL 语句咔嚓一下删掉主贴,那些“小弟”可就成了孤魂野鬼,数据库里留下了一堆垃圾数据。
这时候,wp_delete_post()
就闪亮登场了!它就像一个专业的“清道夫”,不但能删掉主贴,还能把那些相关的“小弟”一并处理掉,保证数据库的干净整洁。
wp_delete_post()
的庐山真面目
让我们先睹为快,看看 wp_delete_post()
函数的源码(基于 WordPress 最新版本):
function wp_delete_post( $postid, $force_delete = false ) {
global $wpdb;
$postid = absint( $postid );
if ( ! $postid ) {
return false;
}
$post = get_post( $postid );
if ( ! $post ) {
return false;
}
$post_type_object = get_post_type_object( $post->post_type );
if ( ! current_user_can( $post_type_object->cap->delete_post, $postid ) ) {
return false;
}
if ( 'attachment' === $post->post_type ) {
return wp_delete_attachment( $postid, $force_delete );
}
/**
* Fires before a post is deleted, at the start of the 'wp_delete_post' function.
*
* @since 4.3.0
*
* @param int $postid Post ID.
*/
do_action( 'wp_delete_post', $postid );
if ( 'trash' === $post->post_status && ! $force_delete ) {
return wp_untrash_post( $postid );
}
/**
* Fires before trashing or deleting a post.
*
* @since 2.9.0
*
* @param int $postid Post ID.
*/
do_action( 'before_delete_post', $postid );
if ( $force_delete ) {
/**
* Fires before a post is permanently deleted.
*
* @since 3.2.0
*
* @param int $postid Post ID.
*/
do_action( 'delete_post', $postid );
$result = $wpdb->delete( $wpdb->posts, array( 'ID' => $postid ) );
if ( ! $result ) {
return false;
}
wp_delete_post_terms( $postid, get_object_taxonomies( $post ) );
delete_post_meta( $postid );
$comment_ids = $wpdb->get_col( $wpdb->prepare( "SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = %d", $postid ) );
foreach ( $comment_ids as $comment_id ) {
wp_delete_comment( $comment_id, true );
}
wp_delete_post_revisions( $postid );
clean_post_cache( $postid );
/**
* Fires after a post is permanently deleted.
*
* @since 2.2.0
*
* @param int $postid Post ID.
*/
do_action( 'after_delete_post', $postid );
} else {
wp_trash_post( $postid );
return $post;
}
return $post;
}
怎么样,是不是感觉有点长?别怕,咱们一点一点来分析。
源码逐行解读
-
函数定义:
function wp_delete_post( $postid, $force_delete = false ) {
wp_delete_post()
:函数名,不用多说。$postid
:要删除的帖子 ID,必须是整数。$force_delete
:是否强制删除(彻底删除)。默认为false
,表示放入回收站。如果设置为true
,则直接从数据库中删除。这个参数非常重要,关系到你的帖子是进“回收站”还是直接“火葬场”。
-
安全检查:
global $wpdb; $postid = absint( $postid ); if ( ! $postid ) { return false; } $post = get_post( $postid ); if ( ! $post ) { return false; } $post_type_object = get_post_type_object( $post->post_type ); if ( ! current_user_can( $post_type_object->cap->delete_post, $postid ) ) { return false; }
global $wpdb;
:引入全局数据库对象,后面要用它来操作数据库。$postid = absint( $postid );
:把帖子 ID 转换成绝对整数,防止注入攻击。if ( ! $postid ) { return false; }
:如果帖子 ID 为空,直接返回false
,啥也不做。$post = get_post( $postid );
:根据帖子 ID 获取帖子对象。if ( ! $post ) { return false; }
:如果帖子不存在,直接返回false
。$post_type_object = get_post_type_object( $post->post_type );
:获取帖子类型对象,比如 post、page、attachment 等。if ( ! current_user_can( $post_type_object->cap->delete_post, $postid ) ) { return false; }
:检查当前用户是否有权限删除该帖子。WordPress 的权限管理非常严格,不是谁想删就能删的。
这一段代码主要是做一些基本的安全检查,确保要删除的帖子存在,并且当前用户有权限删除它。
-
附件特殊处理:
if ( 'attachment' === $post->post_type ) { return wp_delete_attachment( $postid, $force_delete ); }
如果帖子类型是附件(attachment),则调用
wp_delete_attachment()
函数来删除附件。附件的处理方式和普通帖子略有不同,需要单独处理。 -
钩子(Hooks):
/** * Fires before a post is deleted, at the start of the 'wp_delete_post' function. * * @since 4.3.0 * * @param int $postid Post ID. */ do_action( 'wp_delete_post', $postid ); /** * Fires before trashing or deleting a post. * * @since 2.9.0 * * @param int $postid Post ID. */ do_action( 'before_delete_post', $postid ); if ( $force_delete ) { /** * Fires before a post is permanently deleted. * * @since 3.2.0 * * @param int $postid Post ID. */ do_action( 'delete_post', $postid ); }
WordPress 的钩子机制非常强大,允许开发者在特定事件发生时执行自定义代码。这里使用了三个钩子:
wp_delete_post
:在wp_delete_post()
函数开始时触发。before_delete_post
:在帖子被放入回收站或永久删除之前触发。delete_post
:在帖子被永久删除之前触发。
通过这些钩子,你可以实现各种各样的功能,比如在删除帖子前发送邮件通知管理员,或者记录删除日志等等。
-
回收站 vs. 永久删除:
if ( 'trash' === $post->post_status && ! $force_delete ) { return wp_untrash_post( $postid ); } if ( $force_delete ) { // 永久删除的代码 } else { wp_trash_post( $postid ); return $post; }
- 如果帖子的状态是
trash
(回收站),并且$force_delete
为false
,则调用wp_untrash_post()
函数将帖子从回收站中恢复。 - 如果
$force_delete
为true
,则执行永久删除的代码。 - 否则,调用
wp_trash_post()
函数将帖子放入回收站。
这里体现了 WordPress 的一个重要设计理念:先放入回收站,给用户一个后悔的机会。只有在用户明确表示要永久删除时,才会真正从数据库中删除。
- 如果帖子的状态是
-
永久删除的核心代码:
if ( $force_delete ) { /** * Fires before a post is permanently deleted. * * @since 3.2.0 * * @param int $postid Post ID. */ do_action( 'delete_post', $postid ); $result = $wpdb->delete( $wpdb->posts, array( 'ID' => $postid ) ); if ( ! $result ) { return false; } wp_delete_post_terms( $postid, get_object_taxonomies( $post ) ); delete_post_meta( $postid ); $comment_ids = $wpdb->get_col( $wpdb->prepare( "SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = %d", $postid ) ); foreach ( $comment_ids as $comment_id ) { wp_delete_comment( $comment_id, true ); } wp_delete_post_revisions( $postid ); clean_post_cache( $postid ); /** * Fires after a post is permanently deleted. * * @since 2.2.0 * * @param int $postid Post ID. */ do_action( 'after_delete_post', $postid ); }
这部分代码是
wp_delete_post()
函数的核心,负责永久删除帖子以及相关的元数据、评论和修订版本。$result = $wpdb->delete( $wpdb->posts, array( 'ID' => $postid ) );
:从wp_posts
表中删除帖子。wp_delete_post_terms( $postid, get_object_taxonomies( $post ) );
:删除帖子相关的分类和标签(terms)。delete_post_meta( $postid );
:删除帖子相关的元数据(custom fields)。$comment_ids = $wpdb->get_col( $wpdb->prepare( "SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = %d", $postid ) );
:获取帖子相关的评论 ID。foreach ( $comment_ids as $comment_id ) { wp_delete_comment( $comment_id, true ); }
:循环删除帖子相关的评论。注意,这里$force_delete
设置为true
,表示永久删除评论。wp_delete_post_revisions( $postid );
:删除帖子的修订版本。clean_post_cache( $postid );
:清除帖子缓存,确保下次访问时获取的是最新的数据。
这一段代码非常重要,它保证了删除帖子的彻底性,避免了数据库中留下垃圾数据。
-
最后的钩子:
/** * Fires after a post is permanently deleted. * * @since 2.2.0 * * @param int $postid Post ID. */ do_action( 'after_delete_post', $postid );
after_delete_post
:在帖子被永久删除之后触发。
这个钩子可以用来执行一些清理工作,比如更新统计数据,或者发送删除成功的通知等等。
-
返回值:
return $post;
- 如果帖子被放入回收站,则返回帖子对象。
- 如果帖子被永久删除,则返回帖子对象。注意,即使帖子已经被删除,仍然返回帖子对象,这可能是为了方便后续操作。
重点函数解析
-
wp_delete_post_terms()
:这个函数负责删除帖子相关的分类和标签(terms)。它会先获取帖子所有的分类和标签,然后循环调用
wp_remove_object_terms()
函数来删除它们。function wp_delete_post_terms( $post_id, $taxonomies ) { foreach ( (array) $taxonomies as $taxonomy ) { $terms = wp_get_object_terms( $post_id, $taxonomy, array( 'fields' => 'ids' ) ); wp_remove_object_terms( $post_id, $terms, $taxonomy ); } }
-
delete_post_meta()
:这个函数负责删除帖子相关的元数据(custom fields)。它会根据帖子 ID 从
wp_postmeta
表中删除所有相关的记录。function delete_post_meta( $post_id ) { global $wpdb; $post_id = absint( $post_id ); if ( ! $post_id ) { return false; } $wpdb->delete( $wpdb->postmeta, array( 'post_id' => $post_id ) ); }
-
wp_delete_comment()
:这个函数负责删除评论。它可以删除单个评论,也可以删除所有与帖子相关的评论。
function wp_delete_comment( $comment_id, $force_delete = false ) { global $wpdb; $comment_id = absint( $comment_id ); if ( ! $comment_id ) { return false; } $comment = get_comment( $comment_id ); if ( ! $comment ) { return false; } /** * Fires before a comment is deleted from the database. * * @since 2.7.0 * * @param int $comment_id The comment ID. * @param WP_Comment $comment The comment object. */ do_action( 'delete_comment', $comment_id, $comment ); if ( $force_delete ) { /** * Fires immediately before a comment is permanently deleted from the database. * * @since 2.7.0 * * @param int $comment_id The comment ID. * @param WP_Comment $comment The comment object. */ do_action( 'before_delete_comment', $comment_id, $comment ); $result = $wpdb->delete( $wpdb->comments, array( 'comment_ID' => $comment_id ) ); if ( ! $result ) { return false; } wp_delete_comment_meta_by_mid( $comment_id ); /** * Fires immediately after a comment is permanently deleted from the database. * * @since 2.7.0 * * @param int $comment_id The comment ID. */ do_action( 'after_delete_comment', $comment_id ); } else { wp_trash_comment( $comment_id ); } /** * Fires after a comment has been deleted from the database. * * @since 2.7.0 * * @param int $comment_id The comment ID. */ do_action( 'deleted_comment', $comment_id ); return true; }
-
wp_delete_post_revisions()
:这个函数负责删除帖子的修订版本。修订版本是 WordPress 自动保存的帖子历史版本,可以用来恢复之前的版本。
function wp_delete_post_revisions( $post_id ) { global $wpdb; $post_id = absint( $post_id ); if ( ! $post_id ) { return false; } $revision_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'revision'", $post_id ) ); if ( $revision_ids ) { foreach ( $revision_ids as $revision_id ) { wp_delete_post( $revision_id, true ); } } }
使用场景举例
-
从后台删除帖子:
当你从 WordPress 后台删除一个帖子时,WordPress 会自动调用
wp_delete_post()
函数。默认情况下,帖子会被放入回收站。如果你想永久删除帖子,可以在回收站中选择“永久删除”。 -
自定义代码删除帖子:
你也可以在自定义代码中调用
wp_delete_post()
函数来删除帖子。例如:$post_id = 123; // 要删除的帖子 ID $force_delete = true; // 永久删除 $result = wp_delete_post( $post_id, $force_delete ); if ( $result ) { echo '帖子删除成功!'; } else { echo '帖子删除失败!'; }
-
插件开发:
如果你正在开发一个 WordPress 插件,可能需要删除帖子。
wp_delete_post()
函数是你的好帮手。
注意事项
- 权限问题: 确保当前用户有权限删除帖子。
$force_delete
参数: 谨慎使用$force_delete
参数。一旦设置为true
,帖子将被永久删除,无法恢复。- 钩子: 充分利用 WordPress 的钩子机制,可以在删除帖子前后执行自定义代码。
总结
wp_delete_post()
函数是 WordPress 中一个非常重要的函数,它负责删除帖子以及相关的元数据、评论和修订版本。通过分析源码,我们可以深入了解 WordPress 的工作原理,并更好地使用它。记住,删帖需谨慎,请三思而后行!
结尾
今天就到这里了,希望大家对 wp_delete_post()
函数有了更深入的了解。下次再遇到删帖的问题,就不用再抓瞎了。记住,阿码永远是你最可靠的“代码向导”! 咱们下期再见! 祝大家代码无 Bug,生活更精彩!