WooCommerce 價格跟著匯率、金價自動更新:每天排程抓台銀牌告

WooCommerce 價格跟著匯率、金價自動更新:每天排程抓台銀牌告

最後更新:2026/10/15

做美國代購的店,商品成本是美金,賣的是台幣,匯率一週動個三、五毛,一百件商品就要重算一百次。賣金飾的店更辛苦,金價每天都不一樣,報價單上總要寫「以當日牌價為準」。手動改價不是改不完,是改到後來乾脆不改,利潤就在匯率裡慢慢流掉。

這篇讓 WooCommerce 自己改價:每件商品填一個「美金底價」,網站每天早上去抓台灣銀行的牌告匯率,換算成台幣、加上你設定的加成、四捨五入到 10 元,寫回商品的價格。後台商品列表上方會顯示上次更新的時間、匯率和改了幾件,想立刻更新也有一顆按鈕。

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

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

我的網站是 WordPress,有裝 WooCommerce。我想照下面這篇文章,讓部分商品的價格每天依匯率(或金價)自動換算更新。
請先問我:哪些商品要自動改價、底價是什麼幣別、匯率要從哪裡抓、加成多少、價格要四捨五入到幾元、每天幾點更新。
問清楚之後,再一步一步告訴我:要用哪一段程式碼、貼在哪裡、哪些地方要換成我自己的資料,以及改完怎麼測試。
如果文章的做法不適合我的網站,請直接告訴我原因和替代做法。
文章:(貼上這篇的網址,或整篇內容)

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

資料從哪裡來

台灣銀行的牌告匯率有一個公開的 CSV 檔,網址是 https://rate.bot.com.tw/xrt/flcsv/0/day,不用申請、不用金鑰,用瀏覽器打開會直接下載。每一列是一種幣別,欄位依序是:幣別、「本行買入」的現金和即期匯率、「本行賣出」的現金和即期匯率,中間還夾著幾個遠期匯率。我們要的是美金那一列的「即期賣出」,也就是你去銀行用台幣買美金的價格,在第 14 欄。

金價的話,台灣銀行也有黃金牌價頁面,但沒有同樣方便的 CSV;做金飾的店可以找有提供金價資料的服務,或是每天早上由店員在後台填一個數字,程式的其他部分完全一樣。程式碼裡抓匯率的那一段是獨立的函式,換資料來源只要改那一段。

完整程式碼

// 第 76 篇:價格自動跟著匯率、金價、原料價更新

// 1. 商品編輯頁多一格「美金底價」:有填的商品才會被自動改價
add_action('woocommerce_product_options_pricing', function () {
    woocommerce_wp_text_input(['id' => '_mimi_base_usd', 'label' => '美金底價', 'type' => 'number', 'custom_attributes' => ['step' => '0.01', 'min' => '0'], 'desc_tip' => true, 'description' => '每天依台銀牌告匯率換算成台幣,寫進一般價格。留空就不會自動改價。']);
});
add_action('woocommerce_process_product_meta', function ($post_id) {
    update_post_meta($post_id, '_mimi_base_usd', wc_clean(wp_unslash($_POST['_mimi_base_usd'] ?? '')));
});

// 2. 去抓今天的匯率(台灣銀行牌告匯率 CSV,取美金「即期賣出」)
function mimi_fetch_usd_rate() {
    $url = apply_filters('mimi_rate_url', 'https://rate.bot.com.tw/xrt/flcsv/0/day');
    $res = wp_remote_get($url, ['timeout' => 15]);
    if (is_wp_error($res) || wp_remote_retrieve_response_code($res) !== 200) {
        return new WP_Error('fetch', is_wp_error($res) ? $res->get_error_message() : '回應碼 ' . wp_remote_retrieve_response_code($res));
    }
    foreach (explode("\n", wp_remote_retrieve_body($res)) as $line) {
        $cols = str_getcsv($line);
        if (($cols[0] ?? '') === 'USD' && isset($cols[13]) && is_numeric($cols[13])) {
            return (float) $cols[13]; // 第 14 欄是「即期賣出」
        }
    }
    return new WP_Error('parse', '找不到美金匯率');
}

// 3. 換算並改價:底價 × 匯率 × 加成,四捨五入到 10 元
function mimi_update_prices_by_rate() {
    $rate = mimi_fetch_usd_rate();
    $log  = ['time' => current_time('Y-m-d H:i'), 'rate' => null, 'updated' => 0, 'error' => ''];
    if (is_wp_error($rate)) {
        $log['error'] = $rate->get_error_message();
        update_option('mimi_rate_log', $log);
        return $log;
    }
    $markup = (float) apply_filters('mimi_rate_markup', 1.15); // 加 15% 當運費、關稅和利潤
    $ids = wc_get_products(['limit' => -1, 'return' => 'ids', 'meta_key' => '_mimi_base_usd', 'meta_compare' => '>', 'meta_value' => 0]);
    foreach ($ids as $id) {
        $product = wc_get_product($id);
        $usd     = (float) $product->get_meta('_mimi_base_usd');
        $twd     = round($usd * $rate * $markup / 10) * 10;
        if ((float) $product->get_regular_price() !== $twd) {
            $product->set_regular_price((string) $twd);
            $product->save();
            $log['updated']++;
        }
    }
    $log['rate'] = $rate;
    update_option('mimi_rate_log', $log);
    return $log;
}

