Skip to content

functions.php

php
<?php
/**
 * ============================================================
 *  woodmart-child / functions.php  ── 交接版(含繁中摘要註解)
 * ============================================================
 * 本檔案為原 functions.php 的「閱讀用副本」(.txt 不會被 WordPress 載入),
 * 在每個 function 上方加入 3-5 行繁中說明,方便新團隊快速理解。
 * 程式邏輯與原檔 100% 一致;如需修改請改原檔再同步本檔。
 *
 * 模組分區(行號為原檔行號,本檔含註解後會略有偏移):
 *   A 1-58       資產載入、版本控制、編輯器字型
 *   B 60-86      WooCommerce 運費邏輯
 *   C 88-150     訂單詳情頁追蹤(GA4、affiliate)
 *   D 152-278    ★ 藍新超商取貨訂單狀態管理
 *   E 280-328    後台訂單列表「需出貨」欄位
 *   F 330-490    前端最佳化(emoji/embed 移除、DNS prefetch、defer)
 *   G 492-727    ★ 結帳欄位客製(地址、條件式顯示)
 *   H 729-770    6H 配送注意事項彈窗
 *   I 772-838    追蹤碼(LINE Tag、FB 驗證、GTM)
 *   J 840-1144   覆寫父主題 woodmart_page_title()
 *   K 1147-1212  訂單滯留檢查(停用中)
 *   L 1214-1262  AddToAny / 優惠券 email 修正
 *   M 1264-1279  SEO:英文網址 noindex
 *   N 1281-1337  ★ LINE Pay 狀態異常自動修復
 *   O 1339-1377  結帳性別欄位
 *   P 1379-1408  Yoast robots.txt 修正
 *   Q 1410-1482  學生角色機制
 *   R 1484-1597  GPT 問答 shortcode + AJAX
 *   S 1599-1667  相關商品排除分類
 *   T 1669-1802  ★ 自訂超商取貨運送方式類別
 *   U 1804-2152  ★★★ 藍新 × 運送方式整合 JS(最複雜)
 *   V 2154-2175  後端阻擋 LINE Pay+超商
 *   W 2177-2271  ★★ 藍新付款參數補正
 *   X 2273-2372  ★★ 動態關閉藍新超商付款設定
 *   Y 2374-2397  藍新自動跳轉 3 秒
 * ============================================================
 */

// ========== 模組 A:資產載入、版本控制、編輯器字型 ==========

/**
 * 【功能】載入子主題的 style.css 與 main.min.js,並用 filemtime 自動帶版本號(破快取)。
 * 【觸發】wp_enqueue_scripts,priority 1000(最後載入,確保覆蓋父主題)。
 * 【備註】依賴父主題的 'woodmart-style' handle;JS 依賴 jQuery。
 */
function woodmart_child_enqueue_styles() {
    $css_file = get_stylesheet_directory() . '/style.css';
    $css_version = file_exists($css_file) ? filemtime($css_file) : '1.0.0';
    wp_enqueue_style( 'child-style', get_stylesheet_directory_uri() . '/style.css', array( 'woodmart-style' ), $css_version );

    $js_file = get_stylesheet_directory() . '/js/main.min.js';
    $js_version = file_exists($js_file) ? filemtime($js_file) : '1.0.0';
    wp_enqueue_script( 'custom-script', get_stylesheet_directory_uri() . '/js/main.min.js', array( 'jquery' ), $js_version, true );
}
add_action( 'wp_enqueue_scripts', 'woodmart_child_enqueue_styles', 1000 );

/**
 * 【功能】把所有屬於父/子主題的 CSS/JS URL 後面的 ?ver= 版本號,改寫為該檔案的修改時間 (filemtime)。
 * 【觸發】script_loader_src / style_loader_src,priority 15。
 * 【效果】無須手動 bump 版本,檔案一改、瀏覽器自動破快取。
 */
function crave_script_version_with_filemtime( $src ) {
    if ( strpos( $src, get_stylesheet_directory_uri() ) === false && strpos( $src, get_template_directory_uri() ) === false ) {
        return $src;
    }

    $parsed_url = parse_url( $src );
    if ( ! isset( $parsed_url['path'] ) ) {
        return $src;
    }

    $file_path = str_replace(
        array( get_stylesheet_directory_uri(), get_template_directory_uri() ),
        array( get_stylesheet_directory(), get_template_directory() ),
        $src
    );

    $file_path = strtok( $file_path, '?' );

    if ( file_exists( $file_path ) ) {
        $version = filemtime( $file_path );
        $src = strtok( $src, '?' );
        $src = add_query_arg( 'ver', $version, $src );
    }

    return $src;
}
add_filter( 'script_loader_src', 'crave_script_version_with_filemtime', 15, 1 );
add_filter( 'style_loader_src', 'crave_script_version_with_filemtime', 15, 1 );

/**
 * 【功能】為 TinyMCE 編輯器擴充中文字型(微軟正黑體、新細明體、標楷體、黑體等)與英文字型清單。
 * 【觸發】tiny_mce_before_init filter。
 * 【備註】後台貼文/頁面編輯器才會用到。
 */
function add_custum_fontfamily($initArray){

    // 中文字型
    $initArray['font_formats'] = "微軟正黑體=微軟正黑體,Microsoft JhengHei;新細明體=PMingLiU,新細明體;標楷體=標楷體,DFKai-SB,BiauKai;黑體=黑體,SimHei,Heiti TC;微軟雅黑體Light=微軟雅黑體Light,Microsoft YaHei Light;";


    // 英文字型
    $initArray['font_formats'] .= "Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=v erdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats;";

    return $initArray;
}
add_filter('tiny_mce_before_init', 'add_custum_fontfamily');
// ========== 模組 B:WooCommerce 運費邏輯 ==========

/**
 * 【功能】滿額免運顯示規則:當有 free_shipping 時,原本會隱藏其他運送方式;
 *        本函式特例保留「超商取貨」(newebpay_cvscom)和「6H 配送」(flat_rate:16),
 *        且 6H 配送在免運時改收 150 元(不享免運)。
 * 【觸發】woocommerce_package_rates,priority 100。
 */
function my_hide_shipping_when_free_is_available( $rates ) {
    $free = array();
    foreach ( $rates as $rate_id => $rate ) {
        if ( 'free_shipping' === $rate->method_id ) {
            $free[ $rate_id ] = $rate;
        }
    }

    if (!empty($free)) {
        foreach ( $rates as $rate_id => $rate ) {
            // 免運費時 仍顯示超商取貨
            if ( 'newebpay_cvscom'  === $rate->method_id ){
                $free[ $rate_id ] = $rate;
            }
            //免運時,仍顯示6H配送,改為150
            if('flat_rate:16' === $rate->id ){
                $rate->cost = 150;
                $free[$rate_id] = $rate;

            }
        }
    }
    return ! empty( $free ) ? $free : $rates;
}
add_filter( 'woocommerce_package_rates', 'my_hide_shipping_when_free_is_available', 100 );



// ========== 模組 C:訂單詳情頁追蹤(GA4、Affiliate) ==========

/**
 * 【功能】在訂單完成頁面(thank-you / 訂單詳情)輸出 GA4 purchase event,回傳訂單金額與幣別 TWD。
 * 【觸發】woocommerce_order_details_after_customer_details。
 * 【GA4】Measurement ID:G-Z5C8WK0J0F。
 */
function wh_CustomReadOrder($order_id)
{
    //getting order object
    $order = wc_get_order($order_id);

    // 檢查訂單是否存在
    if (!$order) {
        return;
    }

    $order_id  = $order->get_id();
    $order_data = $order->get_data();
    $order_total = $order_data['total'];

    ?>

    <script type="text/javascript">
        //GA4
        gtag('event', 'purchase', {
            'send_to': 'G-Z5C8WK0J0F',
            'value': '<?php echo esc_js($order_total); ?>',
            'currency': 'TWD'
        });
    </script>

    <?php
}

add_action('woocommerce_order_details_after_customer_details', 'wh_CustomReadOrder');


/**
 * 【功能】[affiliates] shortcode:在頁面輸出 VBTrax 聯盟追蹤的 conversion script,
 *        從 ?order=ID 取訂單金額並回傳給 vbtrax.com。
 * 【安全】已修正 XSS:用 absint() 過濾 GET 參數。
 * 【用途】放在訂單完成頁,供聯盟行銷追蹤轉換。
 */
function affiliates_trank(){

    //getting order object

    global $woocommerce;

    // 修正 XSS 風險:驗證和清理 GET 參數
    $order_id = isset($_GET['order']) ? absint($_GET['order']) : 0;

	if($order_id > 0){

    $order = wc_get_order($order_id);

    // 檢查訂單是否存在
    if (!$order) {
        return '';
    }

    $order_data     = $order->get_data();
    $order_total    = $order_data["total"];

    $trank_code .= "<script> (function () {var VARemoteLoadOptions = {whiteLabel: { id: 8, siteId: 1784, domain: 'vbtrax.com' }, conversion: true,conversionData: {step: 'sale',orderTotal: '";
    $trank_code .= $order_total."',";
    $trank_code .= "order:'".$order_id."',";
    $trank_code .= "},locale: 'en-US', mkt: true};(function (c, o, n, v, e, r, l, y) {c['VARemoteLoadOptions'] = e; r = o.createElement(n), l = o.getElementsByTagName(n)[0];r.async = 1; r.src = v; l.parentNode.insertBefore(r, l);})(window, document, 'script', 'https://cdn.vbtrax.com/javascripts/va.js', VARemoteLoadOptions);})(); </script>";

    return $trank_code;}
}
add_shortcode('affiliates', 'affiliates_trank');

/**
 * ========================================
 * 藍新金流超商取貨付款訂單狀態管理
 * ========================================
 * 目標:
 * 1. 超商取貨選擇門市後 → pending(等待付款中)
 * 2. 顧客實際取貨付款後 → completed(已完成)
 * 3. 不修改外掛檔案,用 hook 覆蓋邏輯
 *
 * 策略:在外掛設定狀態後立即覆蓋
 */

/**
 * 主要方法:監控所有狀態變更並立即修正
 * 使用最高優先級確保在所有其他 hook 之後執行
 *
 * ⚠️ 超商取貨付款流程:
 * 1. 顧客下單選門市 → pending(等待付款中)
 * 2. 門市資訊確認(藍新第一次回傳)→ 強制改回 pending(等待顧客取貨付款)
 * 3. 顧客到超商取貨付款(藍新第二次回傳,有「付款時間」)→ 維持 completed
 */
// ========== 模組 D:藍新超商取貨訂單狀態管理(核心,最易出錯) ==========

/**
 * 【功能】★ 攔截藍新超商取貨付款(CVSCOMPayed)訂單的狀態變更:
 *          - 顧客只是「選了門市」(藍新第一次回傳,備註只有店名)→ 強制改回 pending
 *          - 顧客「實際取貨付款」(藍新第二次回傳,備註含「付款時間」)→ 維持 completed
 * 【觸發】woocommerce_order_status_changed,priority 999(最高,確保在外掛之後執行)。
 * 【判斷】訂單備註同時有「藍新金流交易序號」+「付款時間」才算真正付款。
 * 【關聯】newebpay_cvscom_manual_update(手動更新時補正)。
 */
add_action('woocommerce_order_status_changed', 'newebpay_cvscom_fix_status', 999, 4);
function newebpay_cvscom_fix_status($order_id, $old_status, $new_status, $order) {
    // 只處理藍新金流訂單
    if (!$order || $order->get_payment_method() !== 'newebpay') {
        return;
    }

    // 取得訂單資訊
    $selected_payment = $order->get_meta('_nwpSelectedPayment');

    // 判斷是否為「超商取貨付款」訂單
    // 超商取貨付款:顧客到超商才付款,在此之前都保持 pending 狀態
    if ($selected_payment !== 'CVSCOMPayed') {
        return;
    }

    // 檢查訂單備註,判斷是選擇門市還是實際付款
    $notes = wc_get_order_notes(array(
        'order_id' => $order_id,
        'limit' => 20,
    ));

    $has_payment_completed = false;
    $has_store_note = false;

    foreach ($notes as $note) {
        // 檢查是否有「真正的」付款完成備註
        // 必須同時有「藍新金流交易序號」和「付款時間」才算付款完成
        // 因為第一次回傳(選門市)只有交易序號,沒有付款時間
        // 第二次回傳(實際付款)才會有付款時間
        if (strpos($note->content, '藍新金流交易序號') !== false
            && strpos($note->content, '付款時間') !== false) {
            $has_payment_completed = true;
        }
        // 檢查是否有門市選擇備註
        if (strpos($note->content, '超商取貨資訊') !== false || strpos($note->content, '店家:') !== false) {
            $has_store_note = true;
        }
    }

    // ⚠️ 核心邏輯:
    // 如果已經有「付款時間」,表示顧客真的付款了,不要改回 pending
    if ($has_payment_completed) {
        return;
    }

    // 沒有付款時間,表示只是選了門市,強制改回 pending
    if ($new_status === 'processing' || $new_status === 'completed') {
        remove_action('woocommerce_order_status_changed', 'newebpay_cvscom_fix_status', 999);

        if ($has_store_note) {
            $order->set_status('pending', '超商取貨付款訂單:門市已選定,等待顧客取貨付款', true);
        } else {
            $order->set_status('pending', '超商取貨付款:等待顧客選擇門市並取貨付款', true);
        }

        $order->save();
        add_action('woocommerce_order_status_changed', 'newebpay_cvscom_fix_status', 999, 4);
    }
}

/**
 * 後台手動更新:攔截「至藍新更新交易狀態」按鈕
 * ⚠️ 超商取貨付款訂單:只有在尚未付款時才強制保持 pending 狀態
 */
