從痞客邦、Blogger 搬到 WordPress 後,把文章裡的外站圖片抓回自己的媒體庫

從痞客邦、Blogger 搬到 WordPress 後,把文章裡的外站圖片抓回自己的媒體庫

最後更新:2026/10/15

寫了八年的痞客邦部落格,六百篇文章匯進 WordPress,看起來一切正常,直到某天打開舊文章,圖片全變成破圖。原因很簡單:匯入的只有文字,文章裡的圖片網址還是 pimg.tw 開頭,圖片檔案一直放在舊平台的主機上。舊平台限制外連、改網址、或哪天關站,你的文章就只剩文字。

〈WordPress 網站搬家〉那篇講的是整個 WordPress 搬主機,圖片會跟著搬;這篇處理的是從別的平台搬過來、圖片沒跟來的情況。做法是一段程式碼,在後台「工具」多一個「抓回外站圖片」頁面:先預覽每篇文章有幾張外站圖片,確認後一鍵把它們下載進自己的媒體庫,並把文章裡的網址換成自己的。

不想自己改?把這篇交給 AI

把這篇的網址(或全文)連同下面這段話貼給 AI:

我的網站是 WordPress。我從別的平台搬過來,文章裡的圖片還連著舊平台的網址,我想照下面這篇文章把它們抓回自己的媒體庫。
請先問我:舊平台是哪一個、大約有幾篇文章、主機空間還剩多少、有沒有先備份資料庫。
問清楚之後,再一步一步告訴我:要用哪一段程式碼、貼在哪裡、怎麼先預覽再執行,以及跑完怎麼確認。
如果文章的做法不適合我的網站,請直接告訴我原因和替代做法。
文章:(貼上這篇的網址,或整篇內容)

改之前先備份,密碼不要貼給 AI。

完整程式碼

// 第 85 篇:把文章裡的外站圖片抓回自己的媒體庫

// 處理一篇文章:找出不是自己網站的 <img>,下載進媒體庫,把網址換掉
function mimi_localize_images($post_id, $dry_run = true) {
    require_once ABSPATH . 'wp-admin/includes/media.php';
    require_once ABSPATH . 'wp-admin/includes/file.php';
    require_once ABSPATH . 'wp-admin/includes/image.php';

    $post    = get_post($post_id);
    $content = $post->post_content;
    $home    = wp_parse_url(home_url(), PHP_URL_HOST);
    $result  = ['post' => $post_id, 'found' => 0, 'replaced' => 0, 'failed' => []];

    preg_match_all('/<img[^>]+src=["\']([^"\']+)["\']/i', $content, $m);
    foreach (array_unique($m[1]) as $src) {
        $host = wp_parse_url($src, PHP_URL_HOST);
        if (!$host || $host === $home) {
            continue; // 自己的圖,跳過
        }
        $result['found']++;
        if ($dry_run) {
            continue;
        }
        $new = media_sideload_image($src, $post_id, null, 'src'); // 下載、建附件、回傳新網址
        if (is_wp_error($new)) {
            $result['failed'][] = $src . ':' . $new->get_error_message();
            continue;
        }
        $content = str_replace($src, $new, $content);
        $result['replaced']++;
    }
    if (!$dry_run && $result['replaced']) {
        wp_update_post(['ID' => $post_id, 'post_content' => $content]);
    }
    return $result;
}

// 後台工具:工具 > 抓回外站圖片。先「預覽」看有幾張,再「開始」
add_action('admin_menu', function () {
    add_management_page('抓回外站圖片', '抓回外站圖片', 'manage_options', 'mimi-localize', function () {
        $go  = !empty($_POST['go']) && check_admin_referer('mimi_localize');
        $ids = get_posts(['post_type' => ['post', 'page'], 'post_status' => 'any', 'numberposts' => -1, 'fields' => 'ids']);
        echo '<div class="wrap"><h1>抓回外站圖片</h1>';
        $total = ['found' => 0, 'replaced' => 0, 'failed' => []];
        foreach ($ids as $id) {
            $r = mimi_localize_images($id, !$go);
            if ($r['found']) {
                echo '<p>' . esc_html(get_the_title($id)) . ':外站圖片 ' . $r['found'] . ' 張' . ($go ? ',抓回 ' . $r['replaced'] . ' 張' : '') . '</p>';
                $total['found'] += $r['found'];
                $total['replaced'] += $r['replaced'];
                $total['failed'] = array_merge($total['failed'], $r['failed']);
            }
        }
        echo '<p><strong>' . ($go ? '完成:抓回 ' . $total['replaced'] . ' 張' : '共 ' . $total['found'] . ' 張外站圖片(還沒抓)') . '</strong></p>';
        foreach ($total['failed'] as $f) {
            echo '<p style="color:#b32d2e">失敗:' . esc_html($f) . '</p>';
        }
        echo '<form method="post">' . wp_nonce_field('mimi_localize', '_wpnonce', true, false) . '<button class="button button-primary" name="go" value="1">開始抓回(先備份資料庫)</button></form></div>';
    });
});

