效果图如下

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

  

WordPress产品分类添加,自动排序插件的更多相关文章

  1. 《React后台管理系统实战 :四》产品分类管理页:添加产品分类、修改(更新)产品分类

    一.静态页面 目录结构 F:\Test\react-demo\admin-client\src\pages\admin\category add-cate-form.jsx index.jsx ind ...

  2. sublime插件 cssComb实现css自动排序及格式化

    cssComb是一个实现css代码自动排序,当然顺便也实现了代码的格式化 安装: 首先需要打开sublime搜索安装csscomb插件(前提是已经安装了sublime的package control) ...

  3. 关于eclipse添加自动查找文件以及svn的插件

    1.添加自动查找当前文件位置的插件(如下图) 在百度搜索下载 OpenExplorer_1.5.0.v201108051313.jar,下载之后放入eclipse下面的plugin文件夹下面既可以 2 ...

  4. 九款让WordPress成为赚钱利器的广告插件

    Blog有了很不错的流量后,看到别人博客挂的广告挣$,是否也有挂广告的冲动,但是,修改wordpress模版去让人不厌其烦,布局.样式都的重新修改一下,为了不那么麻烦,笔者整理的几款wordpress ...

  5. 30+最佳Ajax jQuery的自动完成插件的例子

    在这篇文章中,我们将介绍35个jQuery AJAX的自动完成提示例子. jQuery 的自动完成功能,使用户快速找到并选择一定的价值.每个人都想要快速和即时搜索输入栏位,因为这个原因,许 流行的搜索 ...

  6. WordPress不同分类使用不同的文章模板

    倡萌昨天分享的 Custom Post Template 和 Single Post Template 可以让你自定义每篇文章的文章模板,今天来说说WordPress不同分类使用不同的文章模板. 方法 ...

  7. 转来的emacs配置文件,自动安装插件

    网上转来的emacs配置文件,便于自动安装插件,收藏起来 http://www.gogae.org/post-7/ EMACS是一个伪装成代码编辑器的操作系统. EMACS是一个非常强大的代码编辑器, ...

  8. MySql无限分类数据结构--预排序遍历树算法

    MySql无限分类数据结构--预排序遍历树算法 无限分类是我们开发中非常常见的应用,像论坛的的版块,CMS的类别,应用的地方特别多. 我们最常见最简单的方法就是在MySql里ID ,parentID, ...

  9. MixItUp:超炫!基于 CSS3 & jQuery 的过滤和排序插件

    MixItUp 是一款轻量,但功能强大的 jQuery 插件,提供了对分类和有序内容的美丽的动画过滤和排序功能.特别适合用于作品集网站,画廊,图片博客以及任何的分类或有序内容. 它是如何工作的? Mi ...

  10. Awesomplete - 零依赖的简单自动完成插件

    Awesomplete 是一款超轻量级的,可定制的,简单的自动完成插件,零依赖,使用现代化标准构建.你可以简单地添加 awesomplete 样式,让它自动处理(你仍然可以通过指定 HTML 属性配置 ...

随机推荐

  1. 【Hibernate】Re07 关系映射处理

    一.单向多对一关系映射处理 演示案例列举了员工与部门的关系,一个部门下具有多个员工,相反的一个员工只隶属于一个部门下面 Maven依赖坐标: <dependency> <groupI ...

  2. 【Redis】03 Redis 数据类型、相关补充、常用命令

    redis的数据类型 1,概述 使用Redis进行应用设计和开发的一个核心概念是数据类型. 与关系数据库不同,在Redis中不存在需要我们担心的表, 在使用Redis进行应用设计和开发时,我们首先应该 ...

  3. 使用 C# 和 ONNX 來玩转Phi-3 SLM

    LLM 席卷世界刷新 AI 的认知之后,由于 LLM 需要的硬件要求实在太高,很难在普通设备上运行,因此 SLM 逐漸受到重視,Phi-3 SLM 是由 Microsoft 所开发的模型,可以在你的电 ...

  4. 亲测可用的 Linux(Ubuntu18.04下)可运行的俄罗斯方块游戏的仿真环境—————————可用于强化学习算法的游戏模拟器环境

    俄罗斯方块模拟器(tetris 游戏),Python库地址: https://gitee.com/devilmaycry812839668/gym-tetris 在Python3.7环境下亲测可用: ...

  5. (续) python 中 ctypes 的使用尝试

    内容接前文: https://www.cnblogs.com/devilmaycry812839668/p/15032493.html ================================ ...

  6. Apache DolphinScheduler使用图关系解决核心链路告警问题,减轻任务运维负担!

    转载自程序员小陶 Apache DolphinScheduler 在使用过程中,肯定会有任务出现失败的情况,那么问题来了:调度任务的告警是需要人为配置的,在生产环境中,面对海量的任务,如何找到重要的任 ...

  7. BMC Genomics | 综合代谢组学和转录组学分析揭示了菊花黄酮和咖啡酰奎宁酸的生物合成机制

    杭白菊是一种流行的药用和食用植物,主要通过黄酮类和咖啡酰奎宁酸(CQAs)的存在发挥其生物活性.然而,菊花头状花序中黄酮和CQA生物合成的调控机制尚不清楚. 本研究采用高效液相色谱法测定了菊花头状花序 ...

  8. 在Debian上安装freeswitch

    在Debian上安装freeswitch 说明: 首次发表日期:2024-08-12 参考文档: https://medium.com/@jogikrunal9477/ultimate-guide-t ...

  9. 【全】CSS动画大全之按钮【a】

    效果预览 代码 <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> < ...

  10. programmers model

    Handler模式一直使用MSP,所以在handler模式下处理器会忽略SPSEL位:异常进入及返回机制会更新CONTROL寄存器. 在操作系统的环境中,推荐线程在Thread模式下运行使用PSP,内 ...