/**
 * 【功能】後台點擊「至藍新更新交易狀態」按鈕時的補正:
 *        若是超商取貨付款訂單但備註尚無「付款時間」,強制保持 pending。
 * 【觸發】woocommerce_payment_complete,priority 20。
 * 【關聯】與 newebpay_cvscom_fix_status 同邏輯,但攔截不同 hook。
 */
add_action('woocommerce_payment_complete', 'newebpay_cvscom_manual_update', 20, 1);
function newebpay_cvscom_manual_update($order_id) {
    $order = wc_get_order($order_id);

    if (!$order || $order->get_payment_method() !== 'newebpay') {
        return;
    }

    // 檢查是否為超商取貨付款訂單
    $selected_payment = $order->get_meta('_nwpSelectedPayment');
    if ($selected_payment !== 'CVSCOMPayed') {
        return;
    }

    // 檢查訂單備註,判斷是否已經實際付款
    $notes = wc_get_order_notes(array(
        'order_id' => $order_id,
        'limit' => 20,
    ));

    $has_payment_completed = false;
    foreach ($notes as $note) {
        // 必須同時有「藍新金流交易序號」和「付款時間」才算付款完成
        if (strpos($note->content, '藍新金流交易序號') !== false
            && strpos($note->content, '付款時間') !== false) {
            $has_payment_completed = true;
            break;
        }
    }

    // 如果已經有付款時間,不要改回 pending
    if ($has_payment_completed) {
        return;
    }

    // 沒有付款時間,強制保持 pending 狀態
    if ($order->get_status() === 'processing' || $order->get_status() === 'completed') {
        $order->set_status('pending', '超商取貨付款:等待顧客取貨付款', true);
        $order->save();
    }
}

// ========== 模組 E:後台訂單列表「需出貨」欄位 ==========

/**
 * 【功能】在後台訂單列表插入「需出貨」欄位(緊接在訂單狀態欄之後)。
 * 【觸發】manage_edit-shop_order_columns,priority 20。
 */
add_filter( 'manage_edit-shop_order_columns', 'custom_shop_order_column', 20 );
function custom_shop_order_column($columns){
    $reordered_columns = array();

    // Inserting columns to a specific location
    foreach( $columns as $key => $column){
        $reordered_columns[$key] = $column;
        if( $key ==  'order_status' ){
            // Inserting after "Status" column
            $reordered_columns['shipping_column'] = '需出貨';
        }
    }
    return $reordered_columns;
}
/**
 * 【功能】「需出貨」欄位的內容渲染:
 *        - 超商取貨且已選店 → 紅字「超取需出貨」
 *        - 6H 配送 → 黃字「6H出貨」
 * 【觸發】manage_shop_order_posts_custom_column,priority 20。
 */
add_action( 'manage_shop_order_posts_custom_column' , 'custom_orders_list_column_content', 20, 2 );
function custom_orders_list_column_content( $column, $post_id ){
    switch ( $column ){
        case 'shipping_column' :
            // An instance of
            $order = wc_get_order($post_id);

            // Iterating through order shipping items
            // https://stackoverflow.com/questions/46102428/get-orders-shipping-items-details-in-woocommerce-3
            foreach( $order->get_items( 'shipping' ) as $item_id => $shipping_item_obj ){
                // Get the data in an unprotected array
                $shipping_item_data = $shipping_item_obj->get_data();
                $shipping_data_name         = $shipping_item_data['name'];
                $shipping_data_method_title = $shipping_item_data['method_title'];
                $shipping_data_method_id    = $shipping_item_data['method_id'];
                // shipping_data_name: 超商取貨付款
                // shipping_data_method_title: 超商取貨付款
                // shipping_data_method_id: newebpay_cvscom

                if( $shipping_data_method_title == '超商取貨付款' || $shipping_data_method_title == '超商取貨' ){
                    $store_name = $order->get_meta('_newebpayStoreName');
                    if ($store_name !== '') {
                        echo '<span style="color: #ca4a1f">超取需出貨</span>';
                    }
                }else if($shipping_data_method_title == '6H配送'){
                    echo "<span style='color:#FDAF01;'>6H出貨</span>";
                }else{
                    echo '';
                }
            }
            break;
    }
}


// ========== 模組 F:前端最佳化 ==========

/**
 * 【功能】幫除了 jquery.js 之外的所有 script 標籤加上 defer 屬性,提升前端載入速度。
 * 【觸發】script_loader_tag(目前已被註解停用,line 348)。
 * 【備註】因相容性問題暫時關閉;要啟用時請充分測試。
 */
function crave_js_defer_attr($tag) {
    if (is_admin()) {
        return $tag;
    }
    // Do not add defer attribute to these scripts
    $scripts_to_exclude = array('jquery.js'); // add a string of js file e.g. script.js

    foreach($scripts_to_exclude as $exclude_script) {
        if (true == strpos($tag, $exclude_script ) )
            return $tag;
    }
    // Defer all remaining scripts not excluded above
    return str_replace( ' src', ' defer src', $tag );
}
// jQuery issue fix CTKpro
// add_filter( 'script_loader_tag', 'crave_js_defer_attr', 10);

/**
* Remove junk from head
*/
/**
 * 【功能】移除 WordPress 在 head 輸出的版本號(generator meta),避免被探測攻擊面。
 * 【觸發】the_generator filter。
 * 【備註】緊接著的 remove_action 也清掉一系列 wp_head 雜訊(RSD、wlwmanifest、feed、shortlink 等)。
 */
// remove WordPress version number
function crave_remove_version() {
    return '';
}
add_filter('the_generator', 'crave_remove_version');
remove_action('wp_head', 'wp_generator');
remove_action('wp_head', 'rsd_link'); // remove really simple discovery (RSD) link
remove_action('wp_head', 'wlwmanifest_link'); // remove wlwmanifest.xml (needed to support windows live writer)
remove_action('wp_head', 'feed_links', 2); // remove rss feed links (if you don't use rss)
remove_action('wp_head', 'feed_links_extra', 3); // removes all extra rss feed links
remove_action('wp_head', 'index_rel_link'); // remove link to index page
remove_action('wp_head', 'start_post_rel_link', 10, 0); // remove random post link
remove_action('wp_head', 'parent_post_rel_link', 10, 0); // remove parent post link
remove_action('wp_head', 'adjacent_posts_rel_link', 10, 0); // remove the next and previous post links
remove_action('wp_head', 'adjacent_posts_rel_link_wp_head', 10, 0 );
remove_action('wp_head', 'wp_shortlink_wp_head', 10, 0 ); // remove shortlink

/**
 * 【功能】關閉 WordPress 的 emoji 載入(移除 emoji JS、CSS、TinyMCE plugin、DNS prefetch)。
 * 【觸發】init action。
 * 【效果】減少前端 HTTP 請求,加快載入。
 */
function crave_disable_emojis() {
    remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
    remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
    remove_action( 'wp_print_styles', 'print_emoji_styles' );
    remove_action( 'admin_print_styles', 'print_emoji_styles' );
    remove_filter( 'the_content_feed', 'wp_staticize_emoji' );
    remove_filter( 'comment_text_rss', 'wp_staticize_emoji' );
    remove_filter( 'wp_mail', 'wp_staticize_emoji_for_email' );
    add_filter( 'tiny_mce_plugins', 'crave_disable_emojis_tinymce' );
    add_filter( 'wp_resource_hints', 'crave_disable_emojis_remove_dns_prefetch', 10, 2 );
}
add_action( 'init', 'crave_disable_emojis' );

/**
* Filter function used to remove the tinymce emoji plugin.
*
* @param array $plugins
* @return array Difference betwen the two arrays
*/
/**
 * 【功能】從 TinyMCE 外掛清單移除 wpemoji,配合 crave_disable_emojis()。
 */
function crave_disable_emojis_tinymce( $plugins ) {
    if ( is_array( $plugins ) ) {
        return array_diff( $plugins, array( 'wpemoji' ) );
    } else {
        return array();
    }
}

/**
* Remove emoji CDN hostname from DNS prefetching hints.
*
* @param array $urls URLs to print for resource hints.
* @param string $relation_type The relation type the URLs are printed for.
* @return array Difference betwen the two arrays.
*/
/**
 * 【功能】從 DNS prefetch hints 中移除 emoji CDN(s.w.org),配合 crave_disable_emojis()。
 */
function crave_disable_emojis_remove_dns_prefetch( $urls, $relation_type ) {
    if ( 'dns-prefetch' == $relation_type ) {
        /** This filter is documented in wp-includes/formatting.php */
        $emoji_svg_url = apply_filters( 'emoji_svg_url', 'https://s.w.org/images/core/emoji/2/svg/' );
        $urls = array_diff( $urls, array( $emoji_svg_url ) );
    }
    return $urls;
}

/**
 * 【功能】全面關閉 WordPress 的 oEmbed 功能(REST 端點、TinyMCE、rewrite 規則、JS 等)。
 * 【觸發】init action,priority 9999(晚於外掛註冊)。
 */
function crave_disable_embeds() {

    // Remove the REST API endpoint.
    remove_action( 'rest_api_init', 'wp_oembed_register_route' );

    // Turn off oEmbed auto discovery.
    add_filter( 'embed_oembed_discover', '__return_false' );

    // Don't filter oEmbed results.
    remove_filter( 'oembed_dataparse', 'wp_filter_oembed_result', 10 );

    // Remove oEmbed discovery links.
    remove_action( 'wp_head', 'wp_oembed_add_discovery_links' );

    // Remove oEmbed-specific JavaScript from the front-end and back-end.
    remove_action( 'wp_head', 'wp_oembed_add_host_js' );
    add_filter( 'tiny_mce_plugins', 'crave_disable_embeds_tiny_mce_plugin' );

    // Remove all embeds rewrite rules.
    add_filter( 'rewrite_rules_array', 'crave_disable_embeds_rewrites' );

    // Remove filter of the oEmbed result before any HTTP requests are made.
    remove_filter( 'pre_oembed_result', 'wp_filter_pre_oembed_result', 10 );
}
add_action( 'init', 'crave_disable_embeds', 9999 );

/**
 * 【功能】從 TinyMCE 外掛清單移除 wpembed,配合 crave_disable_embeds()。
 */
function crave_disable_embeds_tiny_mce_plugin($plugins) {
    return array_diff($plugins, array('wpembed'));
}

/**
 * 【功能】移除所有 oEmbed 相關的 rewrite 規則。
 */
function crave_disable_embeds_rewrites($rules) {
    foreach($rules as $rule => $rewrite) {
        if(false !== strpos($rewrite, 'embed=true')) {
            unset($rules[$rule]);
        }
    }
    return $rules;
}

/**
 * 【功能】前台移除 jQuery Migrate(避免舊版 plugin 的相容性負擔)。
 * 【觸發】wp_default_scripts action。
 * 【備註】後台仍保留以避免破壞 admin UI;jQuery 版本鎖在 1.12.4。
 */
function crave_remove_jquery_migrate( &$scripts) {
    if(!is_admin()) {
        $scripts->remove('jquery');
        $scripts->add('jquery', false, array( 'jquery-core' ), '1.12.4');
    }
}
add_action( 'wp_default_scripts', 'crave_remove_jquery_migrate' );

/**
 * 【功能】在 wp_head 最前端輸出 DNS prefetch hints,預先解析常用第三方域名(typekit、cdnjs、googleapis、GA 等)。
 * 【觸發】wp_head action,priority 0(最先輸出)。
 */
function dns_prefetch() {
    // 修正邏輯:預設啟用 DNS prefetch
    $prefetch = 'on';
    echo '<meta http-equiv="x-dns-prefetch-control" content="' . esc_attr($prefetch) . '">';

    // 只有當 DNS prefetch 啟用時才加入預連接的域名
    if ($prefetch == 'on') {
        $dns_domains = array(
            "//use.typekit.net",
            "//netdna.bootstrapcdn.com",
            "//cdnjs.cloudflare.com",
            "//ajax.googleapis.com",
            "//s0.wp.com",
            "//s.gravatar.com",
            "//stats.wordpress.com",
            "//www.google-analytics.com"
        );
        foreach ($dns_domains as $domain) {
            if (!empty($domain)) {
                echo '<link rel="dns-prefetch" href="' . esc_url($domain) . '" />';
            }
        }
    }
}
add_action( 'wp_head', 'dns_prefetch', 0 );


// ========== 模組 G:結帳欄位客製(地址、條件式顯示) ==========

/**
 * 【功能】在結帳頁將所有地址欄位(country/address_1/address_2/city/state/postcode)的 required 設為 false。
 *        實際必填驗證改由 wps_select_checkout_field_process() 依運送方式動態判斷。
 * 【觸發】woocommerce_default_address_fields,priority 20。
 */
add_filter( 'woocommerce_default_address_fields' , 'filter_default_address_fields', 20, 1 );
function filter_default_address_fields( $address_fields ) {
    // Only on checkout page
    if( ! is_checkout() ) return $address_fields;

    // All field keys in this array
    $key_fields = array('country','address_1','address_2','city','state','postcode', 'state', 'city');

    // Loop through each address fields (billing and shipping)
    foreach( $key_fields as $key_field )
        $address_fields[$key_field]['required'] = false;

    return $address_fields;
}

/**
 * 【功能】在結帳頁注入 jQuery:根據運送方式動態顯示/隱藏地址欄位。
 *        - 選超商取貨(newebpay_cvscom,含 instance ID 如 newebpay_cvscom:20)→ 隱藏所有地址欄位
 *        - 選宅配且國家=TW → 顯示所有地址欄位(必填)
 *        - 選宅配且國家≠TW → 顯示但不要求 address_2/postcode/state/city
 * 【觸發】wp_footer action(每頁底部,內含 is_checkout 判斷實際使用情境在結帳頁)。
 * 【關聯】wps_select_checkout_field_process()(後端對應驗證)。
 */
