wp_delete_post()
概述
wp_delete_post() 是 WordPress 核心函数,用于将文章或页面移至回收站或永久删除。当永久删除时,会连带删除所有关联数据,如评论、元数据和分类术语。默认情况下,文章或页面会移至回收站,除非回收站被禁用、项目已在回收站中,或 $force_delete 参数设为 true。
关键要点
- 函数接受两个参数:$post_id(必需,文章 ID)和 $force_delete(可选,布尔值,默认为 false,决定是否绕过回收站强制删除)。
- 返回值:成功时返回 WP_Post 对象,失败时返回 false 或 null。
- 对于文章或页面类型,若 $force_delete 为 false、回收站功能启用且文章不在回收站中,函数会自动调用 wp_trash_post()。
- 对于附件类型,会调用 wp_delete_attachment() 处理。
- 删除过程会触发多个钩子,如 pre_delete_post、before_delete_post、delete_post、deleted_post 等,允许开发者干预或执行额外操作。
- 永久删除时,会清理相关数据,包括评论、元数据、分类关系、修订版本和子页面链接。
- 注意:自定义文章类型默认会被永久删除,不受 $force_delete 参数影响,如需移至回收站应使用 wp_trash_post()。
代码示例
// 删除 ID 为 1 的文章,默认移至回收站
wp_delete_post( 1 );
// 强制永久删除 ID 为 2 的文章
wp_delete_post( 2, true );
// 删除所有自定义文章类型“products”的文章
function wpdocs_delete_all_products() {
$myproducts = get_pages( array( 'post_type' => 'products') );
foreach ( $myproducts as $myproduct ) {
wp_delete_post( $myproduct->ID, true ); // true 为永久删除,false 则移至回收站
}
}
add_action( 'init', 'wpdocs_delete_all_products' );注意事项
- 使用 $force_delete 参数时需谨慎,因为永久删除不可恢复。
- 对于自定义文章类型,wp_delete_post() 默认永久删除,不遵循回收站逻辑,开发者应显式处理回收站需求。
- 函数内部涉及数据库操作,建议在适当钩子或权限检查后调用,以避免数据不一致。
Trashes or deletes a post or page.
Description
When the post and page is permanently deleted, everything that is tied to it is deleted also. This includes comments, post meta fields, and terms associated with the post.
The post or page is moved to Trash instead of permanently deleted unless Trash is disabled, item is already in the Trash, or $force_delete is true.
See also
Parameters
$post_idintrequired-
Post ID. (The default of 0 is for historical reasons; providing it is incorrect.)
$force_deletebooloptional-
Whether to bypass Trash and force deletion.
Default:
false
Source
function wp_delete_post( $post_id = 0, $force_delete = false ) {
global $wpdb;
$post_id = (int) $post_id;
if ( $post_id <= 0 ) {
_doing_it_wrong( __FUNCTION__, __( 'The post ID must be greater than 0.' ), '6.9.0' );
return false;
}
$post = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE ID = %d", $post_id ) );
if ( ! $post ) {
return $post;
}
$post = get_post( $post );
if ( ! $force_delete
&& ( 'post' === $post->post_type || 'page' === $post->post_type )
&& 'trash' !== get_post_status( $post_id ) && EMPTY_TRASH_DAYS
) {
return wp_trash_post( $post_id );
}
if ( 'attachment' === $post->post_type ) {
return wp_delete_attachment( $post_id, $force_delete );
}
/**
* Filters whether a post deletion should take place.
*
* @since 4.4.0
*
* @param WP_Post|false|null $check Whether to go forward with deletion. Anything other than null will short-circuit deletion.
* @param WP_Post $post Post object.
* @param bool $force_delete Whether to bypass the Trash.
*/
$check = apply_filters( 'pre_delete_post', null, $post, $force_delete );
if ( null !== $check ) {
return $check;
}
/**
* Fires before a post is deleted, at the start of wp_delete_post().
*
* @since 3.2.0
* @since 5.5.0 Added the `$post` parameter.
*
* @see wp_delete_post()
*
* @param int $post_id Post ID.
* @param WP_Post $post Post object.
*/
do_action( 'before_delete_post', $post_id, $post );
delete_post_meta( $post_id, '_wp_trash_meta_status' );
delete_post_meta( $post_id, '_wp_trash_meta_time' );
wp_delete_object_term_relationships( $post_id, get_object_taxonomies( $post->post_type ) );
$parent_data = array( 'post_parent' => $post->post_parent );
$parent_where = array( 'post_parent' => $post_id );
if ( is_post_type_hierarchical( $post->post_type ) ) {
// Point children of this page to its parent, also clean the cache of affected children.
$children_query = $wpdb->prepare(
"SELECT * FROM $wpdb->posts WHERE post_parent = %d AND post_type = %s",
$post_id,
$post->post_type
);
$children = $wpdb->get_results( $children_query );
if ( $children ) {
$wpdb->update( $wpdb->posts, $parent_data, $parent_where + array( 'post_type' => $post->post_type ) );
}
}
// Do raw query. wp_get_post_revisions() is filtered.
$revision_ids = $wpdb->get_col(
$wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'revision'", $post_id )
);
// Use wp_delete_post (via wp_delete_post_revision) again. Ensures any meta/misplaced data gets cleaned up.
foreach ( $revision_ids as $revision_id ) {
wp_delete_post_revision( $revision_id );
}
// Point all attachments to this post up one level.
$wpdb->update( $wpdb->posts, $parent_data, $parent_where + array( 'post_type' => 'attachment' ) );
wp_defer_comment_counting( true );
$comment_ids = $wpdb->get_col(
$wpdb->prepare( "SELECT comment_ID FROM $wpdb->comments WHERE comment_post_ID = %d ORDER BY comment_ID DESC", $post_id )
);
foreach ( $comment_ids as $comment_id ) {
wp_delete_comment( $comment_id, true );
}
wp_defer_comment_counting( false );
$post_meta_ids = $wpdb->get_col(
$wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE post_id = %d ", $post_id )
);
foreach ( $post_meta_ids as $mid ) {
delete_metadata_by_mid( 'post', $mid );
}
/**
* Fires immediately before a post is deleted from the database.
*
* The dynamic portion of the hook name, `$post->post_type`, refers to
* the post type slug.
*
* @since 6.6.0
*
* @param int $post_id Post ID.
* @param WP_Post $post Post object.
*/
do_action( "delete_post_{$post->post_type}", $post_id, $post );
/**
* Fires immediately before a post is deleted from the database.
*
* @since 1.2.0
* @since 5.5.0 Added the `$post` parameter.
*
* @param int $post_id Post ID.
* @param WP_Post $post Post object.
*/
do_action( 'delete_post', $post_id, $post );
$result = $wpdb->delete( $wpdb->posts, array( 'ID' => $post_id ) );
if ( ! $result ) {
return false;
}
/**
* Fires immediately after a post is deleted from the database.
*
* The dynamic portion of the hook name, `$post->post_type`, refers to
* the post type slug.
*
* @since 6.6.0
*
* @param int $post_id Post ID.
* @param WP_Post $post Post object.
*/
do_action( "deleted_post_{$post->post_type}", $post_id, $post );
/**
* Fires immediately after a post is deleted from the database.
*
* @since 2.2.0
* @since 5.5.0 Added the `$post` parameter.
*
* @param int $post_id Post ID.
* @param WP_Post $post Post object.
*/
do_action( 'deleted_post', $post_id, $post );
clean_post_cache( $post );
if ( is_post_type_hierarchical( $post->post_type ) && $children ) {
foreach ( $children as $child ) {
clean_post_cache( $child );
}
}
wp_clear_scheduled_hook( 'publish_future_post', array( $post_id ) );
/**
* Fires after a post is deleted, at the conclusion of wp_delete_post().
*
* @since 3.2.0
* @since 5.5.0 Added the `$post` parameter.
*
* @see wp_delete_post()
*
* @param int $post_id Post ID.
* @param WP_Post $post Post object.
*/
do_action( 'after_delete_post', $post_id, $post );
return $post;
}
Hooks
- do_action( ‘after_delete_post’, int $post_id, WP_Post $post )
-
Fires after a post is deleted, at the conclusion of wp_delete_post() .
- do_action( ‘before_delete_post’, int $post_id, WP_Post $post )
-
Fires before a post is deleted, at the start of wp_delete_post() .
- do_action( ‘deleted_post’, int $post_id, WP_Post $post )
-
Fires immediately after a post is deleted from the database.
- do_action( “deleted_post_{$post->post_type}”, int $post_id, WP_Post $post )
-
Fires immediately after a post is deleted from the database.
- do_action( ‘delete_post’, int $post_id, WP_Post $post )
-
Fires immediately before a post is deleted from the database.
- do_action( “delete_post_{$post->post_type}”, int $post_id, WP_Post $post )
-
Fires immediately before a post is deleted from the database.
- apply_filters( ‘pre_delete_post’, WP_Post|false|null $check, WP_Post $post, bool $force_delete )
-
Filters whether a post deletion should take place.
Changelog
| Version | Description |
|---|---|
| 1.0.0 | Introduced. |
Skip to note 4 content
Tim
Beware: Custom Post Types will be deleted (not moved to trash) disregarding the $force_delete parameter. Use wp_trash_post() if you want to move a custom post to trash.
Skip to note 5 content
Codex
Delete Post
Deleting the WP default post “Hello World” which has ID 1.
Skip to note 6 content
Said El Bakkali
/** * Deletes all posts from "products" custom post type. */ function wpdocs_delete_all_products() { $myproducts = get_pages( array( 'post_type' => 'products') ); foreach ( $myproducts as $myproduct ) { // Delete all products. wp_delete_post( $myproduct->ID, true); // Set to False if you want to send them to Trash. } } add_action( 'init', 'wpdocs_delete_all_products' );