0%

正威網路行銷工作室,專注於基隆、台北與全台客製化網頁設計,提供專業 RWD 響應式、SEO 搜尋引擎優化、品牌形象設計與網站維護託管服務。

搜尋文章
聯絡資訊
地址基隆市仁二路 220 號 5 樓
追蹤我們

WordPress 刪除文章時一併刪除圖片:只刪沒被其他文章使用的安全寫法

取得 YouTube 的縮圖教學

在 WordPress 刪除一篇文章,文章用到的圖片並不會跟著刪掉:媒體庫裡的圖片、WordPress 自動產生的各種尺寸縮圖,都還留在主機上。文章刪多了,主機空間就被這些用不到的檔案佔掉。

這篇提供一段程式碼,在永久刪除文章時,把「只有這篇文章在用」的圖片一起刪除。重點在於不能誤刪:同一張圖片可能也是別篇文章的特色圖片,或出現在別篇文章的內文裡,刪掉就會變成破圖。

動手之前:一定要先備份

媒體檔案刪除之後,WordPress 沒有垃圾桶可以救回來。使用這段程式碼之前:

  • 備份資料庫與 wp-content/uploads 資料夾(用主機的備份功能或備份外掛都可以)。
  • 有測試站的話,先在測試站試過,再放到正式網站。

先了解:刪除文章時,WordPress 會做什麼?

  • 移到垃圾桶:什麼都不會刪,文章隨時可以還原。
  • 永久刪除(在垃圾桶按「永久刪除」或「清空垃圾桶」,或是文章在垃圾桶放超過 30 天被自動清除):文章本身、自訂欄位、修訂版本會被刪掉,但圖片會留在媒體庫,變成「未附加」的狀態。

下面的程式碼掛在 before_delete_post 這個動作(action)上,只有永久刪除時才會執行,移到垃圾桶不受影響。

程式碼

加到子主題的 functions.php,或用 Code Snippets 外掛新增:

PHP
/**
 * 永久刪除文章時,一併刪除只屬於這篇文章的圖片
 * 被其他文章當特色圖片、或出現在其他文章內文裡的圖片會保留
 */
add_action( 'before_delete_post', 'ahwei_delete_post_images' );

function ahwei_delete_post_images( $post_id ) {
    $post = get_post( $post_id );

    // 只處理一般文章;要包含頁面可改成 array( 'post', 'page' )
    if ( ! $post || ! in_array( $post->post_type, array( 'post' ), true ) ) {
        return;
    }
    // 自動草稿不處理
    if ( 'auto-draft' === $post->post_status ) {
        return;
    }

    // 候選圖片:特色圖片 + 在這篇文章上傳的圖片
    $candidates   = array();
    $thumbnail_id = (int) get_post_thumbnail_id( $post );
    if ( $thumbnail_id ) {
        $candidates[] = $thumbnail_id;
    }

    $attached = get_posts( array(
        'post_type'      => 'attachment',
        'post_status'    => 'inherit',
        'post_parent'    => $post_id,
        'post_mime_type' => 'image',
        'posts_per_page' => -1,
        'fields'         => 'ids',
    ) );

    $candidates = array_unique( array_merge( $candidates, array_map( 'intval', $attached ) ) );

    foreach ( $candidates as $attachment_id ) {
        if ( ! ahwei_is_image_used_elsewhere( $attachment_id, $post_id ) ) {
            wp_delete_attachment( $attachment_id, true );
        }
    }
}

/**
 * 檢查圖片有沒有被其他文章使用 (特色圖片或內文)
 */
function ahwei_is_image_used_elsewhere( $attachment_id, $post_id ) {
    global $wpdb;

    // 1) 是不是其他文章的特色圖片
    $as_thumbnail = (int) $wpdb->get_var( $wpdb->prepare(
        "SELECT COUNT(*) FROM {$wpdb->postmeta} pm
         INNER JOIN {$wpdb->posts} p ON p.ID = pm.post_id
         WHERE pm.meta_key = '_thumbnail_id'
           AND pm.meta_value = %s
           AND pm.post_id <> %d
           AND p.post_type <> 'revision'",
        (string) $attachment_id,
        $post_id
    ) );
    if ( $as_thumbnail > 0 ) {
        return true;
    }

    // 2) 其他文章的內文有沒有用到 (比對 wp-image-編號 與檔案路徑)
    $patterns = array( '%' . $wpdb->esc_like( 'wp-image-' . $attachment_id ) . '%' );

    $file = (string) get_post_meta( $attachment_id, '_wp_attached_file', true );
    if ( '' !== $file ) {
        // 例如 2024/05/photo-scaled.jpg 取出 2024/05/photo
        $base       = preg_replace( '/(-scaled)?\.[a-z0-9]+$/i', '', $file );
        $patterns[] = '%' . $wpdb->esc_like( $base ) . '%';
    }

    foreach ( $patterns as $like ) {
        $in_content = (int) $wpdb->get_var( $wpdb->prepare(
            "SELECT COUNT(*) FROM {$wpdb->posts}
             WHERE ID <> %d
               AND post_type NOT IN ( 'revision', 'attachment' )
               AND post_content LIKE %s",
            $post_id,
            $like
        ) );
        if ( $in_content > 0 ) {
            return true;
        }
    }

    return false;
}