add_action( 'wp_footer', 'custom_checkout_field_script' );
function custom_checkout_field_script() {

    // HERE your shipping methods rate IDs
    $newebpay_cvscom = 'newebpay_cvscom';

    $required_text = esc_attr__( 'required', 'woocommerce' );
    $required_html = '<abbr class="required" title="' . $required_text . '">*</abbr>';
    ?>
    <script>
        jQuery(function($){
            var ism = 'input[name^="shipping_method"]',
                ismc = ism+':checked',
                rq = '-required',
                vr = 'validate'+rq,
                w = 'woocommerce',
                wv = w+'-validated',
                iv = '-invalid',
                fi = '-field',
                wir = w+iv+' '+w+iv+rq+fi,
                b = '#billing_',
                f = '_field',
                a1 = 'country',
                a2 = 'address_1',
                a3 = 'address_2',
                a4 = 'postcode',
                a5 = 'state',
                a6 = 'city',
                b1 = b+a1+f,
                b2 = b+a2+f,
                b3 = b+a3+f,
                b4 = b+a4+f,
                b5 = b+a5+f,
                b6 = b+a6+f,
                newebpay = '<?php echo $newebpay_cvscom; ?>';

            // Utility function to shows or hide checkout fields
            function showHide( action='show', selector='' ){
                if( action == 'show' ){
                    $(selector).show(function(){
                        // console.log('show');
                        // console.log($(selector));
                        $(this).addClass(vr);
                        $(this).removeClass(wv);
                        $(this).removeClass(wir);
                        // console.log($(selector+' > label > abbr').html());
                        // console.log( $(selector+' label') );
                        if( $(selector+' > label > abbr').html() == undefined ){
                            $(selector+' > label span.optional').remove();
                            $(selector+' label').append('<?php echo $required_html; ?>');
                        }
                    });
                }else if( action == 'requiredfalse'){
                    $(selector).show(function(){
                        // console.log('requiredfalse');
                        // console.log($(selector));
                        $(this).removeClass(vr);
                        $(this).removeClass(wv);
                        $(this).removeClass(wir);
                        // console.log($(selector+' > label > abbr').html());
                        // console.log( $(selector+' label > .required') );
                        $(selector+' label > .required').remove();
                    });
                }else{
                    $(selector).hide(function(){
                        // console.log('hide');
                        $(this).removeClass(vr);
                        $(this).removeClass(wv);
                        $(this).removeClass(wir);
                        if( $(selector+' > label > abbr').html() != undefined )
                            $(selector+' label > .required').remove();
                    });
                }
            }

            // 檢查是否為超商取貨(支援 instance ID,例如 newebpay_cvscom:20)
            function isCvscomShipping() {
                var selectedShipping = $(ismc).val();
                return selectedShipping && selectedShipping.indexOf(newebpay) !== -1;
            }

            // Initializing at start after checkout init (Based on the chosen shipping method)
            setTimeout(function(){
                if( isCvscomShipping() ){
                    showHide('hide',b1);
                    showHide('hide',b2);
                    showHide('hide',b3);
                    showHide('hide',b4);
                    showHide('hide',b5);
                    showHide('hide',b6);
                }else{
                    showHide('show',b1);
                    showHide('show',b2);
                    showHide('show',b3);
                    showHide('show',b4);
                    showHide('show',b5);
                    showHide('show',b6);
                }
            }, 100);

            // When shipping method is changed (Live event)
            $( 'form.checkout' ).on( 'change', ism, function() {
                if( isCvscomShipping() ){
                    showHide('hide',b1);
                    showHide('hide',b2);
                    showHide('hide',b3);
                    showHide('hide',b4);
                    showHide('hide',b5);
                    showHide('hide',b6);
                }else{
                    showHide('show',b1);
                    showHide('show',b2);
                    showHide('show',b3);
                    showHide('show',b4);
                    showHide('show',b5);
                    showHide('show',b6);
                }
            });

            // 若選擇國外
            $( 'form.checkout' ).on( 'change', '#billing_country', function() {
                // console.log('enter');
                if( $(this).val() == 'TW' ){
                    console.log('TW');
                    showHide('show',b1);
                    showHide('show',b2);
                    showHide('show',b3);
                    showHide('show',b4);
                    showHide('show',b5);
                    showHide('show',b6);
                }else{
                    // console.log('others');
                    showHide('show',b1);
                    showHide('show',b2);
                    showHide('requiredfalse',b3);
                    showHide('requiredfalse',b4);
                    showHide('requiredfalse',b5);
                    showHide('requiredfalse',b6);
                }
            });
        });
    </script>
    <?php
}

// add_filter('filter_woocommerce_shipping_packages', function ($r) {
//     $cs = WC()->session->get( 'chosen_shipping_methods' );
//     error_log('chosen shipping: ' . print_r($cs, true));
//     return $r;
// });
// add_filter( 'woocommerce_shipping_packages', 'filter_woocommerce_shipping_packages', 10, 2 );

/****
 * checkout field檢查
 */
/**
 * 【功能】結帳送出時的後端必填驗證(依運送方式分流):
 *        - 超商取貨:地址欄位全免
 *        - flat_rate:4 / flat_rate:6:只驗 address_1
 *        - flat_rate:16(6H 配送):須完整地址,且縣市須為「台北市/臺北市/新北市」+ 新北限定特定區
 *        - 其他(含國際):完整地址全部必填
 * 【觸發】woocommerce_checkout_process action。
 * 【關聯】custom_checkout_field_script()(前端顯示)。
 */
add_action('woocommerce_checkout_process', 'wps_select_checkout_field_process');
function wps_select_checkout_field_process() {
    $newebpay_cvscom = 'newebpay_cvscom';
    $chosen_shipping_method = WC()->session->get( 'chosen_shipping_methods' )[0];
    $billing                = '<strong> ' . __('訂購人的', 'woocommerce') . ' ';
    $shipping               = '<strong> ' . __('訂購人的', 'woocommerce') . ' ';
    $country                = __('國家', 'woocommerce');
    $address1               = __('地址', 'woocommerce');
    $postcode               = __('郵遞區號', 'woocommerce');
    $state                  = __('縣 / 市', 'woocommerce');
    $city                  = __('鄉鎮市區', 'woocommerce');
    $end_text               = '</strong> '. __('為必填欄位。', 'woocommerce');
    $not_matching        = '</strong> '.__('不符合。','woocommerce');

    // 使用 strpos 檢查是否為超商取貨(支援 instance ID,如 newebpay_cvscom:20)
    if( strpos($chosen_shipping_method, $newebpay_cvscom) !== false ) {
        // 超商取貨不需要驗證地址欄位
    }elseif( $chosen_shipping_method == 'flat_rate:4' ||
             $chosen_shipping_method == 'flat_rate:6'){
        if( empty($_POST['billing_address_1']) )
            wc_add_notice( $billing . $address1 . $end_text, 'error' );
        // if( empty($_POST['billing_state']) )
            // wc_add_notice( $billing . $state . $end_text, 'error' );
    }elseif($chosen_shipping_method == 'flat_rate:16'){
        //6H配送檢查
        if( empty($_POST['billing_country']) )
            wc_add_notice( $billing . $country . $end_text, 'error' );
        if( empty($_POST['billing_address_1']) )
            wc_add_notice( $billing . $address1 . $end_text, 'error' );
        if( empty($_POST['billing_postcode']) )
            wc_add_notice( $billing . $postcode . $end_text, 'error' );
        if( empty($_POST['billing_state']) )
            wc_add_notice( $billing . $state . $end_text, 'error' );
        if( empty($_POST['billing_city']) )
            wc_add_notice( $billing . $city . $end_text, 'error' );

        if($_POST['billing_state']!='台北市' && $_POST['billing_state']!='臺北市' && $_POST['billing_state']!='新北市'){
            wc_add_notice($billing . $postcode . $not_matching, 'error');
        }
        if($_POST['billing_state']=='新北市'){
            if($_POST['billing_city']!='新店區' && $_POST['billing_city']!='永和區' && $_POST['billing_city']!='中和區' && $_POST['billing_city']!='樹林區' && $_POST['billing_city']!='三重區' && $_POST['billing_city']!='蘆洲區' && $_POST['billing_city']!='新莊區' && $_POST['billing_city']!='汐止區' && $_POST['billing_city']!='板橋區'){
                wc_add_notice($billing . $postcode . $not_matching, 'error');
            }
        }
    }
    else {
        if( empty($_POST['billing_country']) )
            wc_add_notice( $billing . $country . $end_text, 'error' );
        if( empty($_POST['billing_address_1']) )
            wc_add_notice( $billing . $address1 . $end_text, 'error' );
        if( empty($_POST['billing_postcode']) )
            wc_add_notice( $billing . $postcode . $end_text, 'error' );
        if( empty($_POST['billing_state']) )
            wc_add_notice( $billing . $state . $end_text, 'error' );
        if( empty($_POST['billing_city']) )
            wc_add_notice( $billing . $city . $end_text, 'error' );
    }
}


// ========== 模組 H:6H 配送注意事項彈窗 ==========

/**
 * 【功能】結帳頁切換到 flat_rate:16(6H 配送)時,跳出 jquery-confirm 彈窗顯示出貨時段、
 *        郵遞區號注意事項、年節期間提醒。
 * 【觸發】wp_footer,僅在 is_checkout() 且非 endpoint 時輸出。
 * 【依賴】CDN 載入 jquery-confirm 3.3.2。
 */
    add_action( 'wp_footer', 'checkout_action_wp_footer', 10, 0 );
    function checkout_action_wp_footer(){
        if ( is_checkout() && ! is_wc_endpoint_url() ) {
            //add js code to check shipping methos choosen
            ?>
            <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-confirm/3.3.2/jquery-confirm.min.css">
            <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-confirm/3.3.2/jquery-confirm.min.js"></script>
            <script type="text/javascript">
                jQuery(document).ready(function() {
                    function checkShow6HRAlert(){
                        var current_method = jQuery('input[name^="shipping_method"]:checked').val();
                        if(current_method == 'flat_rate:16'){
                            jQuery.alert({
                            title: '6H貨運注意事項:',
                            content: "<ol style='list-style: decimal;padding-left:20px;'>"+
                                        '<li>訂單處理時間為週一至週五於9:30至15:00,當日15:00前下單之訂單可當日配達,若超過15:00下單則於下個工作日完成送件。(週五15:00後下單之訂單則於隔週一開始進行配送)</li>'+
                                        '<li>下單前請確認郵遞區號、住址以及收件人資訊是否填寫正確,請確認收件地址皆有人可收件。</li>'+
                                        '<li>若因天災、年節期間貨運量大等因素影響物流運送時程,將另行通知。</li>'+
                                      "</ol>",
                            });
                        }
                    }
                    // checkShow6HRAlert();
                     // On live "change event"
                     jQuery(document.body ).on( 'change', 'input[name^="shipping_method"]', function() {
                        checkShow6HRAlert();
                    });
                })
            </script>
            <!-- <div id="6hdialog">
                <p>6H貨運注意事項:</p>
                <ol>
                    <li>最快二小時到貨,最慢六小時到貨。請確認在這段時間內自己都是可以收件的喔~</li>
                    <li>週一至週五於9:30至16:00前下訂單及當天配達,若超過下午四點則下個工作日中午12:30開始寄送。</li>
                    <li>統一配送時間為週一至週五 中午 12:30 和下午4:00 (週五下午四點過後訂單則統一於週一開始進行配送喔)</li>
                    <li>請確認郵遞區號、住址以及收件人資訊是否填寫正確喔!</li>
                </ol>
            </div> -->
            <?php
        }
    }

// ========== 模組 I:追蹤碼(LINE Tag、FB 驗證、GTM) ==========

/**
 * 【功能】輸出 LINE Tag base code(pv 事件),結帳頁額外送 cv(轉換)事件。
 * 【觸發】wp_head action。
 * 【tagId】7873c94a-88a8-4847-a533-5fff1f881a8b
 */
add_action('wp_head','set_line_tag');
function set_line_tag(){
    echo "<!-- LINE Tag Base Code -->
    <!-- Do Not Modify -->
    <script>
    (function(g,d,o){
      g._ltq=g._ltq||[];g._lt=g._lt||function(){g._ltq.push(arguments)};
      var h=location.protocol==='https:'?'https://d.line-scdn.net':'http://d.line-cdn.net';
      var s=d.createElement('script');s.async=1;
      s.src=o||h+'/n/line_tag/public/release/v1/lt.js';
      var t=d.getElementsByTagName('script')[0];t.parentNode.insertBefore(s,t);
        })(window, document);
    _lt('init', {
      customerType: 'lap',
      tagId: '7873c94a-88a8-4847-a533-5fff1f881a8b'
    });
    _lt('send', 'pv', ['7873c94a-88a8-4847-a533-5fff1f881a8b']);
    </script>
    <noscript>
      <img height='1' width='1' style='display:none'
           src='https://tr.line.me/tag.gif?c_t=lap&t_id=7873c94a-88a8-4847-a533-5fff1f881a8b&e=pv&noscript=1' />
    </noscript>
    <!-- End LINE Tag Base Code -->";

    if( is_checkout() ){
        echo "
        <script>
            _lt('send', 'cv', { type: 'Conversion' },['7873c94a-88a8-4847-a533-5fff1f881a8b']);
        </script>";
    }
}



/**
 * 【功能】從 wp_posts 撈出標題含 'facebook_verification' 的文章,將其內容輸出為 FB 域名驗證 meta。
 * 【觸發】wp_head action。
 * 【安全】已修正 SQL injection:使用 wpdb::prepare() + esc_like()。
 * 【設計】用一篇後台文章存驗證碼,方便非工程人員修改。
 */
