各位观众老爷,晚上好!我是你们的老朋友,今天咱们来聊聊WordPress里一个有点狠的角色——wp_delete_post()
,这哥们儿专干删除文章的活儿,而且下手挺黑,连带着文章的元数据和评论都给一锅端了。今天咱们就扒一扒它的老底,看看它到底是怎么做到的。
开场白:删除的艺术
在WordPress的世界里,删除文章可不是简简单单地把数据库里的一行数据删掉那么简单。文章就像个大户人家,底下管着一堆人:元数据是他的财务管家,评论是来访的客人,附件是他的家产。要彻底删除一篇文章,就得把这些关系都理清楚,一个都不能放过。wp_delete_post()
就是干这事的。
第一幕:wp_delete_post()
的登场
首先,让我们看看wp_delete_post()
的庐山真面目:
/**
* Deletes a post.
*
* @since 2.0.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param int $postid Post ID.
* @param bool $force_delete Optional. Whether to bypass Trash and force deletion.
* Default false.
* @return WP_Post|false WP_Post on success. False on failure.
*/
function wp_delete_post( $postid = 0, $force_delete = false ) {
global $wpdb;
$postid = (int) $postid;
if ( ! $postid ) {
return false;
}
$post = get_post( $postid );
if ( ! $post ) {
return false;
}
$trashed = false;
if ( ! $force_delete && EMPTY_TRASH_DAYS && ( 'trash' !== $post->post_status ) ) {
// ... (省略了垃圾箱相关的代码,后面会提到)
} else {
// ... (省略了强制删除相关的代码,后面会提到)
}
return $post;
}
简单来说,这个函数接收两个参数:
$postid
:要删除的文章ID。$force_delete
:是否强制删除,跳过垃圾箱。默认是false
,也就是先扔到垃圾箱。
第二幕:判断,判断,再判断
函数一开始,先对$postid
进行类型转换,确保是个整数。然后,它会用get_post()
函数尝试获取文章对象。如果$postid
是0或者文章不存在,那就直接打道回府,返回false
。毕竟,巧妇难为无米之炊嘛。
第三幕:垃圾箱的诱惑 (如果 $force_delete
是 false
)
如果$force_delete
是false
,并且启用了垃圾箱功能(EMPTY_TRASH_DAYS
大于0),并且文章不在垃圾箱里('trash' !== $post->post_status
),那么文章会被移动到垃圾箱,而不是直接删除。
$trashed = wp_trash_post( $postid );
if ( $trashed ) {
return $post;
} else {
return false;
}
这里用到了wp_trash_post()
函数,这个函数只是简单地把文章的状态改为'trash'
。 就像把犯人关进监狱,并没有真正处决。
第四幕:强制删除的铁拳 (如果 $force_delete
是 true
)
如果$force_delete
是true
,或者垃圾箱功能没启用,或者文章已经在垃圾箱里了,那就直接进入强制删除的环节。这才是真正的重头戏。
/**
* Fires before a post is deleted, at the start of the 'wp_delete_post' function.
*
* @since 4.4.0
*
* @param int $postid Post ID.
*/
do_action( 'before_delete_post', $postid );
$post = get_post( $postid );
if ( ! $wpdb->delete( $wpdb->posts, array( 'ID' => $postid ) ) ) {
return false;
}
clean_post_cache( $postid );
// Delete Post Meta
delete_post_meta( $postid );
// Delete all attachments
$children = get_posts(
array(
'post_parent' => $postid,
'post_type' => 'attachment',
'fields' => 'ids',
'numberposts' => -1,
)
);
if ( ! empty( $children ) ) {
foreach ( $children as $child ) {
wp_delete_attachment( $child, $force_delete );
}
}
wp_delete_object_term_relationships( $postid, get_object_taxonomies( $post->post_type ) );
$comment_ids = $wpdb->get_col( $wpdb->prepare( "SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = %d", $postid ) );
if ( $comment_ids ) {
$wpdb->query( "DELETE FROM $wpdb->comments WHERE comment_ID IN (" . implode( ',', array_map( 'intval', $comment_ids ) ) . ")" );
$wpdb->query( "DELETE FROM $wpdb->commentmeta WHERE comment_id IN (" . implode( ',', array_map( 'intval', $comment_ids ) ) . ")" );
wp_update_comment_count_now( $postid );
}
$post->post_status = 'deleted';
/**
* Fires after a post is deleted.
*
* @since 2.0.0
*
* @param int $postid Post ID.
*/
do_action( 'deleted_post', $postid );
让我们一步一步来看:
do_action( 'before_delete_post', $postid );
: 在删除文章之前,先触发一个before_delete_post
的动作钩子。这允许其他插件或者主题在文章被删除之前做一些事情,比如备份数据或者发送通知。这是一种解耦的设计思想,让不同的模块可以协同工作,而不需要直接修改wp_delete_post()
函数的代码。$wpdb->delete( $wpdb->posts, array( 'ID' => $postid ) )
: 这是真正删除文章的SQL语句。$wpdb
是WordPress的数据库操作对象,delete()
方法用于删除数据库表中的数据。这里删除的是$wpdb->posts
表(也就是文章表)中ID
等于$postid
的记录。clean_post_cache( $postid );
: 删除文章后,需要清理文章缓存,避免下次访问时仍然显示旧的数据。clean_post_cache()
函数就是干这个的。delete_post_meta( $postid );
: 这行代码调用了delete_post_meta()
函数,用于删除与文章相关的元数据。$children = get_posts(...)
: 这部分代码用于获取文章的所有附件。附件也是一种文章类型(post_type
为attachment
),并且它们的post_parent
字段指向父文章的ID。foreach ( $children as $child ) { wp_delete_attachment( $child, $force_delete ); }
: 遍历所有附件,并调用wp_delete_attachment()
函数删除它们。注意,这里也使用了$force_delete
参数,确保附件也被强制删除。wp_delete_object_term_relationships( $postid, get_object_taxonomies( $post->post_type ) )
: 这行代码用于删除文章与分类、标签等分类法的关联关系。wp_delete_object_term_relationships()
函数负责删除这些关联关系。-
删除评论: 接下来,就是删除评论的环节。
$comment_ids = $wpdb->get_col( $wpdb->prepare( "SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = %d", $postid ) )
:首先,查询所有与该文章相关的评论ID。$wpdb->query( "DELETE FROM $wpdb->comments WHERE comment_ID IN (" . implode( ',', array_map( 'intval', $comment_ids ) ) . ")" )
:然后,根据评论ID删除wp_comments
表中的评论。$wpdb->query( "DELETE FROM $wpdb->commentmeta WHERE comment_id IN (" . implode( ',', array_map( 'intval', $comment_ids ) ) . ")" )
:最后,删除wp_commentmeta
表中与这些评论相关的元数据。wp_update_comment_count_now( $postid )
:更新文章的评论计数。
$post->post_status = 'deleted';
: 将文章的状态设置为'deleted'
。这并不是一个标准的文章状态,可能是为了标记文章已经被删除,方便后续处理。do_action( 'deleted_post', $postid );
: 在文章被删除后,触发一个deleted_post
的动作钩子。这允许其他插件或者主题在文章被删除之后做一些事情,比如更新索引或者发送通知。
第五幕:元数据的清理
delete_post_meta()
函数是删除元数据的关键,让我们看看它的代码:
/**
* Delete all meta data matching the specified post ID.
*
* @since 2.9.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param int $post_id Post ID.
* @return bool Whether the post meta was successfully deleted.
*/
function delete_post_meta( $post_id ) {
global $wpdb;
if ( ! $post_id = absint( $post_id ) ) {
return false;
}
/**
* Fires before post meta is deleted.
*
* @since 3.0.0
*
* @param int $post_id Post ID.
*/
do_action( 'delete_post_meta', $post_id );
$result = $wpdb->delete( $wpdb->postmeta, array( 'post_id' => $post_id ) );
clean_post_cache( $post_id );
/**
* Fires after post meta is deleted.
*
* @since 3.0.0
*
* @param int $post_id Post ID.
*/
do_action( 'deleted_post_meta', $post_id );
return (bool) $result;
}
这个函数也很简单:
do_action( 'delete_post_meta', $post_id );
: 在删除元数据之前,触发一个delete_post_meta
动作钩子。$wpdb->delete( $wpdb->postmeta, array( 'post_id' => $post_id ) )
: 使用SQL语句删除wp_postmeta
表中post_id
等于$post_id
的所有记录。clean_post_cache( $post_id );
: 清理文章缓存。do_action( 'deleted_post_meta', $post_id );
: 在删除元数据之后,触发一个deleted_post_meta
动作钩子。
第六幕:评论的覆灭
删除评论的代码在wp_delete_post()
函数中已经展示过了,这里再简单回顾一下:
- 查询评论ID: 首先,查询所有与该文章相关的评论ID。
- 删除评论: 然后,根据评论ID删除
wp_comments
表中的评论。 - 删除评论元数据: 最后,删除
wp_commentmeta
表中与这些评论相关的元数据。
总结:wp_delete_post()
的生死簿
让我们用一个表格来总结一下wp_delete_post()
的工作流程:
步骤 | 描述 | 涉及函数/SQL |
---|---|---|
1. 参数校验 | 检查$postid 是否有效,获取文章对象。 |
get_post() |
2. 垃圾箱判断 | 如果$force_delete 为false ,且启用垃圾箱,则将文章移动到垃圾箱。 |
wp_trash_post() |
3. 删除前钩子 | 触发before_delete_post 动作钩子。 |
do_action( 'before_delete_post', $postid ) |
4. 删除文章 | 从wp_posts 表中删除文章记录。 |
$wpdb->delete( $wpdb->posts, array( 'ID' => $postid ) ) |
5. 清理缓存 | 清理文章缓存。 | clean_post_cache( $postid ) |
6. 删除元数据 | 删除与文章相关的元数据。 | delete_post_meta( $postid ) , $wpdb->delete( $wpdb->postmeta, array( 'post_id' => $postid ) ) |
7. 删除附件 | 获取并删除文章的所有附件。 | get_posts( array( 'post_parent' => $postid, 'post_type' => 'attachment' ) ) , wp_delete_attachment( $child, $force_delete ) |
8. 删除分类/标签关联关系 | 删除文章与分类、标签等分类法的关联关系。 | wp_delete_object_term_relationships( $postid, get_object_taxonomies( $post->post_type ) ) |
9. 删除评论 | 删除与文章相关的评论和评论元数据。 | $wpdb->get_col( "SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = %d" ) , $wpdb->query( "DELETE FROM $wpdb->comments WHERE comment_ID IN (...)" ) , $wpdb->query( "DELETE FROM $wpdb->commentmeta WHERE comment_id IN (...)" ) , wp_update_comment_count_now( $postid ) |
10. 设置文章状态 | 将文章状态设置为'deleted' 。 |
$post->post_status = 'deleted' |
11. 删除后钩子 | 触发deleted_post 动作钩子。 |
do_action( 'deleted_post', $postid ) |
补充说明:附件的删除
wp_delete_attachment()
函数用于删除附件,它的代码也值得一看:
/**
* Deletes an attachment.
*
* @since 2.0.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param int $post_id Attachment ID.
* @param bool $force_delete Whether to bypass Trash and force deletion. Default false.
* @return WP_Post|false WP_Post on success. False on failure.
*/
function wp_delete_attachment( $post_id = 0, $force_delete = false ) {
global $wpdb;
$post_id = (int) $post_id;
if ( ! $post_id ) {
return false;
}
$post = get_post( $post_id );
if ( ! $post ) {
return false;
}
if ( 'attachment' !== $post->post_type ) {
return false;
}
/**
* Fires before an attachment is deleted, at the start of the 'wp_delete_attachment' function.
*
* @since 4.4.0
*
* @param int $post_id Attachment ID.
*/
do_action( 'before_delete_attachment', $post_id );
if ( ! $force_delete && EMPTY_TRASH_DAYS && ( 'trash' !== $post->post_status ) ) {
return wp_trash_post( $post_id );
}
$file = get_attached_file( $post_id );
if ( $file ) {
/**
* Filters whether to run wp_delete_file() when deleting an attachment.
*
* @since 3.6.0
*
* @param bool $delete Whether to delete the file. Default true.
* @param int $post_id Attachment ID.
*/
if ( apply_filters( 'wp_delete_file', true, $post_id ) ) {
$delete_result = wp_delete_file( $file );
if ( ! empty( $delete_result['error'] ) ) {
return false;
}
}
}
$result = wp_delete_post( $post_id, true );
/**
* Fires after an attachment is deleted.
*
* @since 2.0.0
*
* @param int $post_id Attachment ID.
*/
do_action( 'deleted_attachment', $post_id );
return $result;
}
这个函数和wp_delete_post()
类似,也是先进行参数校验,然后判断是否需要放入垃圾箱。如果需要强制删除,它会先删除附件对应的文件(使用wp_delete_file()
函数),然后调用wp_delete_post()
函数删除附件的文章记录。
总结
wp_delete_post()
是一个功能强大的函数,它不仅可以删除文章,还可以删除与文章相关的元数据、评论和附件。它通过一系列的SQL查询和钩子函数,确保了删除操作的完整性和灵活性。理解wp_delete_post()
的工作原理,可以帮助我们更好地管理WordPress网站的数据,并且可以为自定义的删除操作提供参考。
好了,今天的讲座就到这里。希望大家有所收获!下次再见!