// 4. 每天早上 6 點自動跑一次(用 WordPress 的排程)
add_action('init', function () {
    if (!wp_next_scheduled('mimi_update_prices')) {
        wp_schedule_event(strtotime('tomorrow 06:00 ' . wp_timezone_string()), 'daily', 'mimi_update_prices');
    }
});
add_action('mimi_update_prices', 'mimi_update_prices_by_rate');

// 5. 後台商品列表上方顯示上次更新的結果,並提供「現在更新」按鈕
add_action('admin_notices', function () {
    $screen = get_current_screen();
    if (!$screen || $screen->id !== 'edit-product' || !current_user_can('manage_woocommerce')) {
        return;
    }
    if (!empty($_GET['mimi_rate_run']) && check_admin_referer('mimi_rate_run')) {
        mimi_update_prices_by_rate();
    }
    $log = get_option('mimi_rate_log');
    $url = wp_nonce_url(admin_url('edit.php?post_type=product&mimi_rate_run=1'), 'mimi_rate_run');
    echo '<div class="notice notice-info"><p>匯率改價:' . ($log ? esc_html(sprintf('%s 匯率 %s,更新 %d 件%s', $log['time'], $log['rate'] ?? '—', $log['updated'], $log['error'] ? ',錯誤:' . $log['error'] : '')) : '還沒跑過')
        . ' <a class="button button-small" href="' . esc_url($url) . '">現在更新</a></p></div>';
});

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

五段各做了什麼

第 1 段在商品編輯頁多一格「美金底價」。只有填了底價的商品會被自動改價,其他商品完全不動,所以你可以先拿兩三件商品試。

第 2 段去台灣銀行抓 CSV,找到幣別是 USD 的那一列,取第 14 欄的即期賣出匯率。抓不到或格式變了,會回傳錯誤訊息,不會亂改價格。網址用了一個過濾器 mimi_rate_url,之後要換成別的資料來源,可以從外面換掉而不用改這段。

第 3 段是換算:台幣價格 = 美金底價 × 匯率 × 加成,再四捨五入到 10 元。加成預設 1.15,也就是在匯率之外多加 15% 當運費、關稅和利潤,你可以改成自己的數字。算出來的價格和目前的一般價格一樣就跳過,不一樣才寫回去,所以每天跑也不會無謂地改動商品。最後把這次的時間、匯率、改了幾件、有沒有錯誤記在一個選項裡。

第 4 段用 WordPress 內建的排程(WP-Cron)每天早上 6 點跑一次。WP-Cron 要有人打開網站才會觸發,流量少的網站可能會晚一點才跑;如果你的主機有提供系統排程,可以改成由系統每天準時呼叫,做法在下一節。

第 5 段在後台「商品」列表的最上方放一個藍色提示,寫著上次更新的時間、匯率和件數,旁邊一顆「現在更新」按鈕,讓你隨時手動跑一次,匯率大幅變動的日子不用等到隔天早上。

測試結果

我們在本機測試站把「精油組合」填美金底價 25,實際去抓台灣銀行的 CSV:

  • 抓到的美金即期賣出匯率是 32.35,換算 25 × 32.35 × 1.15 = 930.06,四捨五入到 10 元得到 930,商品的一般價格從 980 改成 930,紀錄寫「更新 1 件」。
  • 再用一份假的匯率資料(32.3)跑一次,算出來還是 930,紀錄寫「更新 0 件」,商品沒有被重複寫入。
  • 排程確認已經建立,下一次執行時間是隔天早上 6:00,每天一次。

讓排程準時:改用主機的系統排程

WP-Cron 的原理是「有訪客打開網頁時順便檢查有沒有到期的工作」,半夜沒人上網站,工作就會延到早上第一個訪客才跑。要準時,可以在主機的控制台(cPanel、Plesk 或 Hestia 都有「Cron 工作」)加一條每分鐘或每五分鐘執行一次的指令:

*/5 * * * * wget -q -O /dev/null https://你的網域/wp-cron.php?doing_wp_cron

再到 wp-config.php 加一行 define('DISABLE_WP_CRON', true);,讓 WordPress 不再靠訪客觸發。主機的操作畫面各家不同,不確定的話問主機商怎麼加 Cron 工作就可以。

什麼商品適合自動改價

成本直接跟著某個公開數字走的商品最適合:代購、進口商品跟匯率,金飾跟金價,咖啡豆、可可這類原料也有公開報價。成本裡還有很多人工和運費的商品,自動改價只是其中一部分,加成那個數字要抓好。另外提醒一件事:價格每天變,客人昨天看 930 今天變 940 會問,商品頁寫一句「價格依當日匯率調整」,就能省掉解釋。

如果你的商品成本跟著市場走,想把定價、庫存和出貨一起規劃成不用天天盯的流程,可以先看〈IG 帳號不是你的資產〉想想網站要做到什麼,一個人經營怎麼自動化可以看〈一個人做不完?一人工作室的 3 種自動化〉。MIMI 專做客製化網頁設計,購物車電商網站可以依你的成本結構設計定價方式。MIMI 提供台灣網頁設計服務,全台灣的店家都可以用電話、Email 直接和設計師討論;費用可以先看首頁的製作費用參考,歡迎聯絡 MIMI。

WooCommerce 數量折扣、滿額折扣、會員價,不裝外掛
WooCommerce 出貨後給客人物流單號:後台填一次,完成信和會員中心都看得到

發佈留言

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

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