add_action( 'wp_head', 'set_fb_verification_to_meta');
function set_fb_verification_to_meta(){
	global $wpdb;
	$title = 'facebook_verification';

	// 修正 SQL Injection 風險:正確使用 wpdb::prepare()
	$results = $wpdb->get_results(
		$wpdb->prepare(
			"SELECT * FROM $wpdb->posts WHERE post_title LIKE %s",
			'%' . $wpdb->esc_like( $title ) . '%'
		)
	);

	// 檢查查詢結果是否存在,避免陣列存取錯誤
	if (empty($results)) {
		return;
	}

	$p = $results[0];
	$fb_verification_str = preg_replace("/\s/","", strip_tags($p->post_content) ) ?: '';
	echo "<meta name='facebook-domain-verification' content='$fb_verification_str' />";
}

/**
 * 【功能】輸出 Google Tag Manager 標準 snippet(GTM-PC8K325)到 wp_head。
 * 【觸發】wp_head action。
 * 【備註】GTM body 端的 <noscript> 部分若有需要請在 footer.php 補上。
 */
function set_gtm(){
    echo "<!-- Google Tag Manager -->
    <script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
    new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
    j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
    'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
    })(window,document,'script','dataLayer','GTM-PC8K325');</script>
    <!-- End Google Tag Manager -->";
}
add_action('wp_head','set_gtm');

// **********************************************************************//
// Override Themes function -- themes/woodmart/inc/template-tags.php :line 748
// 增加breadcrumbs
// ! Page title function
// **********************************************************************//

// ========== 模組 J:覆寫父主題 woodmart_page_title(),加入 breadcrumbs ==========

/**
 * 【功能】完整覆寫父主題(woodmart/inc/template-tags.php:748)的 woodmart_page_title(),
 *        在頁面標題區塊加入 Breadcrumb NavXT 麵包屑(bcn_display),並支援自訂背景圖、顏色、設計風格。
 * 【觸發】woodmart_after_header,priority 10;且只有在父主題未先定義時才注入。
 * 【依賴】Breadcrumb NavXT 外掛、Woodmart options(page-title-design / size / color)。
 * 【注意】父主題若改原始函式,本覆寫可能與新版功能脫鉤,升級時需比對。
 */
if( ! function_exists( 'woodmart_page_title' ) ) {

    add_action( 'woodmart_after_header', 'woodmart_page_title', 10 );

    function woodmart_page_title() {
        global $wp_query, $post;

        // Remove page title for dokan store list page

        if( function_exists( 'dokan_is_store_page' )  && dokan_is_store_page() ) {
            return '';
        }

        $page_id = 0;

        $disable     = false;
        $page_title  = true;
        $breadcrumbs = woodmart_get_opt( 'breadcrumbs' );

        $image = '';

        $style = '';

        $page_for_posts    = get_option( 'page_for_posts' );
        $page_for_shop     = get_option( 'woocommerce_shop_page_id' );
        $page_for_projects = woodmart_tpl2id( 'portfolio.php' );

        $title_class = 'page-title-';

        $title_color = $title_type = $title_size = 'default';

        // Get default styles from Options Panel
        $title_design = woodmart_get_opt( 'page-title-design' );

        $title_size = woodmart_get_opt( 'page-title-size' );

        $title_color = woodmart_get_opt( 'page-title-color' );

        $shop_title = woodmart_get_opt( 'shop_title' );

        $shop_categories = woodmart_get_opt( 'shop_categories' );

        $single_post_design = woodmart_get_opt( 'single_post_design' );

        // Set here page ID. Will be used to get custom value from metabox of specific PAGE | BLOG PAGE | SHOP PAGE.
        $page_id = woodmart_page_ID();

        if( $page_id != 0 ) {
            // Get meta value for specific page id
            $disable = get_post_meta( $page_id, '_woodmart_title_off', true );

            $image = get_post_meta( $page_id, '_woodmart_title_image', true );

            $custom_title_color = get_post_meta( $page_id, '_woodmart_title_color', true );
            $custom_title_bg_color = get_post_meta( $page_id, '_woodmart_title_bg_color', true );


            if (!empty($image)) {
                // 如果是陣列,取第一個值
                if (is_array($image)) {
                    $image = array_shift($image);
                }

                // 確保是有效的 URL
                if (is_string($image) && !empty($image)) {
                    $style .= "background-image: url(" . esc_url($image) . ");";
                }
            }

            if( $custom_title_bg_color != '' ) {
                $style .= "background-color: " . $custom_title_bg_color . ";";
            }

            if( $custom_title_color != '' && $custom_title_color != 'default' ) {
                $title_color = $custom_title_color;
            }
        }

        if ( $title_design == 'disable' ) $page_title = false;

        if ( ! $page_title && ! $breadcrumbs ) $disable = true;

        if ( is_single() && $single_post_design == 'large_image' ) $disable = false;

        if ( $disable ) return;

        $title_class .= $title_type;
        $title_class .= ' title-size-'  . $title_size;
        $title_class .= ' title-design-' . $title_design;

        if ( $single_post_design == 'large_image' && is_single() ) {
            $title_class .= ' color-scheme-light';
        }else{
            $title_class .= ' color-scheme-' . $title_color;
        }

        if ( $single_post_design == 'large_image' && is_singular( 'post' ) ) {
            $image_url = get_the_post_thumbnail_url( $page_id );
            if ( $image_url && ! $style ) $style .= "background-image: url(" . $image_url . ");";
            $title_class .= ' post-title-large-image';

            ?>
                <div class="page-title <?php echo esc_attr( $title_class ); ?>" style="<?php echo esc_attr( $style ); ?>">
                    <div class="container">
                        <header class="entry-header">
                            <?php if ( get_the_category_list( ', ' ) ): ?>
                                <div class="meta-post-categories"><?php echo get_the_category_list( ', ' ); ?></div>
                            <?php endif ?>

                            <h1 class="entry-title"><?php the_title(); ?></h1>

                            <div class="entry-meta woodmart-entry-meta">
                                <?php woodmart_post_meta(array(
                                    'labels' => 1,
                                    'author' => 1,
                                    'author_ava' => 1,
                                    'date' => 1,
                                    'edit' => 0,
                                    'comments' => 1,
                                    'short_labels' => 0
                                )); ?>
                            </div>
                            <!---CUSTOM CODE START-->
                            <div class="breadcrumbs grid-container grid-parent">
                            <?php if ( function_exists( 'bcn_display' ) ) {
                                bcn_display();
                            } ?>
                            </div>
                            <!---CUSTOM CODE END-->
                        </header>
                    </div>
                </div>
            <?php
            return;
        }

        // Heading for pages
        if( is_singular( 'page' ) && ( ! $page_for_posts || ! is_page( $page_for_posts ) ) ):
            $title = get_the_title();

            ?>
                <div class="page-title <?php echo esc_attr( $title_class ); ?>" style="<?php echo esc_attr( $style ); ?>">
                    <div class="container">
                        <header class="entry-header">
                            <?php if ( woodmart_woocommerce_installed() && ( is_cart() || is_checkout() ) ): ?>
                                <?php woodmart_checkout_steps(); ?>
                            <?php else: ?>
                                <?php if( $page_title ): ?><h1 class="entry-title"><?php echo esc_html( $title ); ?></h1><?php endif; ?>
                                <?php if ( $breadcrumbs ) woodmart_current_breadcrumbs( 'pages' ); ?>
                            <?php endif ?>
                        </header><!-- .entry-header -->
                    </div>
                </div>
            <?php
            return;
        endif;


        // Heading for blog and archives
        if( $single_post_design != 'large_image' && is_singular( 'post' ) || woodmart_is_blog_archive() ):

            $title = ( ! empty( $page_for_posts ) ) ? get_the_title( $page_for_posts ) : esc_html__( 'Blog', 'woodmart' );

            if( is_tag() ) {
                $title = esc_html__( 'Tag Archives: ', 'woodmart')  . single_tag_title( '', false ) ;
            }

            if( is_category() ) {
                $title = '<span>' . single_cat_title( '', false ) . '</span>';
            }

            if( is_date() ) {
                if ( is_day() ) :
                    $title = esc_html__( 'Daily Archives: ', 'woodmart') . get_the_date();
                elseif ( is_month() ) :
                    $title = esc_html__( 'Monthly Archives: ', 'woodmart') . get_the_date( _x( 'F Y', 'monthly archives date format', 'woodmart' ) );
                elseif ( is_year() ) :
                    $title = esc_html__( 'Yearly Archives: ', 'woodmart') . get_the_date( _x( 'Y', 'yearly archives date format', 'woodmart' ) );
                else :
                    $title = esc_html__( 'Archives', 'woodmart' );
                endif;
            }

            if ( is_author() ) {
                /*
                 * Queue the first post, that way we know what author
                 * we're dealing with (if that is the case).
                 *
                 * We reset this later so we can run the loop
                 * properly with a call to rewind_posts().
                 */
                the_post();

                $title = esc_html__( 'Posts by ', 'woodmart' ) . '<span class="vcard"><a class="url fn n" href="' . esc_url( get_author_posts_url( get_the_author_meta( 'ID' ) ) ) . '" title="' . esc_attr( get_the_author() ) . '" rel="me">' . get_the_author() . '</a></span>';

                /*
                 * Since we called the_post() above, we need to
                 * rewind the loop back to the beginning that way
                 * we can run the loop properly, in full.
                 */
                rewind_posts();
            }

            if( is_search() ) {
                $title = esc_html__( 'Search Results for: ', 'woodmart' ) . get_search_query();
            }

            ?>
                <div class="page-title <?php echo esc_attr( $title_class ); ?> title-blog" style="<?php echo esc_attr( $style ); ?>">
                    <div class="container">
                        <header class="entry-header">
                            <?php if( $page_title && is_single() ): ?>
                                <h3 class="entry-title"><?php echo wp_kses( $title, woodmart_get_allowed_html() ); ?></h3>
                            <?php elseif( $page_title ): ?>
                                <h1 class="entry-title"><?php echo wp_kses( $title, woodmart_get_allowed_html() ); ?></h1>
                            <?php endif; ?>
                            <?php if ( $breadcrumbs && ! is_search() ) woodmart_current_breadcrumbs( 'pages' ); ?>
                        </header><!-- .entry-header -->
                    </div>
                </div>
            <?php
            return;
        endif;

        // Heading for portfolio
        if( is_singular( 'portfolio' ) || woodmart_is_portfolio_archive() ):

            $title = get_the_title( $page_for_projects );

            if( is_tax( 'project-cat' ) ) {
                $title = single_term_title( '', false );
            }

            ?>
                <div class="page-title <?php echo esc_attr( $title_class ); ?> title-blog" style="<?php echo esc_attr( $style ); ?>">
                    <div class="container">
                        <header class="entry-header">
                            <?php if( $page_title ): ?><h1 class="entry-title"><?php echo esc_html( $title ); ?></h1><?php endif; ?>
                            <?php if ( $breadcrumbs ) woodmart_current_breadcrumbs( 'pages' ); ?>
                        </header><!-- .entry-header -->
                    </div>
                </div>
            <?php
            return;
        endif;

        // Page heading for shop page
        if( woodmart_is_shop_archive()
            && ( $shop_categories || $shop_title )
         ):

            if( is_product_category() ) {

                $cat = $wp_query->get_queried_object();

                $cat_image = woodmart_get_category_page_title_image( $cat );

                if( $cat_image != '') {
                    $style = "background-image: url(" . $cat_image . ")";
                }
            }

            if( is_product_category() || is_product_tag() ) {
                $title_class .= ' with-back-btn';
            }

            if( ! $shop_title ) {
                $title_class .= ' without-title';
            }

            ?>
                <?php if ( apply_filters( 'woocommerce_show_page_title', true ) && ! is_singular( "product" ) ) : ?>
                    <div class="page-title <?php echo esc_attr( $title_class ); ?> title-shop" style="<?php echo esc_attr( $style ); ?>">
                        <div class="container">
                            <div class="nav-shop">

                                <div class="shop-title-wrapper">
                                    <?php if ( is_product_category() || is_product_tag() ): ?>
                                        <?php woodmart_back_btn(); ?>
                                    <?php endif ?>

                                    <?php if ( $shop_title ): ?>
                                        <h1 class="entry-title"><?php woocommerce_page_title(); ?></h1>
                                    <?php endif ?>
                                </div>

                                <?php if( ! is_singular( "product" ) && $shop_categories ) woodmart_product_categories_nav(); ?>

                            </div>
                        </div>
                    </div>
                <?php endif; ?>

            <?php

            return;
        endif;
    }
}


/**
 * ⚠️ 此功能目前已停用
 * 原功能:每日四次檢查訂單過久未付款,自動取消訂單
 * 停用原因:排程設定被註解,功能無法正常運作
 *
 * 如需啟用此功能,請:
 * 1. 取消下方程式碼的註解
 * 2. 確認時區設定正確(目前使用 UTC-8)
 * 3. 測試排程是否正常執行
 */

// add_action('admin_head','ctk_order_stay_too_long_daily_cron');
// function ctk_order_stay_too_long_daily_cron(){
// 	// 每日四次排程:檢查訂單過久未付款
//     wp_clear_scheduled_hook('ctk_order_stay_too_long_daily_cron_0800');
//     wp_clear_scheduled_hook('ctk_order_stay_too_long_daily_cron_1400');
//     wp_clear_scheduled_hook('ctk_order_stay_too_long_daily_cron_2000');
//     wp_clear_scheduled_hook('ctk_order_stay_too_long_daily_cron_0200');
// 	    // if ( ! wp_next_scheduled( 'ctk_order_stay_too_long_daily_cron_0800' ) ) {
// 	    //     wp_schedule_single_event( strtotime('8:00:00') - (8*60*60) , 'ctk_order_stay_too_long_daily_cron_0800' );
// 	    // }

// 	    // if ( ! wp_next_scheduled( 'ctk_order_stay_too_long_daily_cron_1400' ) ){
// 	    //     wp_schedule_single_event( strtotime('14:00:00') - (8*60*60) , 'ctk_order_stay_too_long_daily_cron_1400');
// 	    // }

