最後更新:2026/10/15
窗簾店的報價單上寫的是「每才 350 元」,玻璃行是「每平方公尺 800 元起」,大圖輸出店是「每平方公尺 250 元,最低一平方公尺」。這類商品沒有固定價格,要等客人說出尺寸才算得出來。搬到網路上,很多店家只好在商品頁寫「請來電報價」,等於把客人推回電話。
比較好的做法是讓客人自己填尺寸,網站當場算給他看,確定了就加入購物車。這篇用一段程式碼做到:商品頁多「寬」和「高」兩格,旁邊即時試算,加入購物車的金額就是算好的,購物車、結帳頁、訂單都寫著尺寸和面積。
不想自己改?把這篇交給 AI
把這篇的網址(或全文)連同下面這段話貼給 AI:
我的網站是 WordPress,有裝 WooCommerce。我想照下面這篇文章,讓一部分商品依尺寸計價:客人填寬和高,價格自動算,尺寸寫進訂單。
請先問我:哪些商品要這樣賣、單價是每平方公尺還是每才、有沒有最低計價面積、尺寸的範圍是多少。
問清楚之後,再一步一步告訴我:要用哪一段程式碼、貼在哪裡、哪些地方要換成我自己的資料,以及改完怎麼測試。
如果文章的做法不適合我的網站,請直接告訴我原因和替代做法。
文章:(貼上這篇的網址,或整篇內容)
改之前先備份,密碼不要貼給 AI。
先想清楚三個數字
每一件依尺寸計價的商品,你要先決定三個數字:每平方公尺的單價、最低計價面積、可以接受的尺寸範圍。
最低計價面積是為了保護自己。客人訂一塊 20 × 30 公分的玻璃,面積只有 0.06 平方公尺,照單價算只要幾十元,連裁切和包裝的工都不夠。設定「未滿 0.5 平方公尺以 0.5 計」,小單就有合理的底價。尺寸範圍則是機器和材料的限制,例如寬和高都要在 30 到 300 公分之間,超過的就不給下單,請客人改用詢價。
如果你的行業習慣用「才」(30.3 × 30.3 公分),單價換算成每平方公尺就好:每才 350 元大約是每平方公尺 3,810 元。商品頁上還是可以用文字寫「每才 350 元」,程式用平方公尺算。
完整程式碼
// 第 74 篇:依尺寸、面積計價(客人填長寬,價格自動算)
// 1. 商品編輯頁:每平方公尺單價、最低計價面積、最小與最大尺寸
add_action('woocommerce_product_options_pricing', function () {
woocommerce_wp_text_input(['id' => '_mimi_m2_price', 'label' => '每平方公尺價格', 'type' => 'number', 'custom_attributes' => ['step' => '1', 'min' => '0'], 'desc_tip' => true, 'description' => '填了之後商品頁會出現寬、高欄位,價格依面積計算。']);
woocommerce_wp_text_input(['id' => '_mimi_min_m2', 'label' => '最低計價面積(平方公尺)', 'type' => 'number', 'custom_attributes' => ['step' => '0.1', 'min' => '0'], 'placeholder' => '0.5']);
woocommerce_wp_text_input(['id' => '_mimi_size_range', 'label' => '尺寸範圍(公分)', 'placeholder' => '30-300', 'desc_tip' => true, 'description' => '寬和高都要在這個範圍內,例如 30-300。']);
});
add_action('woocommerce_process_product_meta', function ($post_id) {
foreach (['_mimi_m2_price', '_mimi_min_m2', '_mimi_size_range'] as $k) {
update_post_meta($post_id, $k, wc_clean(wp_unslash($_POST[$k] ?? '')));
}
});
function mimi_area_cfg($product_id) {
$price = (float) get_post_meta($product_id, '_mimi_m2_price', true);
if ($price <= 0) {
return null;
}
$range = array_map('floatval', explode('-', get_post_meta($product_id, '_mimi_size_range', true) ?: '30-300'));
return ['price' => $price, 'min_m2' => (float) (get_post_meta($product_id, '_mimi_min_m2', true) ?: 0.5), 'min' => $range[0], 'max' => $range[1] ?? 300];
}
function mimi_area_total($cfg, $w, $h) {
$m2 = max($cfg['min_m2'], $w * $h / 10000);
return ['m2' => round($m2, 2), 'total' => round($m2 * $cfg['price'])];
}
// 2. 商品頁的價格改成「每平方公尺 NT$800 起」
add_filter('woocommerce_get_price_html', function ($html, $product) {
$cfg = mimi_area_cfg($product->get_id());
return $cfg ? '每平方公尺 ' . wc_price($cfg['price']) . ' 起' : $html;
}, 10, 2);
// 3. 商品頁的加入購物車按鈕前面放寬、高欄位,還有即時試算
add_action('woocommerce_before_add_to_cart_button', function () {
global $product;
$cfg = mimi_area_cfg($product->get_id());
if (!$cfg) {
return;
}
?>
<div class="mimi-area" data-price="<?php echo esc_attr($cfg['price']); ?>" data-min="<?php echo esc_attr($cfg['min_m2']); ?>">
<p><label>寬(公分)<input type="number" name="mimi_w" min="<?php echo esc_attr($cfg['min']); ?>" max="<?php echo esc_attr($cfg['max']); ?>" required></label>
<label>高(公分)<input type="number" name="mimi_h" min="<?php echo esc_attr($cfg['min']); ?>" max="<?php echo esc_attr($cfg['max']); ?>" required></label></p>
<p class="mimi-area-est">尺寸範圍 <?php echo esc_html($cfg['min'] . '~' . $cfg['max']); ?> 公分;未滿 <?php echo esc_html($cfg['min_m2']); ?> 平方公尺以 <?php echo esc_html($cfg['min_m2']); ?> 平方公尺計。</p>
<p class="mimi-area-total">試算:<strong>—</strong></p>
</div>
<script>
(function () {
var box = document.querySelector('.mimi-area');
if (!box) { return; }
var w = box.querySelector('[name=mimi_w]'), h = box.querySelector('[name=mimi_h]'), out = box.querySelector('.mimi-area-total strong');
function calc() {
var m2 = Math.max(parseFloat(box.dataset.min), (w.value * h.value) / 10000 || 0);
out.textContent = w.value && h.value ? m2.toFixed(2) + ' 平方公尺,NT$' + Math.round(m2 * box.dataset.price).toLocaleString() : '—';
}
w.addEventListener('input', calc); h.addEventListener('input', calc);
})();
</script>
<?php
});
// 4. 沒填或超出範圍就不能加入購物車
add_filter('woocommerce_add_to_cart_validation', function ($ok, $product_id) {
$cfg = mimi_area_cfg($product_id);
if (!$cfg) {
return $ok;
}
$w = (float) ($_POST['mimi_w'] ?? 0);
$h = (float) ($_POST['mimi_h'] ?? 0);
foreach ([$w, $h] as $v) {
if ($v < $cfg['min'] || $v > $cfg['max']) {
wc_add_notice(sprintf('請填寫寬和高,範圍 %s~%s 公分。', $cfg['min'], $cfg['max']), 'error');
return false;
}
}
return $ok;
}, 10, 2);
// 5. 把尺寸存進購物車項目,不同尺寸算不同的項目
add_filter('woocommerce_add_cart_item_data', function ($data, $product_id) {
if (mimi_area_cfg($product_id) && !empty($_POST['mimi_w'])) {
$data['mimi_size'] = ['w' => (float) $_POST['mimi_w'], 'h' => (float) $_POST['mimi_h']];
}
return $data;
}, 10, 2);
// 6. 依面積算價格
add_action('woocommerce_before_calculate_totals', function ($cart) {
foreach ($cart->get_cart() as $item) {
if (empty($item['mimi_size'])) {
continue;
}
$cfg = mimi_area_cfg($item['product_id']);
if ($cfg) {
$item['data']->set_price(mimi_area_total($cfg, $item['mimi_size']['w'], $item['mimi_size']['h'])['total']);
}
}
}, 20);
// 7. 購物車、結帳頁顯示尺寸;下單後寫進訂單
add_filter('woocommerce_get_item_data', function ($rows, $item) {
if (!empty($item['mimi_size'])) {
$cfg = mimi_area_cfg($item['product_id']);
$r = mimi_area_total($cfg, $item['mimi_size']['w'], $item['mimi_size']['h']);
$rows[] = ['key' => '尺寸', 'value' => sprintf('%s × %s 公分(%s 平方公尺)', $item['mimi_size']['w'], $item['mimi_size']['h'], $r['m2'])];
}
return $rows;
}, 10, 2);
add_action('woocommerce_checkout_create_order_line_item', function ($line, $key, $values) {
if (!empty($values['mimi_size'])) {
$cfg = mimi_area_cfg($values['product_id']);
$r = mimi_area_total($cfg, $values['mimi_size']['w'], $values['mimi_size']['h']);
$line->add_meta_data('尺寸', sprintf('%s × %s 公分(%s 平方公尺)', $values['mimi_size']['w'], $values['mimi_size']['h'], $r['m2']), true);
}
}, 10, 3);
程式碼放在 Code Snippets 這類外掛或子主題,放法和備份方式見〈WooCommerce 結帳頁改成台灣習慣〉。
七段各做了什麼
第 1 段在商品編輯頁多三格:每平方公尺價格、最低計價面積、尺寸範圍。只有填了單價的商品才會啟用,其他商品照舊。商品本身的「一般價格」還是要填一個數字(例如最低價),WooCommerce 才會讓商品上架,前台不會顯示它。
第 2 段把商品頁和列表上的價格換成「每平方公尺 NT$800 起」。客人在商店頁就知道這是依尺寸計價的商品,不會以為 800 元可以買一整片。
第 3 段是商品頁的畫面:加入購物車按鈕前面多了寬、高兩格,下面一行寫尺寸範圍和最低計價面積,再下面是試算。試算是用瀏覽器端的小程式做的,客人每改一個數字就重新算一次,填 120 × 150 會立刻看到「1.80 平方公尺,NT$1,440」。
第 4 段在伺服器這邊再檢查一次。瀏覽器的欄位限制可以被繞過,所以加入購物車時再驗一次寬高有沒有在範圍內,沒填或超出範圍就擋下來,顯示「請填寫寬和高,範圍 30~300 公分」。
第 5 段把尺寸存進購物車項目。同一件商品、不同尺寸會變成購物車裡不同的兩列,各自有各自的價格,這點和一般商品不一樣。
第 6 段在購物車算總額之前,把每一列的價格換成「面積 × 單價」,未滿最低面積就用最低面積算。因為價格是在伺服器算的,客人改不了。
第 7 段讓購物車和結帳頁的商品下面多一行「尺寸:120 × 150 公分(1.8 平方公尺)」,下單後同一行寫進訂單項目,後台訂單、通知信、會員中心的訂單明細都看得到,出貨的人照單裁切就好。
測試結果
我們在本機測試站把「精油組合」當成依尺寸計價的商品來測,單價 800、最低 0.5 平方公尺、範圍 30~300 公分:
- 商品頁價格顯示「每平方公尺 NT$800.00 起」;填 120 × 150,試算顯示「1.80 平方公尺,NT$1,440」,加入購物車成功。
- 故意填 10 × 10,被擋下,顯示「請填寫寬和高,範圍 30~300 公分」。
- 新版區塊購物車顯示「尺寸:120 × 150 公分(1.8 平方公尺)」、金額 1,440 元;結帳完成後,訂單項目的金額是 1,440,項目下面有同一行尺寸。
- 傳統購物車填 200 × 250,顯示「200 × 250 公分(5 平方公尺)」、小計 4,000 元。
跟「客製欄位加價」的差別
〈WooCommerce 商品頁加客製欄位〉那篇做的是「勾了刻字加 50 元」這種固定加價;這篇是整個價格都由客人填的數字算出來。兩篇的骨架一樣:商品頁加欄位、加入購物車時驗證、把資料存進購物車項目、算價格、寫進訂單。看懂其中一篇,另一篇就很容易改成你要的樣子,例如改成「長度 × 每公尺單價」的電線、繩子,只要把面積的算法換成長度就好。
價格要讓客人自己算的商品,記得在商品說明把計算方式寫清楚,例如「以寬 × 高計算面積,未滿 0.5 平方公尺以 0.5 計」;試算只是幫客人確認,說明才是依據。
把報價單搬到網站上,客人半夜也能下單
窗簾、玻璃、輸出這些行業,報價多半靠電話和 LINE 來回,客人問一次、店家算一次。把算法放上網站,客人自己填、自己看價錢、自己下單,店家早上打開後台就是一張尺寸寫好的訂單。
如果你的商品也是看尺寸算價格,想一起規劃商品頁、訂單和出貨流程,可以先看〈IG 帳號不是你的資產〉想想網站要做到什麼,商品頁怎麼讓客人安心下單,可以參考〈網站有人看卻沒人聯絡?〉。MIMI 專做客製化網頁設計,購物車電商網站可以依你的計價方式客製。MIMI 提供臺北網頁設計服務,臺北的店家可以用電話、Email 直接和設計師討論;費用可以先看首頁的製作費用參考,歡迎聯絡 MIMI。
