: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
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.
* @param WP_Post|false|null $delete Whether to go forward with 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 );
* Fires before a post is deleted, at the start of wp_delete_post().
* @since 5.5.0 Added the `$post` parameter.
* @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",
$children = $wpdb->get_results( $children_query );
$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
* @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 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 ) );
* Fires immediately after a post is deleted from the database.
* The dynamic portion of the hook name, `$post->post_type`, refers to
* @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 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 5.5.0 Added the `$post` parameter.
* @param int $post_id Post ID.
* @param WP_Post $post Post object.
do_action( 'after_delete_post', $post_id, $post );
* Resets the page_on_front, show_on_front, and page_for_post settings when
* a linked page is deleted or trashed.
* Also ensures the post is no longer sticky.
* @param int $post_id Post ID.
function _reset_front_page_settings_for_post( $post_id ) {
$post = get_post( $post_id );
if ( 'page' === $post->post_type ) {
* If the page is defined in option page_on_front or post_for_posts,
* adjust the corresponding options.
if ( get_option( 'page_on_front' ) == $post->ID ) {
update_option( 'show_on_front', 'posts' );
update_option( 'page_on_front', 0 );
if ( get_option( 'page_for_posts' ) == $post->ID ) {
update_option( 'page_for_posts', 0 );
unstick_post( $post->ID );
* Moves a post or page to the Trash
* If Trash is disabled, the post or page is permanently deleted.
* @param int $post_id Optional. Post ID. Default is the ID of the global `$post`
* if `EMPTY_TRASH_DAYS` equals true.
* @return WP_Post|false|null Post data on success, false or null on failure.
function wp_trash_post( $post_id = 0 ) {
if ( ! EMPTY_TRASH_DAYS ) {
return wp_delete_post( $post_id, true );
$post = get_post( $post_id );
if ( 'trash' === $post->post_status ) {
$previous_status = $post->post_status;
* Filters whether a post trashing should take place.
* @since 6.3.0 Added the `$previous_status` parameter.
* @param bool|null $trash Whether to go forward with trashing.
* @param WP_Post $post Post object.
* @param string $previous_status The status of the post about to be trashed.
$check = apply_filters( 'pre_trash_post', null, $post, $previous_status );
* Fires before a post is sent to the Trash.
* @since 6.3.0 Added the `$previous_status` parameter.
* @param int $post_id Post ID.
* @param string $previous_status The status of the post about to be trashed.
do_action( 'wp_trash_post', $post_id, $previous_status );
add_post_meta( $post_id, '_wp_trash_meta_status', $previous_status );
add_post_meta( $post_id, '_wp_trash_meta_time', time() );
$post_updated = wp_update_post(
'post_status' => 'trash',
wp_trash_post_comments( $post_id );
* Fires after a post is sent to the Trash.
* @since 6.3.0 Added the `$previous_status` parameter.
* @param int $post_id Post ID.
* @param string $previous_status The status of the post at the point where it was trashed.
do_action( 'trashed_post', $post_id, $previous_status );
* Restores a post from the Trash.
* @since 5.6.0 An untrashed post is now returned to 'draft' status by default, except for
* attachments which are returned to their original 'inherit' status.
* @param int $post_id Optional. Post ID. Default is the ID of the global `$post`.
* @return WP_Post|false|null Post data on success, false or null on failure.
function wp_untrash_post( $post_id = 0 ) {
$post = get_post( $post_id );
if ( 'trash' !== $post->post_status ) {
$previous_status = get_post_meta( $post_id, '_wp_trash_meta_status', true );
* Filters whether a post untrashing should take place.
* @since 5.6.0 Added the `$previous_status` parameter.
* @param bool|null $untrash Whether to go forward with untrashing.
* @param WP_Post $post Post object.
* @param string $previous_status The status of the post at the point where it was trashed.
$check = apply_filters( 'pre_untrash_post', null, $post, $previous_status );
* Fires before a post is restored from the Trash.
* @since 5.6.0 Added the `$previous_status` parameter.
* @param int $post_id Post ID.
* @param string $previous_status The status of the post at the point where it was trashed.
do_action( 'untrash_post', $post_id, $previous_status );
$new_status = ( 'attachment' === $post->post_type ) ? 'inherit' : 'draft';
* Filters the status that a post gets assigned when it is restored from the trash (untrashed).
* By default posts that are restored will be assigned a status of 'draft'. Return the value of `$previous_status`
* in order to assign the status that the post had before it was trashed. The `wp_untrash_post_set_previous_status()`
* function is available for this.
* Prior to WordPress 5.6.0, restored posts were always assigned their original status.
* @param string $new_status The new status of the post being restored.
* @param int $post_id The ID of the post being restored.
* @param string $previous_status The status of the post at the point where it was trashed.
$post_status = apply_filters( 'wp_untrash_post_status', $new_status, $post_id, $previous_status );
delete_post_meta( $post_id, '_wp_trash_meta_status' );
delete_post_meta( $post_id, '_wp_trash_meta_time' );
$post_updated = wp_update_post(
'post_status' => $post_status,
wp_untrash_post_comments( $post_id );
* Fires after a post is restored from the Trash.
* @since 5.6.0 Added the `$previous_status` parameter.
* @param int $post_id Post ID.
* @param string $previous_status The status of the post at the point where it was trashed.
do_action( 'untrashed_post', $post_id, $previous_status );
* Moves comments for a post to the Trash.
* @global wpdb $wpdb WordPress database abstraction object.
* @param int|WP_Post|null $post Optional. Post ID or post object. Defaults to global $post.
* @return mixed|void False on failure.
function wp_trash_post_comments( $post = null ) {
$post = get_post( $post );
* Fires before comments are sent to the Trash.
* @param int $post_id Post ID.
do_action( 'trash_post_comments', $post_id );
$comments = $wpdb->get_results( $wpdb->prepare( "SELECT comment_ID, comment_approved FROM $wpdb->comments WHERE comment_post_ID = %d", $post_id ) );
// Cache current status for each comment.
foreach ( $comments as $comment ) {
$statuses[ $comment->comment_ID ] = $comment->comment_approved;
add_post_meta( $post_id, '_wp_trash_meta_comments_status', $statuses );
// Set status for all comments to post-trashed.
$result = $wpdb->update( $wpdb->comments, array( 'comment_approved' => 'post-trashed' ), array( 'comment_post_ID' => $post_id ) );
clean_comment_cache( array_keys( $statuses ) );
* Fires after comments are sent to the Trash.
* @param int $post_id Post ID.
* @param array $statuses Array of comment statuses.
do_action( 'trashed_post_comments', $post_id, $statuses );
* Restores comments for a post from the Trash.
* @global wpdb $wpdb WordPress database abstraction object.
* @param int|WP_Post|null $post Optional. Post ID or post object. Defaults to global $post.
function wp_untrash_post_comments( $post = null ) {
$post = get_post( $post );
$statuses = get_post_meta( $post_id, '_wp_trash_meta_comments_status', true );
* Fires before comments are restored for a post from the Trash.
* @param int $post_id Post ID.
do_action( 'untrash_post_comments', $post_id );
// Restore each comment to its original status.
$group_by_status = array();
foreach ( $statuses as $comment_id => $comment_status ) {
$group_by_status[ $comment_status ][] = $comment_id;
foreach ( $group_by_status as $status => $comments ) {
// Confidence check. This shouldn't happen.
if ( 'post-trashed' === $status ) {
$comments_in = implode( ', ', array_map( 'intval', $comments ) );
$wpdb->query( $wpdb->prepare( "UPDATE $wpdb->comments SET comment_approved = %s WHERE comment_ID IN ($comments_in)", $status ) );