// 	    // if ( ! wp_next_scheduled( 'ctk_order_stay_too_long_daily_cron_2000' ) ){
// 	    //     wp_schedule_single_event( strtotime('20:00:00') - (8*60*60) , 'ctk_order_stay_too_long_daily_cron_2000');
// 	    // }

//         // if ( ! wp_next_scheduled( 'ctk_order_stay_too_long_daily_cron_0200' ) ){
// 	    //     wp_schedule_single_event( strtotime('2:00:00') - (8*60*60) , 'ctk_order_stay_too_long_daily_cron_0200');
// 	    // }
// }
// add_action('ctk_order_stay_too_long_daily_cron_0800','ctk_check_order_stay_too_long',10);
// add_action('ctk_order_stay_too_long_daily_cron_1400','ctk_check_order_stay_too_long',10);
// add_action('ctk_order_stay_too_long_daily_cron_2000','ctk_check_order_stay_too_long',10);
// add_action('ctk_order_stay_too_long_daily_cron_0200','ctk_check_order_stay_too_long',10);
// ========== 模組 K:訂單滯留檢查(目前停用) ==========

/**
 * 【功能】掃描過去 24 小時~此刻前 2 小時內仍為 pending 的訂單,
 *        非超商取貨者直接取消('cancelled',備註:等待過久未付款)。
 * 【狀態】★ 目前停用:上方排程註冊已被註解(line 1158-1184);保留作為未來啟用範本。
 * 【啟用方式】取消上方註解,注意時區換算(採 UTC-8)。
 */
function ctk_check_order_stay_too_long(){
    // 抓過去24小時內~此刻前兩小時的所有等待付款中訂單
    $args = [
        'date_created' => ( time() - DAY_IN_SECONDS ).'...'.( time() - 2*60*60 ),
        'status' => ['pending'],
    ];

    $orders = wc_get_orders( $args );

    foreach ($orders as $order) {
        $order_id = $order->get_id();

        $is_store_pay = false;
        $shipping = $order->get_items( 'shipping' );
        foreach ($shipping as $shipping_item_obj) {
            $shipping_item_data = $shipping_item_obj->get_data();
            $shipping_data_method_title = $shipping_item_data['method_title'];

            if( $shipping_data_method_title == '超商取貨付款' ){
                $is_store_pay = true;
                break;
            }
        }
        if( !$is_store_pay ){
            $order->update_status('cancelled', '等待過久未付款');
        }
    }
}

// ========== 模組 L:AddToAny / 優惠券 email 修正 ==========

/**
 * 【功能】在 AddToAny 社群分享外掛中新增「LINE 加好友」服務,使用自訂 SVG 圖示。
 * 【觸發】A2A_FOLLOW_services filter,priority 10。
 * 【圖示】/wp-content/themes/woodmart-child/img/icons/line_icon.svg
 */
function addtoany_add_follow_services( $services ) {

    $services['line_add_friend'] = array(

        'name'        => '新增 line 好友(超連結)',

        'icon_url'    => '/wp-content/themes/woodmart-child/img/icons/line_icon.svg',

        'icon_width'  => 32,

        'icon_height' => 32,

        'href'        => '${id}',

    );

    return $services;

}

add_filter( 'A2A_FOLLOW_services', 'addtoany_add_follow_services', 10, 1 );


/**
 * 【功能】修正 WooCommerce 優惠券 email 限制的大小寫敏感問題:
 *        原生比對若大小寫不同會失敗,本函式改用 strcasecmp 比對。
 * 【觸發】woocommerce_coupon_is_valid,priority 10。
 * 【關聯】array_contains_case_insensitive() 工具函式。
 */
add_filter ( 'woocommerce_coupon_is_valid', 'wc_check_coupon_is_valid', 10, 2 );
function wc_check_coupon_is_valid( $result, $coupon ) {
    $user = wp_get_current_user();
    $restricted_emails = $coupon->get_email_restrictions();

    if ( count ( $restricted_emails ) > 0 ){
        if ( array_contains_case_insensitive ( $user->user_email, $restricted_emails ) ) {
            return $result;
        } else {
            return false;
        }
    } else {
        return $result;
    }
}
/**
 * 【功能】工具:判斷陣列是否包含指定字串(不分大小寫,使用 strcasecmp)。
 */
function array_contains_case_insensitive($needle, $haystack) {
    foreach ($haystack as $item) {
        if (strcasecmp($needle, $item) === 0) {
            return true;
        }
    }
    return false;
}

/*
? 目標: 不讓英文網址(en_us)被機器人爬到(Noindex / Nofollow)
! 限制 / 警告: NA
* 相關: Plugin - Yoast SEO
TODO 擴充功能: NA
普通註解
*/
// ========== 模組 M:SEO 英文版 noindex ==========

/**
 * 【功能】當網址含 /en_us/ 時,強制 Yoast 輸出 noindex,nofollow,
 *        避免英文版內容被搜尋引擎索引。
 * 【觸發】wpseo_robots filter,priority 10。
 * 【關聯】Yoast SEO 外掛。
 */
add_action( 'wpseo_robots', 'setNoindexIfEn', 10 );
function setNoindexIfEn( $robots ){
    $url_check = $_SERVER['REQUEST_URI'];
    if ( str_contains( $url_check, '/en_us/' ) ) {
        return 'noindex, nofollow';
    } else {
        return $robots;
    }
}

/*
? 目標: 設定 CRON Job 檢查訂單是否已用 Linepay 付款,若有更改訂單狀態,再用 mail 通知 Admin Linepay 訂單狀態轉換異常(從 處理中 到 失敗)
! 限制 / 警告: NA
* 相關: Plugin - SMTP + WooCommerce LINEPay Gateway
TODO 擴充功能: NA
普通註解
*/
// ========== 模組 N:LINE Pay 訂單狀態異常自動修復 ==========

/**
 * 【功能】訂單由 processing → failed 時,註冊一個 5 分鐘後執行的單次 cron(check_linepay_success)。
 *        用於攔截 LINE Pay 偶發的狀態誤判。
 * 【觸發】woocommerce_order_status_changed,priority 10。
 * 【關聯】check_linepay_success_handler() 是實際處理函式。
 */
add_action('woocommerce_order_status_changed', 'log_status', 10, 3);
function log_status($order_id, $old_status, $new_status){
    // 若訂單由「處理中」轉為「失敗」
    if ( 'processing' == $old_status && 'failed' == $new_status ){
         // 計算5分鐘後的時間戳
         $scheduled_time = time() + 5 * 60;

         // 將訂單ID添加到CRON事件的參數中
         $args = array(
             'order_id' => $order_id,
         );

         // 註冊一個新的CRON事件,5分鐘後執行
         wp_schedule_single_event($scheduled_time, 'check_linepay_success', $args);

    } else {
        return;
    }
}

add_action('check_linepay_success', 'check_linepay_success_handler');

/**
 * 【功能】5 分鐘後檢查 _linepay_payment_status meta:
 *        若為 'confirmed'(LINE Pay 端實際已付款成功),把 WC 訂單狀態從 failed 改回 processing,
 *        並寄信通知 4 位管理員(hello/joanna/Ruby/DD@chunling.com.tw)+ 寫 error_log。
 * 【觸發】check_linepay_success(自訂單次 cron)。
 * 【關聯】log_status() 註冊此 cron。
 */
function check_linepay_success_handler($order_id){
    $_linepay_payment_status = get_post_meta( $order_id, '_linepay_payment_status', true );
    // 若訂單 linepay 付款成功
    if ( $_linepay_payment_status && 'confirmed' == $_linepay_payment_status){
        // 轉換訂單狀態,由「失敗」改為「處理中」
        $order = new WC_Order($order_id);
        if (!empty($order)) {
            $order->update_status( 'processing' );
        }

        // 寄送資訊
        $sent_to = [
            'hello@chunling.com.tw',
            'joanna@chunling.com.tw',
            'Ruby@chunling.com.tw',
            'DD@chunling.com.tw'
        ];
        $title = 'HARU - Linepay 訂單狀態轉換檢查通知';
        // $message = '訂單編號 - ' . $order_id . ' 狀態轉換異常(需確認linepay後台狀況後手動調整訂單),請至編輯頁面查看:' . site_url( 'wp-admin/post.php?post='. $order_id .'&action=edit' );
        $message = '訂單編號 - ' . $order_id . ' 狀態轉換異常,已確認 linepay 付款狀態,並更改訂單狀態,請至編輯頁面查看:' . site_url( 'wp-admin/post.php?post='. $order_id .'&action=edit' );

        // 寄送郵件
        wp_mail( $sent_to, $title, $message );

        // Log 紀錄
        error_log( $message );
    }
}

/*
? 目標: 在送出訂單後,更新使用者性別資料
! 限制 / 警告: NA
* 相關: Page - checkout
TODO 擴充功能: NA
普通註解 */
// ========== 模組 O:結帳性別欄位 ==========

/**
 * 【功能】結帳送出後,將 posted_data['gender'] 存到當前使用者的 user_meta(key: gender)。
 * 【觸發】woocommerce_checkout_update_order_meta,priority 10。
 * 【關聯】set_checkout_field_default_value() 下次結帳時帶入預設值。
 */
add_action( 'woocommerce_checkout_update_order_meta', 'update_user_gender_meta', 10, 2 );
function update_user_gender_meta( $order_id, $posted_data ) {
    $user_id = get_current_user_id(); // 獲取當前使用者的 ID

    if ( $user_id && isset( $posted_data['gender'] ) ) {
        $gender = sanitize_text_field( $posted_data['gender'] );

        // 更新使用者的 usermeta
        update_user_meta( $user_id, 'gender', $gender );
    }
}

/*
? 目標: 在 Checkout 頁面設置 gender 欄位預設值
! 限制 / 警告: NA
* 相關: Page - checkout
TODO 擴充功能: NA
普通註解 */
/**
 * 【功能】登入用戶結帳時,自動將之前儲存的 gender user_meta 帶入結帳欄位的預設值。
 * 【觸發】woocommerce_checkout_fields filter。
 */
add_filter( 'woocommerce_checkout_fields', 'set_checkout_field_default_value' );
function set_checkout_field_default_value( $fields ) {
    // 檢查用戶是否已登錄
    if ( is_user_logged_in() ) {
        // 獲取用戶的 meta 值
        $user_id = get_current_user_id();
        $gender = get_user_meta( $user_id, 'gender', true );

        // 設定預設值
        if ( ! empty( $gender ) ) {
            $fields['billing']['gender']['default'] = $gender;
        }
    }
    return $fields;
}

/*
? 目標: 讓 Admin 可以修改 Woocommerce export 的 Custom PHP code to modify output
! 限制 / 警告: NA
* 相關: Plugin - Advanced Order Export For WooCommerce
TODO 擴充功能: NA
普通註解 */
add_filter("woe_user_can_add_custom_php", "__return_true");

/**
 * Fix Yoast SEO robots.txt changes.
 * https://wordpress.org/support/topic/disable-robots-txt-changing-by-yoast-seo/#post-16648736
 */
// ========== 模組 P:Yoast robots.txt 修正、AOE 自訂 PHP ==========

/**
 * 【功能】移除 Yoast SEO 對 robots.txt 的覆寫 callback(filter_robots),讓網站使用預設 robots.txt。
 * 【觸發】wp_loaded action。
 * 【參考】wordpress.org 支援文章 #post-16648736。
 *
 * 【補充】緊接的 add_filter("woe_user_can_add_custom_php", "__return_true")(line 1385)
 *        允許 Advanced Order Export For WooCommerce 後台編輯自訂 PHP code。
 */
function wpwc_fix_yoast_seo_robots_txt() {

	global $wp_filter;

	if ( isset( $wp_filter['robots_txt']->callbacks ) && is_array( $wp_filter['robots_txt']->callbacks ) ) {

		foreach ( $wp_filter['robots_txt']->callbacks as $callback_priority => $callback ) {
			foreach ( $callback as $function_key => $function ) {

				if ( 'filter_robots' === $function['function'][1] ) {
					unset( $wp_filter['robots_txt']->callbacks[ $callback_priority ][ $function_key ] );
				}
			}
		}
	}
}

add_action( 'wp_loaded', 'wpwc_fix_yoast_seo_robots_txt' );

// ========== 模組 Q:學生角色機制(st- 優惠券觸發 + 季度清除) ==========

/**
 * 【功能】註冊一個自訂 user role:'student',僅有 read 能力(用於識別學生身份、給予折扣)。
 * 【觸發】init action。
 */
function add_student_role() {
    if (!get_role('student')) {
        add_role(
            'student', // role 系统名
            'Student', // role 顯示名
            array(
                'read' => true,
            )
        );
    }
}
add_action('init', 'add_student_role');

/**
 * 【功能】當登入用戶套用以 'st-' 開頭的優惠券時,自動加上 student role,
 *        並寫入 user_meta 'student_role_assigned_date'(用於日後過期檢查)。
 * 【觸發】woocommerce_applied_coupon。
 */
function add_student_role_on_coupon_use($coupon_code) {
    if (strpos($coupon_code, 'st-') !== false) {
        $user = wp_get_current_user();

        if ($user && is_user_logged_in()) {
            $user->add_role('student');
            //# 增加時間戳記
            update_user_meta($user->ID, 'student_role_assigned_date', current_time('mysql'));
        }
    }
}
add_action('woocommerce_applied_coupon', 'add_student_role_on_coupon_use');

/**
 * 【功能】掃描所有 student role 用戶,移除 student_role_assigned_date 超過 1 年者。
 * 【觸發】quarterly_student_role_check(自訂季度 cron)。
 */
function check_and_remove_expired_student_roles() {
    $users = get_users(array(
        'role' => 'student',
        'meta_key' => 'student_role_assigned_date',
    ));

    foreach ($users as $user) {
        $assigned_date = get_user_meta($user->ID, 'student_role_assigned_date', true);
        if ($assigned_date) {
            $assigned_timestamp = strtotime($assigned_date);
            $one_year_ago = strtotime('-1 year');

            if ($assigned_timestamp < $one_year_ago) {
                $user->remove_role('student');
            }
        }
    }
}
add_action('quarterly_student_role_check', 'check_and_remove_expired_student_roles');

