效果图如下
目前这个预览菜单这个效果有点问题,但是不影响实际排序,有懂源码的朋友可以自行修改一下,
目录结构
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 = '预览加载失败'; } }); }
没有回复内容