WooCommerce 後台商品列表新增複製購物車連結並支援優惠券輸入功能

前言

在 WooCommerce 後台商品列表中,管理者常需要快速取得商品的「加入購物車」連結以便分享或推廣。這段程式碼實作了在商品列表中新增一欄「複製課程連結」按鈕,點擊後可彈出視窗讓使用者輸入優惠券代碼,並將優惠券參數附加到連結中,最後將完整連結複製到剪貼簿。這對於需要快速產生帶優惠券的購物車連結的電商管理者非常實用。

新增自訂欄位顯示複製按鈕

利用 manage_edit-product_columns 過濾器新增一欄「複製課程連結」,並透過 manage_product_posts_custom_column 動作在該欄位輸出一個帶有商品加入購物車 URL 的按鈕。URL 是以網站首頁 URL 加上 /cart/?add-to-cart=商品ID 組成。

add_filter('manage_edit-product_columns', 'add_copy_link_column');
function add_copy_link_column($columns) {
    $columns['copy_add_to_cart'] = __('複製課程連結', 'woocommerce');
    return $columns;
}

add_action('manage_product_posts_custom_column', 'show_copy_link_column_content', 10, 2);
function show_copy_link_column_content($column, $post_id) {
    if ($column === 'copy_add_to_cart') {
        $product_id = (int) $post_id;
        $site_url = my_copy_cart_site_url();
        $add_to_cart_url = $site_url . '/cart/?add-to-cart=' . $product_id;
        echo '<button type="button" class="button copy-cart-link" data-url="' . esc_attr($add_to_cart_url) . '" title="點擊複製連結">複製</button>';
    }
}

客製化 JavaScript 處理複製邏輯與優惠券輸入

在後台商品列表頁尾插入 JavaScript 和 CSS,當使用者點擊「複製」按鈕時:

  1. 透過 window.prompt 詢問是否輸入優惠券代碼,可留空。
  2. 根據輸入結果組合最終 URL,若有優惠券則加上 &wt_coupon=優惠券代碼
  3. 使用 Clipboard API 複製連結,若不支援則使用傳統 execCommand 備援。
  4. 複製成功會顯示成功提示,失敗則顯示錯誤提示並提供手動複製。
function buildFinalUrl(baseUrl) {
    var coupon = window.prompt('是否要加入優惠券?\n(可留空,直接按確定即可)', '');
    if (coupon === null) return baseUrl;
    coupon = String(coupon || '').trim();
    if (!coupon) return baseUrl;
    var joiner = (baseUrl.indexOf('?') === -1) ? '?' : '&';
    return baseUrl + joiner + 'wt_coupon=' + encodeURIComponent(coupon);
}

$(document).on('click', '.copy-cart-link', function(e) {
    e.preventDefault();
    var button = $(this);
    var baseUrl = button.data('url');
    var originalHtml = button.html();
    if (button.hasClass('copying')) return;
    button.addClass('copying');
    var finalUrl = buildFinalUrl(baseUrl);
    if (navigator.clipboard && window.isSecureContext) {
        navigator.clipboard.writeText(finalUrl).then(function() {
            showCopySuccess(button, originalHtml);
        }).catch(function() {
            fallbackCopyTextToClipboard(finalUrl, button, originalHtml);
        });
    } else {
        fallbackCopyTextToClipboard(finalUrl, button, originalHtml);
    }
});

快速動作連結整合

除了欄位按鈕外,也在商品標題下方的快速動作連結加入「複製購物車連結」,提升操作便利性。此連結同樣帶有商品加入購物車的 URL,並套用相同的 JavaScript 行為。

add_filter('post_row_actions', 'add_copy_link_quick_action', 10, 2);
function add_copy_link_quick_action($actions, $post) {
    if ($post->post_type === 'product') {
        $product_id = (int) $post->ID;
        $site_url = my_copy_cart_site_url();
        $add_to_cart_url = $site_url . '/cart/?add-to-cart=' . $product_id;
        $actions['copy_cart_link'] = '<a href="#" class="copy-cart-link" data-url="' . esc_attr($add_to_cart_url) . '" style="color:#0073aa;">📋 複製購物車連結</a>';
    }
    return $actions;
}

實務應用與優化建議

此功能適合需要快速產生帶優惠券的購物車連結的 WooCommerce 商店管理員,方便推廣或客服回覆。未來可優化:

  • 將網站 URL 改為動態取得,避免硬編碼。
  • 增加複製成功的視覺動畫提升 UX。
  • 支援多種優惠券參數或其他自訂參數。
  • 對於大量商品列表,可考慮優化前端效能。

完整程式碼

<?php
/**
 * WooCommerce 後台商品列表添加複製 add-to-cart 連結的功能 + 可選優惠券
 * 適用於 WPCode(PHP Snippet / Run Everywhere 或 Admin Only)
 *
 * 功能:
 * - 商品列表新增一欄「複製課程連結」
 * - 點按後彈出視窗詢問優惠券(可留空)
 * - 若有填,複製的 URL 會加上:&wt_coupon=COUPON
 * - 同時支援「快速動作」複製
 */

/** 你網站的網域(建議改成動態,不用寫死) */
function my_copy_cart_site_url() {
    return home_url();
}

// 在商品列表中添加自定義列
add_filter('manage_edit-product_columns', 'add_copy_link_column');
function add_copy_link_column($columns) {
    $columns['copy_add_to_cart'] = __('複製課程連結', 'woocommerce');
    return $columns;
}