/**
 * 【功能】定義自訂 cron 排程頻率 'quarterly'(90 天執行一次)。
 * 【觸發】cron_schedules filter。
 */
function add_quarterly_cron_schedule($schedules) {
    $schedules['quarterly'] = array(
        'interval' => 60 * 60 * 24 * 90, // 每 90 天
        'display' => __('Once Quarterly')
    );
    return $schedules;
}
add_filter('cron_schedules', 'add_quarterly_cron_schedule');

/**
 * 【功能】註冊 quarterly_student_role_check cron job(若尚未註冊)。
 * 【觸發】init action。
 */
function schedule_quarterly_student_role_check() {
    if (!wp_next_scheduled('quarterly_student_role_check')) {
        wp_schedule_event(time(), 'quarterly', 'quarterly_student_role_check');
    }
}
add_action('init', 'schedule_quarterly_student_role_check');

/**
 * 【功能】子主題停用時清除 quarterly_student_role_check cron job,避免孤兒任務。
 * 【觸發】register_deactivation_hook。
 */
function deactivate_quarterly_student_role_check() {
    $timestamp = wp_next_scheduled('quarterly_student_role_check');
    wp_unschedule_event($timestamp, 'quarterly_student_role_check');
}
register_deactivation_hook(__FILE__, 'deactivate_quarterly_student_role_check');

// ========== 模組 R:GPT 問答 shortcode + AJAX + wp_gpt_answers 表 ==========

/**
 * 【功能】[gpt_question_button] shortcode:渲染問答按鈕(icon + topic),
 *        前端點擊時透過 AJAX 呼叫 OpenAI API 取得答案並顯示。
 * 【屬性】icon=圖示 URL、question=要問的問題、topic=按鈕顯示文字。
 */
function gpt_question_button_shortcode($atts) {
    $atts = shortcode_atts(array(
        'icon' => '',
        'question' => '',
        'topic' => ''
    ), $atts);

    $icon = esc_url($atts['icon']);
    $question = esc_html(strip_tags($atts['question']));
    $topic = esc_html(strip_tags($atts['topic']));

    $buttons_html = '<div class="gpt-question-button-wrapper">';
    $buttons_html .= '<div class="gpt-question-button" data-question="' . $question . '" data-topic="' . $topic . '">';
    if ($icon) {
        $buttons_html .= '<img src="' . $icon . '" alt="' . $topic . '" class="gpt-question-icon" />';
    }
    $buttons_html .= wp_trim_words($topic);
    $buttons_html .= '</div>';
    $buttons_html .= '<div class="gpt-answer"></div>';
    $buttons_html .= '</div>';

    return $buttons_html;
}
add_shortcode('gpt_question_button', 'gpt_question_button_shortcode');

/**
 * 【功能】載入 GPT 問答的 JS(gpt-script.js),並用 wp_localize_script 傳 ajax_url 與 nonce。
 * 【狀態】★ 對應的 add_action 目前已被註解(line 1518),shortcode 還可使用,但 AJAX 實際未被前端觸發;
 *        若要重新啟用請取消註解。
 */
function gpt_enqueue_scripts() {
    wp_enqueue_script('gpt-script', get_template_directory_uri() . '/js/gpt-script.js', array('jquery'), null, true);
    wp_localize_script('gpt-script', 'gpt_ajax', array(
        'ajax_url' => admin_url('admin-ajax.php'),
        'nonce' => wp_create_nonce('gpt_nonce') // 加入 nonce 安全驗證
    ));
}
//add_action('wp_enqueue_scripts', 'gpt_enqueue_scripts');

/**
 * 【功能】GPT AJAX 處理:
 *        1) check_ajax_referer 驗 nonce(防 CSRF);
 *        2) 先查 wp_gpt_answers 表的快取,命中則直接回傳;
 *        3) 沒快取則用 OPENAI_API_KEY(必須在 wp-config.php 定義)呼叫 GPT-3.5-turbo;
 *        4) 將回應寫入快取表並回傳給前端。
 * 【觸發】wp_ajax_gpt_handle_request / wp_ajax_nopriv_gpt_handle_request。
 * 【安全】API Key 必須放在 wp-config.php,不可硬編。
 */
function gpt_handle_ajax_request() {
    global $wpdb;

    // 修正 CSRF 風險:驗證 nonce
    check_ajax_referer('gpt_nonce', 'nonce');

    $question = sanitize_text_field($_POST['question']);

    // 檢查數據庫中是否已有答案
    $table_name = $wpdb->prefix . 'gpt_answers';
    $cached_answer = $wpdb->get_var($wpdb->prepare(
        "SELECT answer FROM $table_name WHERE question = %s",
        $question
    ));

    if ($cached_answer) {
        wp_send_json_success($cached_answer);
        return;
    }

    // 如果沒有緩存,調用 API 獲取答案
    // ⚠️ 安全性修正:API Key 應該儲存在 wp-config.php 中
    // 在 wp-config.php 加入:define('OPENAI_API_KEY', 'your-new-api-key-here');
    // ⚠️ 重要:請立即前往 OpenAI 平台撤銷舊的 API Key!
    $api_key = defined('OPENAI_API_KEY') ? OPENAI_API_KEY : '';

    // 如果沒有設定 API Key,返回錯誤
    if (empty($api_key)) {
        error_log('OpenAI API Key 未設定,請在 wp-config.php 中加入 define("OPENAI_API_KEY", "your-key");');
        wp_send_json_error('API Key 未設定');
        return;
    }
    $response = wp_remote_post('https://api.openai.com/v1/chat/completions', array(
        'headers' => array(
            'Content-Type' => 'application/json',
            'Authorization' => 'Bearer ' . $api_key,
        ),
        'body' => json_encode(array(
            'model' => 'gpt-3.5-turbo',
            'messages' => array(
                array('role' => 'user', 'content' => $question)
            ),
            'max_tokens' => 500,
        )),
    ));

    if (is_wp_error($response)) {
        error_log('API request failed: ' . $response->get_error_message());
        wp_send_json_error('API request failed');
    } else {
        $body = wp_remote_retrieve_body($response);
        $data = json_decode($body, true);

        if (isset($data['choices'][0]['message']['content'])) {
            $answer = $data['choices'][0]['message']['content'];

            // 將答案存儲到數據庫中
            $wpdb->insert(
                $table_name,
                array(
                    'question' => $question,
                    'answer' => $answer
                ),
                array(
                    '%s',
                    '%s'
                )
            );

            wp_send_json_success($answer);
        } else {
            error_log('Invalid API response: ' . print_r($body, true));
            wp_send_json_error('Invalid API response');
        }
    }
}
add_action('wp_ajax_gpt_handle_request', 'gpt_handle_ajax_request');
add_action('wp_ajax_nopriv_gpt_handle_request', 'gpt_handle_ajax_request');

// ========== 模組 S:相關商品排除分類 ==========

/**
 * 【功能】單一商品頁載入前,掛上「排除 no-show 分類」的相關商品 filter。
 * 【觸發】woocommerce_before_single_product action。
 */
add_action( 'woocommerce_before_single_product', 'woodmart_related_products_exclude_init' );
function woodmart_related_products_exclude_init() {
    if( class_exists('WooCommerce') && defined('WOODMART_THEME_DIR') ) {
        add_filter( 'woocommerce_related_products', 'woodmart_exclude_category_from_related_products', 999, 3 );
        add_filter( 'woocommerce_output_related_products_args', 'woodmart_modify_related_products_args', 20, 1 );
    }
}

/**
 * 【功能】從相關商品列表中排除分類 slug='no-show' 的商品。
 *        使用 transient 快取 1 小時(key: woodmart_exclude_cat_*),並用 static $processing 防止無限遞迴。
 * 【觸發】woocommerce_related_products,priority 999。
 */
function woodmart_exclude_category_from_related_products( $related_posts, $product_id, $args ){
    // 定義要排除的分類 slug
    $exclude_categories = array('no-show');

    if( empty($exclude_categories) || empty($related_posts) ) {
        return $related_posts;
    }

    // 防止無限遞迴
    static $processing = false;
    if ($processing) {
        return $related_posts;
    }
    $processing = true;

    $exclude_ids = array();

    // 使用 transient 快取來避免重複查詢
    $cache_key = 'woodmart_exclude_cat_' . md5(implode(',', $exclude_categories));
    $cached_ids = get_transient($cache_key);

    if ($cached_ids === false) {
        // 通過分類 slug 獲取商品 ID(限制數量避免記憶體問題)
        foreach($exclude_categories as $category_slug) {
            $category = get_term_by('slug', $category_slug, 'product_cat');
            if($category) {
                $category_products = wc_get_products( array(
                    'status' => 'publish',
                    'limit' => 100, // 限制數量,避免查詢過多商品
                    'category' => array($category_slug),
                    'return' => 'ids',
                ));
                $exclude_ids = array_merge($exclude_ids, $category_products);
            }
        }
        $exclude_ids = array_unique($exclude_ids);

        // 快取 1 小時
        set_transient($cache_key, $exclude_ids, HOUR_IN_SECONDS);
    } else {
        $exclude_ids = $cached_ids;
    }

    // 從相關商品列表中排除這些商品
    $filtered_related_posts = array_diff($related_posts, $exclude_ids);

    // 移除了重新獲取相關商品的邏輯,避免無限遞迴
    // 如果結果太少,讓 woodmart_modify_related_products_args 在一開始就增加獲取數量

    $processing = false;
    return $filtered_related_posts;
}

/**
 * 【功能】把相關商品的 posts_per_page 提升到至少 8,補償排除後可能不足的數量。
 * 【觸發】woocommerce_output_related_products_args,priority 20。
 */
function woodmart_modify_related_products_args( $args ) {
    // 確保有足夠的相關商品顯示
    if( isset($args['posts_per_page']) && $args['posts_per_page'] < 8 ) {
        $args['posts_per_page'] = 8; // 增加獲取數量以補償被排除的商品
    }
    return $args;
}

/**
 * ========================================
 * 自定義超商取貨運送方式
 * ========================================
 * 目標:創建獨立的超商取貨運送方式,不依賴舊版外掛
 * 配合新版 newebpay-payment 外掛使用
 */

/**
 * 超商取貨運送方式類別
 */
// ========== 模組 T:自訂超商取貨運送方式類別 ==========

/**
 * 【功能】自訂超商取貨運送方式(取代舊版藍新外掛的運送方式)。
 *        - id = 'newebpay_cvscom'(保留沿用,配合既有 hook 邏輯)
 *        - 支援 shipping zones、instance settings
 *        - 設定欄位:方法標題、運費、滿額免運門檻
 *        - calculate_shipping() 內處理免運券與滿額免運
 * 【關聯】add_custom_cvscom_shipping_method() 將其註冊到 WC。
 */
if (!class_exists('WC_Custom_CVSCOM_Shipping_Method')) {
    class WC_Custom_CVSCOM_Shipping_Method extends WC_Shipping_Method {

        /**
         * 建構子
         */
        public function __construct($instance_id = 0) {
            $this->id                 = 'newebpay_cvscom'; // 使用相同的 ID 以配合現有邏輯
            $this->instance_id        = absint($instance_id);
            $this->method_title       = __('超商取貨', 'woocommerce');
            $this->method_description = __('藍新金流超商取貨運送方式(配合新版外掛)', 'woocommerce');
            $this->supports           = array(
                'shipping-zones',
                'instance-settings',
                'instance-settings-modal',
            );

            $this->init();
        }

        /**
         * 初始化設定
         */
        function init() {
            // Load the settings API
            $this->init_form_fields();
            $this->init_settings();

            // Define user set variables
            $this->title      = $this->get_option('title');
            $this->cost       = $this->get_option('cost');
            $this->free_amount = $this->get_option('free_amount');

            // Save settings in admin
            add_action('woocommerce_update_options_shipping_' . $this->id, array($this, 'process_admin_options'));
        }

        /**
         * 設定表單欄位
         */
        function init_form_fields() {
            $this->instance_form_fields = array(
                'title' => array(
                    'title'       => __('方法標題', 'woocommerce'),
                    'type'        => 'text',
                    'description' => __('這將顯示在結帳頁面上', 'woocommerce'),
                    'default'     => __('超商取貨', 'woocommerce'),
                    'desc_tip'    => true,
                ),
                'cost' => array(
                    'title'       => __('運費', 'woocommerce'),
                    'type'        => 'number',
                    'description' => __('輸入固定運費金額', 'woocommerce'),
                    'default'     => '60',
                    'desc_tip'    => true,
                    'custom_attributes' => array(
                        'step' => '1',
                        'min'  => '0',
                    ),
                ),
                'free_amount' => array(
                    'title'       => __('滿額免運', 'woocommerce'),
                    'type'        => 'number',
                    'description' => __('購物車金額達到此金額時免運費(設定 0 關閉此功能)', 'woocommerce'),
                    'default'     => '0',
                    'desc_tip'    => true,
                    'custom_attributes' => array(
                        'step' => '1',
                        'min'  => '0',
                    ),
                ),
            );
        }

        /**
         * 計算運費
         */
        public function calculate_shipping($package = array()) {
            $cart_total = WC()->cart->get_cart_contents_total();
            $shipping_cost = $this->cost;

            // 滿額免運判斷
            if ($this->free_amount > 0 && $cart_total >= $this->free_amount) {
                $shipping_cost = 0;
            }

            // 檢查是否有免運費優惠券
            $coupons = WC()->cart->get_coupons();
            foreach ($coupons as $coupon) {
                if ($coupon->get_free_shipping()) {
                    $shipping_cost = 0;
                    break;
                }
            }

            $this->add_rate(array(
                'id'      => $this->get_rate_id(),
                'label'   => $this->title,
                'cost'    => $shipping_cost,
                'package' => $package,
            ));
        }
    }
}