程式碼放在 Code Snippets 這類外掛或子主題,放法和備份方式見〈WooCommerce 結帳頁改成台灣習慣〉。

兩段各做了什麼

第一段是處理一篇文章的函式。它用正規表示式找出內文所有 <img> 的網址,網域和自己網站一樣的跳過,其他的算成外站圖片。「預覽」模式只數有幾張;「執行」模式對每一張呼叫 WordPress 內建的 media_sideload_image:下載檔案、放進上傳資料夾、建一筆媒體庫的附件、產生各種尺寸的縮圖,然後回傳新的網址。程式再把內文裡的舊網址換成新網址,全部換完才存回文章。下載失敗的圖片會記下原因,內文裡那一張保持原樣,不會變成空白。

第二段在後台「工具」選單下加一頁「抓回外站圖片」。打開頁面就是預覽:列出每一篇有外站圖片的文章和張數,最後一行是總數。按「開始抓回」才真的執行,執行完同一頁顯示每篇抓回幾張、哪幾張失敗。只有管理員看得到這一頁。

測試結果

我們在本機測試站建一篇「搬家來的文章」,放三張圖:兩張連到 WordPress.org 的圖(一張 PNG 的 Logo、一張 SVG 的表情符號),一張是自己網站的:

  • 預覽顯示「外站圖片 2 張」,自己網站那張沒有被算進去。
  • 執行後顯示「抓回 1 張」和一行失敗:SVG 那張的錯誤是「無效的圖片網址」,因為 WordPress 預設不允許上傳 SVG。
  • 重新打開文章,PNG 的網址已經變成自己網站 wp-content/uploads/ 底下的檔案,SVG 那張還是原本的網址,自己的那張沒動。

跑之前要知道的幾件事

數量多的時候分批跑。六百篇文章、三千張圖一次抓,網頁可能等到逾時。這段程式碼為了簡單是一次處理全部,文章多的網站可以把 numberposts 改成 50,跑完再跑,或是請懂的人改成用排程分批。

主機空間要夠。圖片抓回來就是放在自己的主機上,三千張圖加上縮圖可能是幾 GB,先看主機還剩多少空間。不想讓每張圖產生十幾個縮圖,可以先看〈WordPress 停止產生多餘縮圖〉。

舊平台擋下載。有些平台會擋沒有來源網頁的圖片請求(防盜連),下載會失敗。失敗的清單會列在頁面上,這些圖只能手動存下來再上傳。另外,只有確定是你自己上傳到舊平台的圖片才抓;別人網站的圖片本來就不該出現在你的文章裡。

跑完記得備份。程式會改文章內文,跑之前備份一次資料庫,跑完確認沒問題再做一次完整備份,備份方法在〈WordPress 網站上線前的檢查清單〉。

圖片放在自己的主機,文章才真的是你的

搬家的意義是把內容放在自己手上,圖片留在舊平台等於只搬了一半。抓回來之後,網站的速度、縮圖、WebP 轉換都能自己控制,舊平台怎麼變都不影響你。這也是〈IG 帳號不是你的資產〉那篇講的:平台上的東西隨時會變,自己網站上的才算數。

如果你正打算從痞客邦、Blogger 或其他平台搬到自己的網站,想一次把文章、圖片、網址轉址都處理好,MIMI 專做客製化網頁設計,可以替你規劃搬家流程。MIMI 提供台灣網頁設計服務,全台灣的創作者都可以用電話、Email 直接和設計師討論;費用可以先看首頁的製作費用參考,歡迎聯絡 MIMI。

WordPress 自己寫短代碼:年份、營業中、活動倒數、最新文章,四個例子學會
WordPress 網站變快,自己能做的事:圖片 WebP、關掉用不到的程式、快取、Gzip、Redis

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

我的車
願望清單
最近瀏覽過的
類別