效果圖如下
目前這個預覽選單這個效果有點問題,但是不影響實際排序,有懂原始碼的朋友可以自行修改一下,
目錄結構
menu
-assets
menu.css
menu.js
menu.php
原始碼如下
menu.php檔案
<?php /** * Plugin Name: 選單整理 * Description: 將 WooCommerce 產品分類新增到現有選單中。 * Version: 1.2 * Author: 朵啦 * License: GPL2 */ // 防止直接訪問檔案 if (!defined('ABSPATH')) { exit; } // 註冊外掛設定頁面 add_action('admin_menu', 'cmo_add_admin_menu'); function cmo_add_admin_menu() { add_menu_page( '分類選單管理', // 頁面標題 '分類選單', // 選單標題 'manage_options', // 許可權 'cmo-settings', // 選單 slug 'cmo_settings_page', // 回撥函式 'dashicons-menu', // 圖示 60 // 位置 ); } // 引入 JS 和 CSS 檔案 add_action('admin_enqueue_scripts', 'cmo_enqueue_scripts'); function cmo_enqueue_scripts() { wp_enqueue_script('cmo-menu-js', plugin_dir_url(__FILE__) . 'assets/menu.js', ['jquery'], false, true); wp_enqueue_style('cmo-menu-css', plugin_dir_url(__FILE__) . 'assets/menu.css'); } // 使 ajaxurl 變數在前端 JavaScript 中可用 add_action('admin_enqueue_scripts', 'add_ajax_url'); function add_ajax_url() { wp_localize_script('cmo-menu-js', 'ajaxurl', admin_url('admin-ajax.php')); } // 設定頁面的顯示內容 function cmo_settings_page() { ?> <div class="wrap"> <h1>WooCommerce 分類選單管理</h1> <form method="post" action="options.php"> <?php settings_fields('cmo_settings_group'); function cmo_section_text() { echo '<p>選擇要新增到選單的產品分類</p>'; } do_settings_sections('cmo-settings'); ?> </form> <h2>選單操作</h2> <form method="post" action="" id="menu-action-form"> <label for="cmo_menu_selector">選擇選單:</label> <?php cmo_menu_selector(); ?> <button type="button" id="cmo_add_to_menu" class="button button-primary">新增分類到選定選單</button> <button type="button" id="cmo_backup_menu" class="button">備份當前選單</button> <button type="button" id="cmo_restore_menu" class="button">恢復備份選單</button> </form> <div id="menu-preview"> <h3>選單預覽</h3> <div id="preview-content"></div> </div> </div> <?php } // 註冊設定欄位 add_action('admin_init', 'cmo_settings_init'); function cmo_settings_init() { register_setting('cmo_settings_group', 'cmo_selected_categories'); add_settings_section( 'cmo_main_section', '選擇要新增到選單的產品分類', 'cmo_section_text', 'cmo-settings' ); add_settings_field( 'cmo_categories_field', '產品分類', 'cmo_categories_field_callback', 'cmo-settings', 'cmo_main_section' ); } // 分類選擇欄位回撥,遞迴展示分類 function cmo_categories_field_callback($parent = 0, $level = 0) { if ($parent == 0 || $level == 0) { // 只在最頂層展示全選按鈕 echo '<input type="checkbox" id="select-all"> 全選<br><div style="display: flex; flex-wrap: wrap;">'; } $categories = get_terms([ 'taxonomy' => 'product_cat', 'hide_empty' => false, 'parent' => $parent // 透過 parent 引數遞迴獲取子分類 ]); $selected_categories = get_option('cmo_selected_categories', []); if (!is_array($selected_categories)) { $selected_categories = []; } foreach ($categories as $category) { // 縮排效果,表示分類層級 $indent = str_repeat(' ', $level); echo '<div style="flex-basis: 100%; margin-left:' . ($level * 20) . 'px;">' . '<input type="checkbox" name="cmo_selected_categories[]" value="' . esc_attr($category->term_id) . '" ' . checked(in_array($category->term_id, $selected_categories), true, false) . '> ' . esc_html($category->name) . '</div>'; // 遞迴呼叫自己,展示子分類 cmo_categories_field_callback($category->term_id, $level + 1); } if ($parent == 0 && $level == 0) { // 結束頂層div echo '</div>'; } } // 生成分類選單選擇器 function cmo_menu_selector() { $menus = wp_get_nav_menus(); echo '<select name="cmo_selected_menu" id="cmo_menu_selector">'; foreach ($menus as $menu) { echo '<option value="' . esc_attr($menu->term_id) . '">' . esc_html($menu->name) . '</option>'; } echo '</select>'; } // 新增分類到選單的功能 add_action('wp_ajax_cmo_add_to_menu', 'cmo_add_categories_to_menu'); function cmo_add_categories_to_menu() { if (!isset($_POST['menu_id'])) { wp_send_json_error('選單ID未設定'); } $menu_id = intval($_POST['menu_id']); if (!isset($_POST['selected_categories']) || empty($_POST['selected_categories'])) { wp_send_json_error('未選擇任何分類'); } $selected_categories = $_POST['selected_categories']; // 建立一個陣列來儲存分類和選單項的 ID 關聯 $category_menu_items = []; // 迴圈處理選中的分類 foreach ($selected_categories as $category_id) { $category = get_term($category_id, 'product_cat'); // 獲取當前分類的父分類 ID $parent_id = $category->parent; // 如果父分類已存在選單項,則將其設定為子選單項 $parent_menu_item_id = isset($category_menu_items[$parent_id]) ? $category_menu_items[$parent_id] : 0; // 新增選單項,並儲存它的 ID $menu_item_id = wp_update_nav_menu_item($menu_id, 0, [ 'menu-item-title' => esc_html($category->name), 'menu-item-url' => get_term_link($category), 'menu-item-status' => 'publish', 'menu-item-parent-id' => $parent_menu_item_id, // 指定父選單項 ]); // 將當前分類的選單項 ID 儲存到陣列中,供子分類使用 $category_menu_items[$category_id] = $menu_item_id; } wp_send_json_success('分類已成功新增到選單'); } // 備份當前選單 add_action('wp_ajax_cmo_backup_menu', 'cmo_backup_menu'); function cmo_backup_menu() { if (!isset($_POST['menu_id'])) { wp_send_json_error('選單ID未設定'); } $menu_id = intval($_POST['menu_id']); $menu_items = wp_get_nav_menu_items($menu_id); if ($menu_items) { update_option('cmo_menu_backup_' . $menu_id, $menu_items); wp_send_json_success('選單已成功備份'); } wp_send_json_error('備份失敗'); } // 恢復備份選單 add_action('wp_ajax_cmo_restore_menu', 'cmo_restore_menu'); function cmo_restore_menu() { if (!isset($_POST['menu_id'])) { wp_send_json_error('選單ID未設定'); } $menu_id = intval($_POST['menu_id']); $backup = get_option('cmo_menu_backup_' . $menu_id); if ($backup) { foreach ($backup as $item) { wp_update_nav_menu_item($menu_id, 0, [ 'menu-item-title' => esc_html($item->title), 'menu-item-url' => $item->url, 'menu-item-status' => 'publish', ]); } wp_send_json_success('選單已成功恢復'); } wp_send_json_error('沒有備份可恢復'); } // 預覽選單內容 add_action('wp_ajax_cmo_preview_menu', 'cmo_preview_menu'); function cmo_preview_menu() { if (!isset($_POST['menu_id'])) { wp_send_json_error('選單ID未設定'); } $menu_id = intval($_POST['menu_id']); $menu_items = wp_get_nav_menu_items($menu_id); if (empty($menu_items)) { wp_send_json_error('該選單沒有內容'); } $html = '<ul class="menu-preview">'; foreach ($menu_items as $item) { // 根據選單項的 parent 判斷是否是子項 if ($item->menu_item_parent == 0) { $html .= '<li class="menu-item">' . esc_html($item->title); // 查詢子項 $html .= get_menu_child_items($menu_items, $item->ID); $html .= '</li>'; } } $html .= '</ul>'; wp_send_json_success($html); } // 獲取子選單項的遞迴函式 function get_menu_child_items($menu_items, $parent_id) { $child_items = ''; foreach ($menu_items as $item) { if ($item->menu_item_parent == $parent_id) { if ($child_items == '') { $child_items .= '<ul class="submenu">'; } $child_items .= '<li class="menu-item">' . esc_html($item->title); $child_items .= get_menu_child_items($menu_items, $item->ID); $child_items .= '</li>'; } } if ($child_items != '') { $child_items .= '</ul>'; } return $child_items; } ?>
menu.css檔案
/* 調整預覽框的高度和寬度 */ #menu-preview { margin-top: 20px; border: 1px solid #ddd; padding: 10px; background-color: #f9f9f9; width: 100%; /* 讓框的寬度適應容器 */ height: 400px; /* 設定高度為400px,具體可根據需要調整 */ overflow-y: auto; /* 讓框的內容可以滾動 */ box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1); /* 新增陰影效果 */ } /* 一級選單樣式 */ .menu-preview { display: flex; flex-direction: row; list-style: none; padding: 0; margin: 0; } .menu-item { position: relative; padding: 10px 20px; background-color: #f0f0f0; margin-right: 10px; cursor: default; border: 1px solid #ccc; /* 新增邊框 */ border-radius: 5px; /* 圓角效果 */ font-weight: bold; /* 讓文字加粗 */ transition: background-color 0.3s ease; /* 新增背景顏色的過渡效果 */ } /* 一級選單懸浮效果 */ .menu-item:hover { background-color: #e0e0e0; border-color: #b0b0b0; /* 懸浮時改變邊框顏色 */ } /* 子選單樣式 */ .submenu { display: none; position: absolute; top: 100%; left: 0; background-color: white; list-style: none; padding: 0; margin: 0; box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1); z-index: 10; /* 確保子選單在頂層顯示 */ opacity: 0; /* 初始透明度 */ visibility: hidden; /* 初始不可見 */ transition: opacity 0.3s ease, visibility 0.3s ease; /* 過渡效果 */ } /* 子選單項的樣式 */ .submenu .menu-item { padding: 10px; margin-right: 0; white-space: nowrap; background-color: #ffffff; border: 1px solid #ddd; /* 給子選單項新增邊框 */ border-radius: 3px; } /* 子選單項的懸浮效果 */ .submenu .menu-item:hover { background-color: #f0f0f0; } /* 一級選單懸浮時顯示子選單 */ .menu-item:hover .submenu { display: block; opacity: 1; /* 顯示時漸變透明度 */ visibility: visible; /* 顯示可見 */ z-index: 999; } /* 讓一級選單項和子選單保持距離 */ .menu-item:hover .submenu { margin-top: 5px; } /* 調整子選單的位置 */ .submenu { min-width: 200px; /* 給子選單設定最小寬度 */ z-index: 1000; } /* 滑鼠移開子選單後延遲消失 */ .menu-item { transition: background-color 0.3s ease; } /* 子選單在滑鼠移開後延遲消失 */ .menu-item:hover .submenu { transition: opacity 0.3s ease, visibility 0.3s ease; } .menu-item .submenu { transition-delay: 1.5s; /* 新增延遲消失效果 */ } /* 阻止點選行為,確保只是預覽 */ .menu-preview a { pointer-events: none; color: #333; text-decoration: none; cursor: default; }
menu.js
document.addEventListener('DOMContentLoaded', function() { // 禁用選單預覽的點選事件 const previewLinks = document.querySelectorAll('.menu-preview .menu-item'); previewLinks.forEach(function(link) { link.addEventListener('click', function(event) { event.preventDefault(); // 禁用預設的點選行為 }); }); // 處理選單懸停顯示子選單 const menuItems = document.querySelectorAll('.menu-item'); menuItems.forEach(function(menuItem) { let timer; // 定義延時計時器 menuItem.addEventListener('mouseenter', function() { clearTimeout(timer); // 清除離開時的計時器,確保子選單正常顯示 const submenu = this.querySelector('.submenu'); if (submenu) { submenu.style.display = 'block'; submenu.style.opacity = '1'; submenu.style.visibility = 'visible'; } }); menuItem.addEventListener('mouseleave', function() { const submenu = this.querySelector('.submenu'); if (submenu) { timer = setTimeout(function() { submenu.style.opacity = '0'; submenu.style.visibility = 'hidden'; }, 1500); // 滑鼠離開 1.5 秒後隱藏子選單 } }); }); // 全選功能 const selectAllCheckbox = document.getElementById('select-all'); if (selectAllCheckbox) { selectAllCheckbox.addEventListener('click', function () { const checkboxes = document.querySelectorAll('input[name="cmo_selected_categories[]"]'); checkboxes.forEach(checkbox => checkbox.checked = this.checked); console.log('全選按鈕已點選'); }); } // 按鈕點選事件 const addToMenuButton = document.getElementById('cmo_add_to_menu'); if (addToMenuButton) { addToMenuButton.addEventListener('click', function (event) { console.log('新增分類到選定選單按鈕已點選'); handleMenuAction('cmo_add_to_menu', '新增分類到選定選單', event); }); } const backupMenuButton = document.getElementById('cmo_backup_menu'); if (backupMenuButton) { backupMenuButton.addEventListener('click', function (event) { handleMenuAction('cmo_backup_menu', '備份當前選單', event); }); } const restoreMenuButton = document.getElementById('cmo_restore_menu'); if (restoreMenuButton) { restoreMenuButton.addEventListener('click', function (event) { handleMenuAction('cmo_restore_menu', '恢復備份選單', event); }); } // 預覽選單 const menuSelector = document.getElementById('cmo_menu_selector'); if (menuSelector) { menuSelector.addEventListener('change', function () { const menuId = this.value; loadMenuPreview(menuId); }); } }); // 處理按鈕點選的AJAX請求 function handleMenuAction(action, message, event) { const menuId = document.getElementById('cmo_menu_selector').value; console.log('處理選單:', menuId); const button = event.target; button.disabled = true; button.innerHTML = '處理中...'; // 獲取選中的分類 const selectedCategories = Array.from(document.querySelectorAll('input[name="cmo_selected_categories[]"]:checked')).map(input => input.value); if (selectedCategories.length === 0) { alert("未選擇任何分類"); button.disabled = false; button.innerHTML = message; console.log('未選擇分類'); return; } console.log('傳送的分類:', selectedCategories); // 傳送 AJAX 請求 jQuery.post(ajaxurl, { action: action, menu_id: menuId, selected_categories: selectedCategories // 傳遞選中的分類資料 }, function(response) { console.log('Response:', response); button.disabled = false; button.innerHTML = message; if (response.success) { alert(response.data); console.log('操作成功'); if (action === 'cmo_add_to_menu' || action === 'cmo_preview_menu') { loadMenuPreview(menuId); } } else { console.log('操作失敗:', response.data); alert('操作失敗: ' + response.data); } }); } // 載入選單預覽 function loadMenuPreview(menuId) { document.getElementById('preview-content').innerHTML = '載入中...'; jQuery.post(ajaxurl, { action: 'cmo_preview_menu', menu_id: menuId }, function (response) { if (response.success) { document.getElementById('preview-content').innerHTML = response.data; } else { document.getElementById('preview-content').innerHTML = '預覽載入失敗'; } }); }