/**
 * 註冊超商取貨運送方式
 */
/**
 * 【功能】WC 啟動運送方式時,確認 WC_Custom_CVSCOM_Shipping_Method 類別已存在。
 * 【觸發】woocommerce_shipping_init action。
 */
add_action('woocommerce_shipping_init', 'custom_cvscom_shipping_init');
function custom_cvscom_shipping_init() {
    if (!class_exists('WC_Custom_CVSCOM_Shipping_Method')) {
        return;
    }
}

/**
 * 將超商取貨運送方式加入 WooCommerce
 */
/**
 * 【功能】把 WC_Custom_CVSCOM_Shipping_Method 註冊為 WC 可用的運送方式(id: newebpay_cvscom)。
 * 【觸發】woocommerce_shipping_methods filter。
 */
add_filter('woocommerce_shipping_methods', 'add_custom_cvscom_shipping_method');
function add_custom_cvscom_shipping_method($methods) {
    $methods['newebpay_cvscom'] = 'WC_Custom_CVSCOM_Shipping_Method';
    return $methods;
}

/**
 * ========================================
 * 藍新金流 x 運送方式整合
 * ========================================
 * 目標:根據運送方式智能控制超商取貨相關選項
 * 方案:前端 + 後端雙重驗證
 */

/**
 * 前端:JavaScript 控制顯示邏輯
 */
// ========== 模組 U:藍新 × 運送方式整合 JS(最複雜,~330 行) ==========

/**
 * 【功能】★★★ 結帳頁注入大段 jQuery,依運送方式動態控制付款選項:
 *
 *  情境 A(宅配 / 6H 配送):
 *    - 隱藏藍新「nwp_selected_payments」下拉中的 CVSCOMPayed/CVSCOMNotPayed 選項
 *    - 完全隱藏 #CVSCOMNotPayed checkbox 並清空 value
 *    - 顯示 LINE Pay 付款選項
 *
 *  情境 B(超商取貨):
 *    - 顯示所有藍新付款選項(含 CVSCOM)
 *    - #CVSCOMNotPayed checkbox 視覺隱藏(absolute -9999px)但保留 DOM
 *    - 根據選擇的付款方式自動切換 checkbox:
 *        CVSCOMPayed(取貨付款)→ unchecked(CVSCOM=2)
 *        其他(信用卡等)→ checked(CVSCOM=1,超商取貨不付款)
 *    - 隱藏 LINE Pay
 *    - 提交前 (checkout_place_order) 阻擋 LINE Pay+超商組合並再次補正 checkbox
 *
 *  並監聽 updated_checkout、change shipping_method、change payment_method、update_checkout
 *  確保 AJAX 重新渲染後 UI 維持正確狀態,updateCheckoutButtonText() 同步結帳按鈕文字。
 *
 * 【觸發】wp_footer,僅在 is_checkout() 時注入。
 * 【除錯】內含大量 console.log,正式環境保留方便排查超商取貨問題。
 */
add_action('wp_footer', 'newebpay_shipping_payment_integration');
function newebpay_shipping_payment_integration() {
    if (!is_checkout()) return;
    ?>
    <script>
    jQuery(function($){
        var newebpay_cvscom = 'newebpay_cvscom'; // 超商取貨運送方式 ID

        /**
         * 檢查是否選擇超商取貨運送方式
         */
        function isStorePickingShipping() {
            var selectedShipping = $('input[name^="shipping_method"]:checked').val();

            // 修正:如果沒有選中的運送方式,檢查是否只有超商取貨可用
            if (!selectedShipping) {
                var $shippingOptions = $('input[name^="shipping_method"]');
                if ($shippingOptions.length === 1) {
                    selectedShipping = $shippingOptions.val();
                    console.log('🔍 只有一個運送方式:' + selectedShipping);
                }
            }

            // 檢查是否包含 newebpay_cvscom(因為實際值可能是 newebpay_cvscom:20)
            var isStorePicking = selectedShipping && selectedShipping.indexOf(newebpay_cvscom) !== -1;
            console.log('🔍 檢查運送方式:' + selectedShipping + ' → 是否超商取貨:' + isStorePicking);
            return isStorePicking;
        }

        /**
         * 主控制函數:根據運送方式控制付款選項
         */
        function controlPaymentOptions() {
            if (isStorePickingShipping()) {
                // 情況 B:選擇超商取貨運送方式
                handleStorePickingMode();
            } else {
                // 情況 A:選擇宅配/6H配送
                handleNormalShippingMode();
            }
        }

        /**
         * 情況 A:宅配/6H配送
         * - 隱藏「超商取貨付款」下拉選項
         * - 隱藏「超商取貨不付款」checkbox
         * - 顯示 LINE Pay 付款選項
         */
        function handleNormalShippingMode() {
            var $select = $('select[name="nwp_selected_payments"]');
            var $checkbox = $('#CVSCOMNotPayed');
            var $checkboxLabel = $('label[for="CVSCOMNotPayed"]');
            var $linepay = $('.payment_method_linepay, #payment_method_linepay');

            if ($select.length > 0) {
                // 隱藏「超商取貨付款」選項
                $select.find('option[value="CVSCOMPayed"]').hide();
                $select.find('option[value="CVSCOMNotPayed"]').hide(); // 也隱藏這個選項

                // 如果當前選中的是超商取貨相關選項,切換到信用卡
                var currentVal = $select.val();
                if (currentVal === 'CVSCOMPayed' || currentVal === 'CVSCOMNotPayed') {
                    // 優先選擇信用卡,如果沒有則選第一個可見選項
                    if ($select.find('option[value="Credit"]').length > 0) {
                        $select.val('Credit');
                    } else {
                        var firstVisibleOption = $select.find('option:visible:first').val();
                        $select.val(firstVisibleOption);
                    }
                    $select.trigger('change');
                }
            }

            // 完全隱藏並取消勾選 checkbox(使用 .hide() 是安全的,因為我們不需要它的值)
            $checkbox.hide();
            $checkboxLabel.hide();
            $checkbox.prop('checked', false);
            $checkbox.val(''); // 清空 value

            // 顯示 LINE Pay 付款選項
            if ($linepay.length > 0) {
                $linepay.show();
                console.log('  ✅ 顯示 LINE Pay 付款選項');
            }

            // 🔥 修正:確保按鈕文字正確
            setTimeout(function() {
                updateCheckoutButtonText();
            }, 50);

            console.log('🚚 宅配/6H模式:已隱藏超商取貨選項');
        }

        /**
         * 情況 B:超商取貨運送方式
         * - 顯示所有付款選項
         * - 視覺隱藏 checkbox(但保留功能)
         * - 根據下拉選擇自動控制 checkbox
         * - 隱藏 LINE Pay 付款選項
         */
        function handleStorePickingMode() {
            var $select = $('select[name="nwp_selected_payments"]');
            var $checkbox = $('#CVSCOMNotPayed');
            var $checkboxLabel = $('label[for="CVSCOMNotPayed"]');
            var $linepay = $('.payment_method_linepay, #payment_method_linepay');

            console.log('🏪 進入超商取貨模式');

            if ($select.length > 0) {
                // 顯示所有選項(包括超商取貨付款)
                $select.find('option').each(function() {
                    $(this).show();
                    console.log('  ✅ 顯示選項:' + $(this).val() + ' - ' + $(this).text());
                });

                // 確保下拉選單本身是可見的
                $select.show();
            } else {
                console.log('  ⚠️ 找不到付款方式下拉選單');
            }

            if ($checkbox.length > 0) {
                // ✨ 視覺隱藏但保留功能(不使用 display:none)
                $checkbox.show(); // 確保不是 display:none
                $checkbox.css({
                    'position': 'absolute',
                    'left': '-9999px',
                    'opacity': '0',
                    'pointer-events': 'none'
                });
                $checkboxLabel.css({
                    'position': 'absolute',
                    'left': '-9999px',
                    'opacity': '0',
                    'pointer-events': 'none'
                });
                console.log('  ✅ Checkbox 已視覺隱藏(功能正常)');

                // 根據當前選擇的付款方式,自動設定 checkbox
                autoToggleCheckbox();
            } else {
                console.log('  ⚠️ 找不到 checkbox');
            }

            // 隱藏 LINE Pay 付款選項
            if ($linepay.length > 0) {
                $linepay.hide();
                // 如果 LINE Pay 被選中,切換到其他付款方式
                if ($linepay.find('input[type="radio"]').is(':checked')) {
                    // 優先選擇藍新金流,如果沒有則選第一個可見的付款方式
                    var $newebpay = $('.payment_method_newebpay, #payment_method_newebpay');
                    if ($newebpay.length > 0) {
                        $newebpay.find('input[type="radio"]').prop('checked', true).trigger('change');
                    } else {
                        $('.payment_method:visible:first').find('input[type="radio"]').prop('checked', true).trigger('change');
                    }

                    // 🔥 修正:更新結帳按鈕文字
                    updateCheckoutButtonText();
                }
                console.log('  🚫 已隱藏 LINE Pay 付款選項');
            }

            console.log('🏪 超商取貨模式設定完成');
        }

        /**
         * 更新結帳按鈕文字
         * - 根據當前選中的付款方式,更新按鈕文字
         */
        function updateCheckoutButtonText() {
            var $checkedPayment = $('input[name="payment_method"]:checked');
            var $placeOrderBtn = $('#place_order');

            if ($checkedPayment.length > 0 && $placeOrderBtn.length > 0) {
                var buttonText = $checkedPayment.data('order_button_text');

                if (buttonText) {
                    $placeOrderBtn.text(buttonText);
                    console.log('  🔄 更新結帳按鈕文字為:' + buttonText);
                } else {
                    // 如果沒有自訂文字,使用預設值
                    var defaultText = $placeOrderBtn.data('value');
                    if (defaultText) {
                        $placeOrderBtn.text(defaultText);
                        console.log('  🔄 恢復預設結帳按鈕文字:' + defaultText);
                    }
                }
            }
        }

        /**
         * 自動控制 checkbox 邏輯
         * - 選擇「超商取貨付款」→ 取消勾選(CVSCOM=2)
         * - 選擇其他付款方式 → 自動勾選(CVSCOM=1)
         */
        function autoToggleCheckbox() {
            var $select = $('select[name="nwp_selected_payments"]');
            var $checkbox = $('#CVSCOMNotPayed');

            if ($checkbox.length === 0) {
                console.log('⚠️ checkbox 不存在');
                return;
            }

            var selectedPayment = $select.val();

            // 根據付款方式設置 checkbox
            if (selectedPayment === 'CVSCOMPayed') {
                // 超商取貨付款:CVSCOM=2 → 不勾選
                $checkbox.prop('checked', false);
                console.log('💳 超商取貨付款:CVSCOM=2,checkbox 取消勾選');
            } else {
                // 其他付款方式:CVSCOM=1 → 勾選
                $checkbox.prop('checked', true);
                console.log('💳 ' + selectedPayment + ':CVSCOM=1,checkbox 已勾選');
            }

            console.log('🔍 Checkbox 狀態:checked=' + $checkbox.prop('checked') + ', value=' + $checkbox.attr('value'));
        }

        /**
         * 初始化
         */
        setTimeout(function(){
            controlPaymentOptions();
        }, 100);

        /**
         * 監聽運送方式變更
         */
        $(document.body).on('change', 'input[name^="shipping_method"]', function() {
            controlPaymentOptions();
        });

        /**
         * 監聽 WooCommerce 更新結帳
         */
        $(document.body).on('updated_checkout', function() {
            setTimeout(function() {
                controlPaymentOptions();
            }, 100);
        });

        /**
         * 監聽付款方式下拉變更(僅在超商取貨模式)
         */
        $(document.body).on('change', 'select[name="nwp_selected_payments"]', function() {
            if (isStorePickingShipping()) {
                autoToggleCheckbox();
            }
        });

        /**
         * 🔥 修正:監聽付款方式改變,更新結帳按鈕文字
         */
        $(document.body).on('change', 'input[name="payment_method"]', function() {
            setTimeout(function() {
                updateCheckoutButtonText();
            }, 50);
        });

        /**
         * 🔥 關鍵:在表單提交前強制確保值被正確設置
         * 注意:WooCommerce 在 document.body 觸發此事件,不是 form 本身
         */
        $(document.body).on('checkout_place_order', function() {
            var selectedShipping = $('input[name^="shipping_method"]:checked').val();
            var selectedPayment = $('input[name="payment_method"]:checked').val();

            console.log('🚀 表單提交前檢查');
            console.log('  運送方式:' + selectedShipping);
            console.log('  付款方式:' + selectedPayment);

            // 🚫 阻止 LINE Pay + 超商取貨的組合
            if (isStorePickingShipping() && selectedPayment === 'linepay') {
                alert('⚠️ LINE Pay 不支援超商取貨,請選擇其他付款方式或改為宅配運送。');
                console.log('  ❌ 阻止提交:LINE Pay 不支援超商取貨');
                return false; // 阻止表單提交
            }

            if (isStorePickingShipping()) {
                var $checkbox = $('#CVSCOMNotPayed');
                var $select = $('select[name="nwp_selected_payments"]');
                var selectedNewebpayMethod = $select.val();

                console.log('  藍新付款方式:' + selectedNewebpayMethod);

                // 根據付款方式設置 checkbox
                if (selectedNewebpayMethod === 'CVSCOMPayed') {
                    // CVSCOM=2:超商取貨付款 → 不勾選
                    if ($checkbox.length > 0) {
                        $checkbox.prop('checked', false);
                    }
                    console.log('  ✅ CVSCOM=2(超商取貨付款),checkbox 不勾選');
                } else {
                    // CVSCOM=1:超商取貨不付款 → 勾選
                    if ($checkbox.length > 0) {
                        $checkbox.prop('checked', true);
                    }
                    console.log('  ✅ CVSCOM=1(超商取貨不付款),checkbox 已勾選');
                }

                console.log('  最終 checkbox 狀態:checked=' + ($checkbox.length > 0 ? $checkbox.prop('checked') : 'N/A'));
            }

            // 允許表單提交
            return true;
        });

        /**
         * 🔥 超級關鍵:攔截 AJAX 數據,手動添加 checkbox 值
         */
        $(document.body).on('checkout_error', function() {
            console.log('⚠️ 結帳發生錯誤');
        });

        // 在 WooCommerce 更新結帳前,確保 checkbox 值正確
        $(document.body).on('update_checkout', function() {
            if (isStorePickingShipping()) {
                var $checkbox = $('#CVSCOMNotPayed');
                var $select = $('select[name="nwp_selected_payments"]');
                var selectedPayment = $select.val();

                if ($checkbox.length > 0) {
                    if (selectedPayment === 'CVSCOMPayed') {
                        $checkbox.prop('checked', false);
                    } else {
                        $checkbox.prop('checked', true);
                    }
                    console.log('🔄 update_checkout:checkbox 已更新,checked=' + $checkbox.prop('checked'));
                }
            }
        });
    });
    </script>
    <?php
}

