各位观众老爷,晚上好!我是你们的老朋友,今天咱们来聊聊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网站的数据,并且可以为自定义的删除操作提供参考。
好了,今天的讲座就到这里。希望大家有所收获!下次再见!