函数文档

wp_delete_attachment()

💡 云策文档标注

概述

wp_delete_attachment() 函数用于将附件移至回收站或永久删除。永久删除时,会移除关联的文件、元数据、分类和评论等,但保留主文章。默认行为受媒体回收站设置和参数控制。

关键要点

  • 函数接受两个参数:$post_id(必需,附件ID)和 $force_delete(可选,强制删除标志,默认false)。
  • 返回值为 WP_Post 对象(成功)、false 或 null(失败)。
  • 默认情况下,附件移至回收站,除非媒体回收站禁用、附件已在回收站或 $force_delete 为 true。
  • 永久删除会清理文件系统、元数据、分类关联和评论。
  • 涉及多个 Hook,如 pre_delete_attachment 过滤器和 delete_attachment 动作。

代码示例

// 将附件ID为76的移至回收站
wp_delete_attachment( 76 );

// 永久删除附件ID为76
wp_delete_attachment( 76, true );

注意事项

  • 函数调用 wp_delete_attachment_files() 但不检查其返回值,成功返回不一定保证文件已删除。
  • 在媒体库中默认无回收站访问按钮,使用 $force_delete = false 时可能造成混淆。
  • 删除附件时,作为缩略图的附件被移除后,现有图库图片可能自动替代。

📄 原文内容

Trashes or deletes an attachment.

Description

When an attachment is permanently deleted, the file will also be removed.
Deletion removes all post meta fields, taxonomy, comments, etc. associated with the attachment (except the main post).

The attachment is moved to the Trash instead of permanently deleted unless Trash for media is disabled, item is already in the Trash, or $force_delete is true.

Parameters

$post_idintrequired
Attachment ID.
$force_deletebooloptional
Whether to bypass Trash and force deletion.

Default:false

Return

WP_Post|false|null Post data on success, false or null on failure.

Source

function wp_delete_attachment( $post_id, $force_delete = false ) {
	global $wpdb;

	$post = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->posts WHERE ID = %d", $post_id ) );

	if ( ! $post ) {
		return $post;
	}

	$post = get_post( $post );

	if ( 'attachment' !== $post->post_type ) {
		return false;
	}

	if ( ! $force_delete && EMPTY_TRASH_DAYS && MEDIA_TRASH && 'trash' !== $post->post_status ) {
		return wp_trash_post( $post_id );
	}

	/**
	 * Filters whether an attachment deletion should take place.
	 *
	 * @since 5.5.0
	 *
	 * @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_attachment', null, $post, $force_delete );
	if ( null !== $check ) {
		return $check;
	}

	delete_post_meta( $post_id, '_wp_trash_meta_status' );
	delete_post_meta( $post_id, '_wp_trash_meta_time' );

	$meta         = wp_get_attachment_metadata( $post_id );
	$backup_sizes = get_post_meta( $post->ID, '_wp_attachment_backup_sizes', true );
	$file         = get_attached_file( $post_id );

	if ( is_multisite() && is_string( $file ) && ! empty( $file ) ) {
		clean_dirsize_cache( $file );
	}

	/**
	 * Fires before an attachment is deleted, at the start of wp_delete_attachment().
	 *
	 * @since 2.0.0
	 * @since 5.5.0 Added the `$post` parameter.
	 *
	 * @param int     $post_id Attachment ID.
	 * @param WP_Post $post    Post object.
	 */
	do_action( 'delete_attachment', $post_id, $post );

	wp_delete_object_term_relationships( $post_id, array( 'category', 'post_tag' ) );
	wp_delete_object_term_relationships( $post_id, get_object_taxonomies( $post->post_type ) );

	// Delete all for any posts.
	delete_metadata( 'post', null, '_thumbnail_id', $post_id, true );

	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 );
	}

	/** This action is documented in wp-includes/post.php */
	do_action( 'delete_post', $post_id, $post );
	$result = $wpdb->delete( $wpdb->posts, array( 'ID' => $post_id ) );
	if ( ! $result ) {
		return false;
	}
	/** This action is documented in wp-includes/post.php */
	do_action( 'deleted_post', $post_id, $post );

	wp_delete_attachment_files( $post_id, $meta, $backup_sizes, $file );

	clean_post_cache( $post );

	return $post;
}

Hooks

do_action( ‘deleted_post’, int $post_id, WP_Post $post )

Fires immediately after a post is deleted from the database.

do_action( ‘delete_attachment’, int $post_id, WP_Post $post )

Fires before an attachment is deleted, at the start of wp_delete_attachment() .

do_action( ‘delete_post’, int $post_id, WP_Post $post )

Fires immediately before a post is deleted from the database.

apply_filters( ‘pre_delete_attachment’, WP_Post|false|null $delete, WP_Post $post, bool $force_delete )

Filters whether an attachment deletion should take place.

Changelog

Version Description
2.0.0 Introduced.

