WordPress产品分类添加,自动排序插件

news/2024/9/29 14:16:08

效果图如下

 

 

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

  

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/66160.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

【VMware VCF】使用 VCF Import Tool 将现有 vSphere 环境导入为 VI 域。rp

VCF Import Tool 工具使用两种方式来帮助客户将现有的 vSphere 或 vSphere + vSAN 环境转变为 VMware Cloud Foundation 环境,分别是转换(Convert)和导入(Import)。之前在这篇(使用 VCF Import Tool 将现有 vSphere 环境转换为管理域。)文章中演示了将现有 vSphere 环境…

SpringBoot+Docker +Nginx 部署前后端项目Hf

部署SpringBoot项目(通关版) 一、概述 使用 java -jar 命令直接部署项目的JAR包和使用Docker制作镜像进行部署是两种常见的部署方式。以下是对这两种方式的概述和简要的优劣势分析: 1.1、使用 java -jar 命令直接部署项目的JAR包 概述:通过 java -jar 直接部署项目的JAR包是…

在线性坐标系中绘制二次函数图象

本文记述了用 Matplotlib 在线性坐标系中绘制二次函数图象的例子。 代码主体内容如下: ...def main():fig, axs = plt.subplots(1, 3, figsize=(14,4.5)) #1axs[0] = configure_axes(axs[0], Quadratic Function\t\t\t + r$\Delta > 0$, 18, 18, 10, 2) #2x …

第一届“物天杯”球类赛事规则

一、 篮球赛制、赛程和规则 (一)赛制 男子五人制全场,女子三人制半场。以下赛制男子、女子组相同,根据参赛队伍数量进行赛制选择。 1. 参赛队伍数量为12支及以上 比赛共分两个阶段进行,第一阶段为小组循环赛,第二阶段为淘汰赛及排位赛。 (1)小组赛:参赛班级抽签分成四…

html5一些特性

1.添加Html5标识头 <!DOCTYPE html> 2.注释 <!-- --> 3.块元素 <h1> <p><ul><li><div> 4.内联元素 <a><b><em><img><span> 5.内联框架iframe <body><iframe width="450" height=&…

Lemon Beta 安装使用 保姆级教程

准备食材Lemon Beta(点击此处下载) Mingw-w64(点击此处下载)安装 1) 安装Lemon Beta 把Lemon Beta压缩包下载下来解压,注意 lemon.exe 要设置以管理员身份打开。如果想永久设置,可以右键 lemon.exe,依次点击 属性——兼容性 选项卡——勾选 以管理员身份运行此程序——确…

20241313刘鸣宇《计算机基础与程序设计》第一周学习总结

作业信息这个作业属于哪个课程 <班级的链接>(如2024-2025-1-计算机基础与程序设计)这个作业要求在哪里 <作业要求的链接>(如2024-2025-1计算机基础与程序设计第一周作业)这个作业的目标 <写上具体方面>作业正文 ... 本博客链接教材学习内容总结 第一章:信…

合天网络安全笔记-二-

合天网络安全笔记(二) P17:第15天:文件上传黑名单,白名单及数组绕过技巧 - 网络安全就业推荐 - BV1Zu411s79i 呃大家晚上好,我们先来测试一下呃,我麦的一个声音,大家能听到我声音的话,还还有声音,足够清楚的话,在讨论区这边扣个一,好的都应该都能听得到,然后的话还…