// 顯示列內容
add_action('manage_product_posts_custom_column', 'show_copy_link_column_content', 10, 2);
function show_copy_link_column_content($column, $post_id) {
    if ($column === 'copy_add_to_cart') {
        $product_id = (int) $post_id;

        $site_url = my_copy_cart_site_url();
        $add_to_cart_url = $site_url . '/cart/?add-to-cart=' . $product_id;

        echo '<button type="button" class="button copy-cart-link" data-url="' . esc_attr($add_to_cart_url) . '" title="點擊複製連結">
                 複製
              </button>';
    }
}

// 添加 JavaScript 和 CSS
add_action('admin_footer', 'copy_link_admin_script');
function copy_link_admin_script() {
    $screen = get_current_screen();
    if (!$screen || $screen->id !== 'edit-product') {
        return;
    }
    ?>

<style>
        .copy-cart-link {
            display: inline-flex;
            align-items: center;
            gap: 4px;
            padding: 4px 8px;
            font-size: 12px;
            line-height: 1.4;
            border-radius: 3px;
            cursor: pointer;
            transition: all 0.3s ease;
        }
        .copy-cart-link:hover {
            background-color: #000000;
            color: white;
            transform: translateY(-1px);
        }
        .copy-cart-link .dashicons {
            font-size: 14px;
            width: 14px;
            height: 14px;
        }
        .column-copy_add_to_cart {
            width: 110px;
            text-align: center;
        }
        @media screen and (max-width: 782px) {
            .copy-cart-link {
                padding: 6px 10px;
                font-size: 13px;
            }
        }
    </style>

    <script type="text/javascript">
        jQuery(document).ready(function($) {

            // 組裝最終要複製的 URL(可選 wt_coupon)
            function buildFinalUrl(baseUrl) {
                // 1) 詢問優惠券(可留空)
                var coupon = window.prompt('是否要加入優惠券?\n(可留空,直接按確定即可)', '');

                // 使用者按取消 -> 仍照原本複製(你也可以改成 return null 代表不複製)
                if (coupon === null) {
                    return baseUrl;
                }

                coupon = String(coupon || '').trim();
                if (!coupon) {
                    return baseUrl;
                }

                // 2) 已有 ?add-to-cart=...,直接加 &wt_coupon=
                //    若未來 baseUrl 可能沒有 query,這裡也做保險處理
                var joiner = (baseUrl.indexOf('?') === -1) ? '?' : '&';
                return baseUrl + joiner + 'wt_coupon=' + encodeURIComponent(coupon);
            }

            $(document).on('click', '.copy-cart-link', function(e) {
                e.preventDefault();

                var button = $(this);
                var baseUrl = button.data('url');
                var originalHtml = button.html();

                if (button.hasClass('copying')) return;
                button.addClass('copying');

                var finalUrl = buildFinalUrl(baseUrl);

                // 若你希望「按取消就不複製」,把 buildFinalUrl 的取消行為改成 return null
                // 然後這裡加上:
                // if (!finalUrl) { button.removeClass('copying'); return; }

                if (navigator.clipboard && window.isSecureContext) {
                    navigator.clipboard.writeText(finalUrl).then(function() {
                        showCopySuccess(button, originalHtml);
                    }).catch(function(err) {
                        console.error('Copy failed: ', err);
                        fallbackCopyTextToClipboard(finalUrl, button, originalHtml);
                    });
                } else {
                    fallbackCopyTextToClipboard(finalUrl, button, originalHtml);
                }
            });

            function fallbackCopyTextToClipboard(text, button, originalHtml) {
                var textArea = document.createElement("textarea");
                textArea.value = text;

                textArea.style.top = "0";
                textArea.style.left = "0";
                textArea.style.position = "fixed";
                textArea.style.opacity = "0";
                textArea.style.pointerEvents = "none";

                document.body.appendChild(textArea);
                textArea.focus();
                textArea.select();

                try {
                    var successful = document.execCommand('copy');
                    if (successful) {
                        showCopySuccess(button, originalHtml);
                    } else {
                        showCopyError(button, originalHtml, text);
                    }
                } catch (err) {
                    console.error('Copy failed: ', err);
                    showCopyError(button, originalHtml, text);
                }

                document.body.removeChild(textArea);
            }

            function showCopySuccess(button, originalHtml) {
                button.removeClass('copying').addClass('copied');
                button.html('<span class="dashicons dashicons-yes"></span> 已複製');

                setTimeout(function() {
                    button.removeClass('copied');
                    button.html(originalHtml);
                }, 2500);
            }

            function showCopyError(button, originalHtml, text) {
                button.removeClass('copying');

                var tooltip = $('<div class="copy-error-tooltip" style="position:absolute;background:#333;color:#fff;padding:8px 12px;border-radius:4px;font-size:12px;z-index:9999;max-width:320px;word-break:break-all;">複製失敗,請手動複製:<br>' + text + '</div>');
                $('body').append(tooltip);

                var buttonOffset = button.offset();
                tooltip.css({
                    top: buttonOffset.top - tooltip.outerHeight() - 5,
                    left: buttonOffset.left
                });

                setTimeout(function() { tooltip.remove(); }, 5000);

                tooltip.on('click', function() {
                    if (navigator.clipboard) navigator.clipboard.writeText(text);
                    $(this).remove();
                });
            }

        });
    </script>
    <?php
}

// 可選:添加快速動作連結(在商品名稱下方)
add_filter('post_row_actions', 'add_copy_link_quick_action', 10, 2);
function add_copy_link_quick_action($actions, $post) {
    if ($post->post_type === 'product') {
        $product_id = (int) $post->ID;

        $site_url = my_copy_cart_site_url();
        $add_to_cart_url = $site_url . '/cart/?add-to-cart=' . $product_id;

        $actions['copy_cart_link'] = '<a href="#" class="copy-cart-link" data-url="' . esc_attr($add_to_cart_url) . '" style="color:#0073aa;">📋 複製購物車連結</a>';
    }
    return $actions;
}