User Contributed Notes

  1. Skip to note 4 content

    This function does approximately the same as if you would go the Media Library and trash or delete an attachment and cleanly remove the associations from posts (or other objects) to which they were associated, and subsequently remove the files from the files system (if case you choose to delete the attachment, rather than trashing it):

    • This function has nothing to do with how attachments (like images) are actually used on a site
    • When using $force_delete = false, the attachment gets moved to Trash, eventhough by default, there is no button at the media library to access Trash – This can be confusing
    • When using $force_delete = false, the attachment files (the actual files under wp-content/uploads) are kept as they are
    • When using $force_delete = true, the attachment files (the actual files under wp-content/uploads) are removed
    • Concerning the line at the top in this documentation “(except the main post)”: I’m still not sure what it means. I suspect that it means that e.g., when you remove the image for a WooCommerce product, that the image gets removed, along with all its metadata, but not the WooCommerce product itself
    • It seems that when you remove an attachment that is a thumbnail for a WooCommerce product, that an existing gallery image takes it place – Quite neat, when you are aware of this.

    Example (1) – Trash one attachment:

    </pre>
    <p>Example (2) – Delete multiple attachments:</p>
    <pre class="wp-block-code"><code lang="php" class="language-php line-numbers"></pre>
    				</div><!-- .comment-content -->
    
    					<section id='feedback-5016' class='wporg-has-embedded-code feedback hide-if-js' data-comment-count='0'>
    </section><!-- .feedback -->
    <footer class='feedback-links wporg-dot-link-list' >
    <a role="button" class="feedback-login" href="https://login.wordpress.org/?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_delete_attachment%2F%3Freplytocom%3D5016%23feedback-editor-5016" rel="nofollow">Log in to add feedback</a></footer>
    </article><!-- .comment-body -->
    </li>
    			<li id="comment-2898" data-comment-id="2898" class="comment byuser comment-author-javeweb odd alt thread-even depth-1">
    			<article id="div-comment-2898" class="comment-body">
    
    							<a href="#comment-content-2898" class="screen-reader-text">Skip to note 5 content</a>
    				<header class="comment-meta">
    					<div class="comment-author vcard">
    						<span class="comment-author-attribution">
    						<a href="https://profiles.wordpress.org/javeweb/" rel="external nofollow" class="url">jave.web</a>						</span>
    						<a class="comment-date" href="https://developer.wordpress.org/reference/functions/wp_delete_attachment/#comment-2898">
    							<time datetime="2018-10-11T04:34:32+00:00">
    							8 years ago							</time>
    						</a>
    
    																													</div>
    					<div class="user-note-voting" data-nonce="75b8995e4d" data-can-vote="false"><a class="user-note-voting-up" title="You must log in to vote on the helpfulness of this note" data-id="2898" data-vote="up" href="https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_delete_attachment%2F%23comment-2898"><span class="screen-reader-text">You must log in to vote on the helpfulness of this note</span></a><span class="user-note-voting-count " title="100% like this"><span class="screen-reader-text">Vote results for this note: </span>2</span><a class="user-note-voting-down" title="You must log in to vote on the helpfulness of this note" data-id="2898" data-vote="down" href="https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_delete_attachment%2F%23comment-2898"><span class="screen-reader-text">You must log in to vote on the helpfulness of this note</span></a></div>				</header>
    				<!-- .comment-metadata -->
    			
    				<div class="wporg-has-embedded-code comment-content" id="comment-content-2898">
    				<p>This function calls <a href="https://developer.wordpress.org/reference/functions/wp_delete_attachment_files/">wp_delete_attachment_files()</a> but does not actually check for its return<br />
    => <strong>successful return does not really promise files were actually deleted!</strong></p>
    				</div><!-- .comment-content -->
    
    					<section id='feedback-2898' class='wporg-has-embedded-code feedback hide-if-js' data-comment-count='0'>
    </section><!-- .feedback -->
    <footer class='feedback-links wporg-dot-link-list' >
    <a role="button" class="feedback-login" href="https://login.wordpress.org/?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_delete_attachment%2F%3Freplytocom%3D2898%23feedback-editor-2898" rel="nofollow">Log in to add feedback</a></footer>
    </article><!-- .comment-body -->
    </li>
    			<li id="comment-770" data-comment-id="770" class="comment byuser comment-author-codex even thread-odd thread-alt depth-1">
    			<article id="div-comment-770" class="comment-body">
    
    							<a href="#comment-content-770" class="screen-reader-text">Skip to note 6 content</a>
    				<header class="comment-meta">
    					<div class="comment-author vcard">
    						<span class="comment-author-attribution">
    						<a href="https://profiles.wordpress.org/codex/" rel="external nofollow" class="url">Codex</a>						</span>
    						<a class="comment-date" href="https://developer.wordpress.org/reference/functions/wp_delete_attachment/#comment-770">
    							<time datetime="2015-07-15T06:15:41+00:00">
    							11 years ago							</time>
    						</a>
    
    																													</div>
    					<div class="user-note-voting" data-nonce="6462bcf651" data-can-vote="false"><a class="user-note-voting-up" title="You must log in to vote on the helpfulness of this note" data-id="770" data-vote="up" href="https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_delete_attachment%2F%23comment-770"><span class="screen-reader-text">You must log in to vote on the helpfulness of this note</span></a><span class="user-note-voting-count " title=""><span class="screen-reader-text">Vote results for this note: </span>0</span><a class="user-note-voting-down" title="You must log in to vote on the helpfulness of this note" data-id="770" data-vote="down" href="https://login.wordpress.org?redirect_to=https%3A%2F%2Fdeveloper.wordpress.org%2Freference%2Ffunctions%2Fwp_delete_attachment%2F%23comment-770"><span class="screen-reader-text">You must log in to vote on the helpfulness of this note</span></a></div>				</header>
    				<!-- .comment-metadata -->
    			
    				<div class="wporg-has-embedded-code comment-content" id="comment-content-770">
    				<p>To delete an attachment with an ID of ’76’:</p>
    <pre class="wp-block-code"><code lang="php" class="language-php ">