這段程式碼做的事:

  1. 只處理一般文章(post),自動草稿不處理。想連頁面一起處理,把 array( 'post' ) 改成 array( 'post', 'page' )。
  2. 找出候選圖片:這篇文章的特色圖片,以及在這篇文章裡上傳的圖片。
  3. 每一張都先檢查:有沒有被其他文章設成特色圖片?其他文章、頁面的內文有沒有用到?只要有,就保留。
  4. 確定沒被使用的,才用 WordPress 內建的 wp_delete_attachment() 刪除,它會把原圖和所有尺寸的縮圖一起刪掉。

內文的比對是用圖片的 wp-image-編號 與檔案路徑去找,原則是「寧可多保留、不要誤刪」,所以偶爾會有其實沒被使用、卻被保留下來的圖片,這是刻意的設計。一次清空大量文章時,因為每張圖片都要檢查,可能會比平常久一點。

這段程式碼判斷不到的地方

程式只檢查特色圖片與文章內文,下面這些地方用到的圖片它看不到,可能被誤刪:

  • 頁面編輯器(Elementor、Divi 等)存在自己欄位裡的圖片
  • 小工具、選單、主題設定裡的圖片(例如 Logo、背景圖)
  • WooCommerce 商品圖庫
  • 傳統編輯器用 [gallery ids="..."] 短代碼插入的相簿(只記錄圖片編號,沒有圖片網址)
  • 其他網站或社群貼文直接引用你的圖片網址

網站有用到上面這些,建議不要使用自動刪除,改用下面的手動清理方式。

比較保守的做法:定期手動清理

  1. 到「媒體 → 媒體庫」,切換成清單檢視。
  2. 用上方的篩選選單選「未附加」,列出沒有附加在任何文章上的檔案。
  3. 逐一確認真的沒在使用,再刪除。

要注意「未附加」不代表沒被使用,同一張圖片可能被插入到別篇文章裡,所以刪除前還是要確認。也有外掛可以掃描整個網站的圖片使用狀況,不管用哪一種工具,刪除前都一樣要先備份。

舊版程式碼為什麼不要用

  • 引號變成了全形的“ ”與‘ ’:文章搬家時引號被轉換,照著貼上會造成 PHP 語法錯誤,網站直接白畫面。
  • 不檢查圖片有沒有被其他文章使用:共用的特色圖片會被刪掉,其他文章跟著破圖。
  • 每一種內容被刪除時都會執行:頁面、商品、其他外掛的自訂內容被刪除時,也會去刪圖片。
  • 直接把變數組進 SQL 語法:應該用 $wpdb->prepare() 處理;最後那段手動刪除自訂欄位的語法也是多餘的,WordPress 刪除文章時本來就會處理。

常見問題

把文章移到垃圾桶,圖片會被刪嗎?

不會。只有永久刪除時才會執行,文章在垃圾桶裡都還能連同圖片一起還原。但要記得,垃圾桶裡超過 30 天的文章會被 WordPress 自動永久刪除,那時候程式也會執行。

以前刪掉的文章,留下來的圖片怎麼辦?

這段程式碼只會處理之後刪除的文章。以前留下來的圖片,請用上面「定期手動清理」的方式處理。

延伸閱讀

主機空間被舊檔案塞滿、又不敢亂刪的時候,最需要有人幫忙把關。正威網路行銷是 25 年經驗的基隆網頁設計工作室,提供網站維護託管,也服務台北與全台客戶,歡迎來聊聊。

分享這篇文章

返回文章列表更多「Wordpress代碼教學」文章

發表留言

還沒有人留言,歡迎第一個分享你的想法或問題。留言經審核後才會顯示,Email 不會公開。

讓我們一起打造
您的專屬網站!