/**
 * ========================================
 * 阻止 LINE Pay + 超商取貨的組合(後端驗證)
 * ========================================
 */
// ========== 模組 V:後端阻擋 LINE Pay + 超商取貨組合 ==========

/**
 * 【功能】後端再次驗證:若付款方式 = linepay 且運送方式含 newebpay_cvscom,
 *        加入結帳錯誤「LINE Pay 不支援超商取貨」並寫 error_log。
 *        前端 JS 已先攔(模組 U),這裡是雙重保險。
 * 【觸發】woocommerce_after_checkout_validation,priority 10。
 */
add_action('woocommerce_after_checkout_validation', 'prevent_linepay_with_store_pickup', 10, 2);
function prevent_linepay_with_store_pickup($data, $errors) {
    // 檢查是否選擇了 LINE Pay
    if (isset($data['payment_method']) && $data['payment_method'] === 'linepay') {
        // 檢查是否選擇了超商取貨
        if (isset($data['shipping_method']) && is_array($data['shipping_method'])) {
            foreach ($data['shipping_method'] as $method) {
                if (strpos($method, 'newebpay_cvscom') !== false) {
                    $errors->add('payment_shipping_mismatch',
                        __('LINE Pay 不支援超商取貨運送方式,請選擇其他付款方式或改為宅配運送。', 'woocommerce'));
                    error_log('[Checkout Validation] 阻止 LINE Pay + 超商取貨組合');
                    return;
                }
            }
        }
    }
}

/**
 * 🎯 簡化策略:只處理非超商取貨的情況,超商取貨讓外掛原生邏輯處理
 */
// ========== 模組 W:藍新付款參數補正(receipt 頁攔截) ==========

/**
 * 【功能】當付款方式 = newebpay 但運送方式「不是」超商取貨時,清空所有 CVSCOM 相關 POST/data 欄位,
 *        並把 nwp_selected_payments 從 'CVSCOMPayed' 強制改為 'Credit',避免外掛誤帶超商參數。
 * 【觸發】woocommerce_checkout_posted_data filter,priority 5(早期介入)。
 */
add_filter('woocommerce_checkout_posted_data', 'newebpay_handle_non_cvscom_shipping', 5);
function newebpay_handle_non_cvscom_shipping($data) {
    // 只在使用藍新金流時執行
    if (!isset($data['payment_method']) || $data['payment_method'] !== 'newebpay') {
        return $data;
    }

    $chosen_shipping_methods = WC()->session->get('chosen_shipping_methods');
    if (empty($chosen_shipping_methods)) {
        return $data;
    }

    $chosen_shipping_method = $chosen_shipping_methods[0];

    // 使用 strpos 支持 instance ID(如 newebpay_cvscom:20)
    $is_cvscom_shipping = (strpos($chosen_shipping_method, 'newebpay_cvscom') !== false);

    // 只處理「非超商取貨」的情況
    if (!$is_cvscom_shipping) {
        // 確保 cvscom_not_payed 為空,避免 Undefined key 錯誤
        if (!isset($_POST['cvscom_not_payed'])) {
            $_POST['cvscom_not_payed'] = '';
        }
        $data['cvscom_not_payed'] = '';

        // 如果錯誤地選了超商取貨付款,改為信用卡
        if (isset($_POST['nwp_selected_payments']) && $_POST['nwp_selected_payments'] === 'CVSCOMPayed') {
            $_POST['nwp_selected_payments'] = 'Credit';
            $data['nwp_selected_payments'] = 'Credit';
        }
    }

    return $data;
}

/**
 * 🔑 在藍新生成付款表單前清理/補正參數
 * woocommerce_receipt_newebpay 在外掛 receipt_page()(priority 10)之前執行(priority 0)
 * 這是生成藍新加密參數前最後的攔截機會
 */
/**
 * 【功能】★★ 在藍新外掛產生加密表單前最後攔截,依運送方式補正訂單 meta:
 *        - 非超商運送:刪除 _CVSCOMNotPayed、把 _nwpSelectedPayment 從 CVSCOMPayed/Not 改為 Credit
 *        - 超商運送 + CVSCOMPayed(取貨付款)→ _CVSCOMNotPayed = 0(CVSCOM=2)
 *        - 超商運送 + 其他(線上付款)→ _CVSCOMNotPayed = 1(CVSCOM=1,超商不付款)
 * 【觸發】woocommerce_receipt_newebpay,priority 0(在外掛 receipt_page 之前)。
 * 【關鍵】這是 JS 失靈時的最後一道補正防線。
 */
add_action('woocommerce_receipt_newebpay', 'newebpay_intercept_before_payment_page', 0);
function newebpay_intercept_before_payment_page($order_id) {
    $order = wc_get_order($order_id);
    if (!$order) return;

    // 檢查運送方式
    $shipping_methods = $order->get_shipping_methods();
    $is_cvscom_shipping = false;

    foreach ($shipping_methods as $shipping_method) {
        $method_id = $shipping_method->get_method_id();
        if ($method_id === 'newebpay_cvscom' || strpos($method_id, 'cvscom') !== false) {
            $is_cvscom_shipping = true;
            break;
        }
    }

    // 🎯 核心邏輯:如果不是超商取貨運送,清除所有 CVSCOM 相關參數
    if (!$is_cvscom_shipping) {
        $selected_payment = $order->get_meta('_nwpSelectedPayment', true);

        // 清除藍新外掛會讀取的 meta 資料
        $order->delete_meta_data('_CVSCOMNotPayed');
        $order->update_meta_data('_CVSCOMNotPayed', 0);

        // 如果選擇了 CVSCOMPayed,強制改為 Credit
        if ($selected_payment === 'CVSCOMPayed' || $selected_payment === 'CVSCOMNotPayed') {
            $order->update_meta_data('_nwpSelectedPayment', 'Credit');
        }

        $order->save();
    }
    // 如果是超商取貨運送,確保正確設定 CVSCOM 參數
    else {
        $selected_payment = $order->get_meta('_nwpSelectedPayment', true);

        if ($selected_payment === 'CVSCOMPayed') {
            // 線上付款取貨 → CVSCOM=2,_CVSCOMNotPayed 必須是 0
            $order->update_meta_data('_CVSCOMNotPayed', 0);
            $order->save();
        } else {
            // 超商取貨付款(到店付款)→ CVSCOM=1,_CVSCOMNotPayed 必須是 1
            // 不管 JS 是否正確設定 checkbox,後端強制補正
            $current_flag = $order->get_meta('_CVSCOMNotPayed', true);
            if ($current_flag != '1') {
                $order->update_meta_data('_CVSCOMNotPayed', 1);
                $order->save();
                error_log('[CVSCOM Fix] 訂單 #' . $order->get_id() . ' 補正:_CVSCOMNotPayed 0→1(付款:' . $selected_payment . ')');
            }
        }
    }
}

/**
 * 🔑🔑🔑 終極攔截:直接移除外掛的超商取貨付款設定(暫時性)
 * 這個方法會在生成藍新參數時,暫時關閉超商取貨付款選項
 */
// ========== 模組 X:動態關閉藍新外掛超商付款設定 ==========

/**
 * 【功能】★★ 動態過濾藍新外掛的 settings option:
 *        - 後台(is_admin)完全不攔截,讓設定能正常儲存
 *        - 只在前端 order-pay 或 checkout 頁面攔截
 *        - 若當前訂單/session 非超商運送 → 暫時關閉外掛的
 *          NwpPaymentMethodCVSCOMPayed / NwpPaymentMethodCVSCOMNotPayed 設定
 * 【觸發】option_woocommerce_newebpay_settings filter,priority 9999(最後攔)。
 * 【取得訂單來源】依序嘗試:order-pay query var → POST['order_id'] → session 'order_awaiting_payment'。
 * 【特殊邏輯】結帳頁無 chosen_shipping_methods 時,掃 packages 判斷是否「只有」超商取貨。
 */
add_filter('option_woocommerce_newebpay_settings', 'newebpay_filter_cvscom_settings', 9999);
function newebpay_filter_cvscom_settings($settings) {
    // 🔥 關鍵修正:後台完全不執行攔截,讓設定可以正常儲存
    // 只在前端結帳頁面或訂單付款頁面執行攔截
    if (is_admin()) {
        return $settings; // 後台任何情況都不攔截
    }

    // 只在付款頁面或結帳頁面執行攔截
    if (!is_wc_endpoint_url('order-pay') && !is_checkout()) {
        return $settings;
    }

    // 獲取當前訂單
    $order = null;
    $order_id = 0;

    // 方法 1:從 order-pay 頁面獲取
    global $wp;
    if (isset($wp->query_vars['order-pay'])) {
        $order_id = absint($wp->query_vars['order-pay']);
        $order = wc_get_order($order_id);
    }

    // 方法 2:從 POST 獲取(結帳時)
    if (!$order && isset($_POST['order_id'])) {
        $order_id = absint($_POST['order_id']);
        $order = wc_get_order($order_id);
    }

    // 方法 3:從 session 獲取最近的訂單(最後手段)
    if (!$order && WC()->session) {
        $order_id = WC()->session->get('order_awaiting_payment');
        if ($order_id) {
            $order = wc_get_order($order_id);
        }
    }

    // 判斷運送方式
    $is_cvscom_shipping = false;
    $method_id = '';

    if ($order && $order->get_payment_method() === 'newebpay') {
        // 從訂單中檢查運送方式
        $shipping_methods = $order->get_shipping_methods();

        foreach ($shipping_methods as $shipping_method) {
            $method_id = $shipping_method->get_method_id();
            if ($method_id === 'newebpay_cvscom' || strpos($method_id, 'cvscom') !== false) {
                $is_cvscom_shipping = true;
                break;
            }
        }
    } elseif (is_checkout() && WC()->session) {
        // 在結帳頁面沒有訂單時,從 session 獲取選擇的運送方式
        $chosen_shipping_methods = WC()->session->get('chosen_shipping_methods');
        if (!empty($chosen_shipping_methods)) {
            $method_id = $chosen_shipping_methods[0];
            $is_cvscom_shipping = (strpos($method_id, 'newebpay_cvscom') !== false);
        } else {
            // 修正:如果 session 中沒有選擇的運送方式,檢查可用的運送方式
            // 如果只有超商取貨可用,應該視為選擇了超商取貨
            $packages = WC()->shipping()->get_packages();
            if (!empty($packages)) {
                $package = $packages[0];
                $available_methods = WC()->shipping()->calculate_shipping_for_package($package);

                if (!empty($available_methods['rates'])) {
                    $all_rates = $available_methods['rates'];
                    $cvscom_count = 0;
                    $total_count = count($all_rates);

                    foreach ($all_rates as $rate) {
                        if (strpos($rate->id, 'newebpay_cvscom') !== false) {
                            $cvscom_count++;
                        }
                    }

                    // 如果所有可用的運送方式都是超商取貨,視為選擇了超商取貨
                    if ($cvscom_count > 0 && $cvscom_count === $total_count) {
                        $is_cvscom_shipping = true;
                        $method_id = 'newebpay_cvscom';
                    }
                }
            }
        }
    }

    // 🎯 如果不是超商取貨運送,暫時關閉外掛的超商取貨付款設定
    if (!$is_cvscom_shipping && is_array($settings)) {
        $settings['NwpPaymentMethodCVSCOMPayed'] = 'no';
        $settings['NwpPaymentMethodCVSCOMNotPayed'] = 'no';
    }

    return $settings;
}

/**
 * ========================================
 * 修改藍新金流自動跳轉時間
 * ========================================
 * 將預設的 10 秒改為 3 秒
 */
// ========== 模組 Y:藍新自動跳轉時間(10s → 3s) ==========

/**
 * 【功能】在 order-pay 頁面額外注入 JS,3 秒後自動 submit 名為 'newebpay' 的表單,
 *        覆蓋藍新外掛預設 10 秒延遲,加快導向藍新付款頁的體驗。
 * 【觸發】wp_footer,僅在 is_wc_endpoint_url('order-pay') 時執行。
 */
add_action('wp_footer', 'newebpay_modify_auto_submit_time');
function newebpay_modify_auto_submit_time() {
    // 只在訂單支付頁面執行
    if (!is_wc_endpoint_url('order-pay')) {
        return;
    }
    ?>
    <script>
    jQuery(function($){
        // 覆蓋原有的自動提交,改為 3 秒
        setTimeout(function() {
            if (document.forms['newebpay']) {
                document.forms['newebpay'].submit();
            }
        }, 3000); // 3000 毫秒 = 3 秒
    });
    </script>
    <?php
}