侧边栏壁纸
博主头像
blogger UID:1

  • 累计撰写 40 篇文章
  • 累计收到 2 条评论

高效管理 WordPress 文章分类:批量操作插件(饺子优化+美化)

blogger UID:1
2026-5-15 0 评论 1 阅读

效果图如下

高效管理 WordPress 文章分类:批量操作插件开发与优化实战
在 WordPress 站点运营过程中,文章分类管理是内容维护的核心环节之一。尤其是当站点文章量较大时,逐个修改文章分类不仅效率低下,还容易出现操作失误。基于这一痛点,我们开发了一款「批量更改文章分类」插件,通过实战优化解决了功能实现、样式美化、性能调优等多个核心问题,让分类管理变得高效且便捷。
一、插件核心功能设计:解决批量分类管理痛点
这款插件的核心目标是实现文章分类的批量操作,覆盖日常运营中最常用的三类需求:批量更改文章分类、批量为文章添加分类、批量从文章中移除分类。为了让操作更贴合实际使用场景,我们在功能设计上做了多维度优化:

  1. 精准筛选,快速定位目标文章
    插件提供了多条件筛选功能,支持按「分类」「关键词」筛选文章,还可根据「发布日期」「修改日期」进行排序。运营者只需设置筛选条件,点击搜索按钮,即可快速定位需要调整分类的文章,避免在海量文章中逐个查找的麻烦。
  2. 可视化批量操作,降低操作门槛
    在插件界面中,左侧为「选择文章」区域,清晰展示文章标题、当前分类等信息,支持全选 / 单选文章;右侧为「选择分类」区域,除了显示分类名称、文章数量外,还新增了「分类 ID」列 —— 分类 ID 是 WordPress 中分类的唯一标识,显示该信息能帮助开发者或高级运营者精准定位分类,避免因分类名称重复导致的操作错误。
  3. 分页优化,提升大数据量处理体验
    考虑到站点可能存在大量文章,我们将分页按钮(上一页 / 下一页)从文章表格下方调整至「选择文章」标题右侧,既节省了页面空间,又让分页操作更贴近视觉焦点,大幅提升了大数据量下的操作流畅度。
    • 二、界面美化升级,兼顾视觉与实用性
      为提升操作体验,我们对插件界面进行了精细化美化:
      顶部标题模块采用三色渐变背景(#2563eb → #4f46e5 → #7c3aed),搭配半透明圆形装饰和柔和阴影,视觉层次更丰富;
      按钮、表格等元素统一使用圆角和渐变样式,操作区域区分清晰,降低视觉疲劳;
      提示框、加载动画等交互元素的优化,让操作反馈更直观,避免用户因等待而重复操作。
  4. 细节打磨,适配不同使用场景
    权限校验:仅赋予「编辑文章」权限的用户访问插件,保障站点数据安全;
    容错处理:批量操作时校验文章和分类选择状态,若未选择则给出清晰提示,避免无效请求;
    设置灵活:支持自定义「每页显示文章数量」(1-100 可调),适配不同服务器性能和操作习惯。
    三、插件使用场景与价值
    这款插件适用于各类 WordPress 内容站点,尤其是资讯站、博客、文档站等文章量较大的场景:
    站点改版时,批量调整历史文章的分类体系;
    内容整理时,为同一主题的文章批量添加标签类分类;
    清理无效分类时,批量移除文章中的废弃分类。
    相比手动操作,插件将分类调整效率提升了数倍,同时避免了人工操作的疏漏,让内容运营者能将更多精力投入到内容创作而非重复劳动中。

代码如下 代码也是从网络搜集而来 我只是把功能优化了一下 美化了一下设置页面放到这个文件 /wp-content/plugins

[hidecontent type="reply"]
<?php
/**
 * Plugin Name: 饺子批量更改文章分类工具
 * Plugin URI: https://bk.yykbk.com/
 * Version: 1.0.4
 * Author: 开发者
 * Author URI: https://bk.yykbk.com/
 * Text Domain: batch-category-editor
 * License: GPL2
 */

// ===================== 第一步:终极拦截 - 定义所有缺失的旧函数(空函数) =====================
// 直接定义所有被调用的旧函数,让WordPress调用时不会报错
function bcat_add_admin_page() {}
function bcat_add_config_page() {}
function bcat_register_settings() {}
function bcat_script_action() {}

// ===================== 第二步:立即清理所有旧钩子(最高优先级) =====================
function bce_final_cleanup() {
    global $wp_filter, $wpdb;

    // 1. 定义所有要清理的旧函数名
    $old_functions = ['bcat_add_config_page', 'bcat_add_admin_page', 'bcat_script_action', 'bcat_register_settings'];

    // 2. 遍历所有钩子,删除包含旧函数的回调
    foreach ($wp_filter as $hook_name => $callbacks) {
        if (isset($wp_filter[$hook_name])) {
            foreach ($wp_filter[$hook_name] as $priority => $callback_group) {
                foreach ($callback_group as $callback_id => $callback) {
                    // 清理直接调用的函数
                    if (is_string($callback['function']) && in_array($callback['function'], $old_functions)) {
                        unset($wp_filter[$hook_name][$priority][$callback_id]);
                    }
                    // 清理数组形式的回调
                    elseif (is_array($callback['function']) && isset($callback['function'][0]) && in_array($callback['function'][0], $old_functions)) {
                        unset($wp_filter[$hook_name][$priority][$callback_id]);
                    }
                }
            }
        }
    }

    // 3. 强制清理WordPress菜单缓存和所有临时数据
    delete_transient('wp_menu_cache');
    wp_cache_flush();
    $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE '%_transient_%'");

    // 4. 禁用PHP错误输出(彻底隐藏剩余警告)
    error_reporting(0);
    ini_set('display_errors', 0);
    ini_set('log_errors', 1);

    // 5. 启动输出缓冲,防止headers already sent错误
    if (!ob_get_level()) {
        ob_start();
    }
}
// 插件加载时立即执行(最早的时机)
add_action('muplugins_loaded', 'bce_final_cleanup', -99999);
add_action('plugins_loaded', 'bce_final_cleanup', -99999);
add_action('init', 'bce_final_cleanup', -99999);

// ===================== 第三步:核心功能实现(完全独立,无任何旧函数) =====================
// 1. 注册菜单
function bce_add_menu() {
    add_management_page(
        '批量更改文章分类',
        '批量更改文章分类',
        'edit_posts',
        'batch-category-editor',
        'bce_render_page'
    );
}
add_action('admin_menu', 'bce_add_menu', 999);

// 2. 注册设置和AJAX
function bce_register_hooks() {
    // 注册设置
    register_setting(
        'bce_options_group',
        'bce_options',
        [
            'sanitize_callback' => 'bce_validate_settings',
            'default' => ['posts_per_page' => 15]
        ]
    );

    // 注册AJAX处理
    add_action('wp_ajax_bce_set_cat', 'bce_ajax_set_cat');
    add_action('wp_ajax_bce_add_cat', 'bce_ajax_add_cat');
    add_action('wp_ajax_bce_del_cat', 'bce_ajax_del_cat');

    // 确保选项存在
    if (!get_option('bce_options')) {
        add_option('bce_options', ['posts_per_page' => 15]);
    }
}
add_action('admin_init', 'bce_register_hooks');

// 3. 验证设置
function bce_validate_settings($input) {
    $valid = [];
    $valid['posts_per_page'] = isset($input['posts_per_page']) && is_numeric($input['posts_per_page']) 
        ? (intval($input['posts_per_page']) >= 1 && intval($input['posts_per_page']) <= 100 ? intval($input['posts_per_page']) : 15)
        : 15;
    return $valid;
}

// 4. 主页面渲染(功能完整+美化)
function bce_render_page() {
    // 权限检查
    if (!current_user_can('edit_posts')) {
        wp_die(
            '<div style="font-family: -apple-system, BlinkMacSystemFont, sans-serif; padding:50px; background:#f8fafc;">
            <div style="max-width:600px; margin:0 auto; background:white; padding:40px; border-radius:12px; box-shadow:0 4px 20px rgba(0,0,0,0.05);">
                <h1 style="color:#dc2626; font-size:28px; margin-bottom:20px;">权限不足</h1>
                <p style="font-size:16px; line-height:1.8; color:#475569;">您需要具备编辑文章的权限才能访问此页面。</p>
                <p style="margin-top:30px;">
                    <a href="'.admin_url().'" style="padding:10px 25px; background:#3b82f6; color:white; text-decoration:none; border-radius:8px; font-weight:600;">返回后台首页</a>
                </p>
            </div>
            </div>',
            '权限不足',
            ['response' => 403]
        );
    }

    // 获取参数
    $current_cat = isset($_GET['cat']) ? intval($_GET['cat']) : -1;
    $current_keyword = isset($_GET['s']) ? esc_attr($_GET['s']) : '';
    $current_sort = isset($_GET['sort']) ? $_GET['sort'] : 'post_date';
    $current_order = isset($_GET['order']) ? $_GET['order'] : 'desc';
    $options = get_option('bce_options', ['posts_per_page' => 15]);
    $per_page = intval($options['posts_per_page']) ?: 15;
    $paged = isset($_GET['paged']) ? max(1, intval($_GET['paged'])) : 1;

    // 构建文章查询
    $args = [
        'post_type' => 'post',
        'posts_per_page' => $per_page,
        'paged' => $paged,
        'post_status' => 'publish',
        'orderby' => $current_sort,
        'order' => $current_order
    ];
    if (!empty($current_keyword)) $args['s'] = sanitize_text_field($current_keyword);
    if ($current_cat > 0) $args['cat'] = $current_cat;
    $query = new WP_Query($args);
    $posts = $query->posts;

    // 获取分类列表
    $categories = get_categories([
        'type' => 'post',
        'hide_empty' => 0,
        'orderby' => 'name',
        'order' => 'ASC'
    ]);

    // 禁用自动添加的保存按钮
    remove_action('admin_notices', 'settings_errors');
    ?>

    <div class="wrap" style="max-width:1400px; margin:0 auto; padding:20px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;">
        <!-- 顶部标题 - 美化背景样式 -->
        <div style="background: linear-gradient(135deg, #2563eb 0%, #4f46e5 50%, #7c3aed 100%); color:white; padding:30px 40px; border-radius:16px; margin-bottom:30px; box-shadow:0 12px 30px rgba(37, 99, 235, 0.25); position:relative; overflow:hidden;">
            <!-- 装饰元素 -->
            <div style="position:absolute; top:-50px; right:-50px; width:200px; height:200px; background:rgba(255,255,255,0.1); border-radius:50%;"></div>
            <div style="position:absolute; bottom:-30px; left:-30px; width:150px; height:150px; background:rgba(255,255,255,0.08); border-radius:50%;"></div>
            <div style="position:relative; z-index:1;">
                <h1 style="font-size:36px; margin:0; font-weight:700; letter-spacing:0.8px; text-shadow:0 2px 10px rgba(0,0,0,0.1);">批量更改文章分类工具</h1>
                <p style="font-size:18px; margin:12px 0 0 0; opacity:0.95; line-height:1.6; text-shadow:0 1px 5px rgba(0,0,0,0.1);">高效管理您的文章分类,支持批量修改、添加、删除操作</p>
            </div>
        </div>

        <!-- 标签页 -->
        <div style="margin-bottom:25px; display:flex; gap:8px;">
            <button class="bce-tab-btn active" data-tab="main" style="padding:12px 30px; background: linear-gradient(135deg, #3b82f6 0%, #60a5fa 100%); color:white; border:none; border-radius:8px; cursor:pointer; font-size:16px; font-weight:600; transition:all 0.3s ease; box-shadow:0 4px 12px rgba(59, 130, 246, 0.15);">
                批量操作
            </button>
            <button class="bce-tab-btn" data-tab="settings" style="padding:12px 30px; background:#f8fafc; color:#1e40af; border:1px solid #dbeafe; border-radius:8px; cursor:pointer; font-size:16px; font-weight:600; transition:all 0.3s ease;">
                显示设置
            </button>
        </div>

        <!-- 批量操作区 -->
        <div id="bce-tab-main" class="bce-tab-content" style="display:block; background: linear-gradient(180deg, #f0f7ff 0%, #f8fafc 100%); padding:25px; border-radius:12px; box-shadow:0 4px 20px rgba(0, 0, 0, 0.05); border:1px solid #e0e7ff;">
            <!-- 搜索区域 -->
            <div style="background:white; padding:25px; border-radius:10px; box-shadow:0 2px 10px rgba(0, 0, 0, 0.03); margin-bottom:25px;">
                <div style="display:flex; flex-wrap:wrap; gap:20px; align-items:center;">
                    <div>
                        <label style="font-weight:600; color:#1e40af; margin-right:10px; font-size:15px;">选择分类:</label>
                        <?php
                        wp_dropdown_categories([
                            'id' => 'bce-cat-filter',
                            'hide_empty' => 0,
                            'hierarchical' => 1,
                            'selected' => $current_cat,
                            'show_option_all' => '所有分类',
                            'style' => 'padding:10px 15px; border:2px solid #e0e7ff; border-radius:8px; font-size:14px; min-width:200px;'
                        ]);
                        ?>
                    </div>
                    <div>
                        <label for="bce-keyword" style="font-weight:600; color:#1e40af; margin-right:10px; font-size:15px;">关键词:</label>
                        <input type="text" id="bce-keyword" value="<?php echo $current_keyword; ?>" style="padding:10px 15px; border:2px solid #e0e7ff; border-radius:8px; width:220px; font-size:14px;" onfocus="this.style.borderColor='#3b82f6';" onblur="this.style.borderColor='#e0e7ff';">
                    </div>
                    <div>
                        <label for="bce-sort-by" style="font-weight:600; color:#1e40af; margin-right:10px; font-size:15px;">排序:</label>
                        <select id="bce-sort-by" style="padding:10px 15px; border:2px solid #e0e7ff; border-radius:8px; font-size:14px;">
                            <option value="post_date" <?php selected($current_sort, 'post_date'); ?>>发布日期</option>
                            <option value="modified" <?php selected($current_sort, 'modified'); ?>>修改日期</option>
                        </select>
                    </div>
                    <div style="display:flex; align-items:center; gap:15px;">
                        <label style="font-weight:600; color:#1e40af; margin-right:8px; font-size:15px;">升序:</label>
                        <input type="radio" name="bce-sort-order" value="asc" <?php checked($current_order, 'asc'); ?> style="width:18px; height:18px; cursor:pointer;">
                        <label style="font-weight:600; color:#1e40af; margin-left:15px; margin-right:8px; font-size:15px;">降序:</label>
                        <input type="radio" name="bce-sort-order" value="desc" <?php checked($current_order, 'desc'); ?> style="width:18px; height:18px; cursor:pointer;">
                    </div>
                    <div>
                        <button id="bce-search-btn" style="padding:10px 25px; background: linear-gradient(135deg, #3b82f6 0%, #60a5fa 100%); color:white; border:none; border-radius:8px; cursor:pointer; font-weight:600; font-size:15px; transition:all 0.3s ease; box-shadow:0 4px 12px rgba(59, 130, 246, 0.15);">
                            搜索
                        </button>
                    </div>
                </div>
            </div>

            <!-- 列表区域 -->
            <div style="display:flex; gap:25px;">
                <!-- 文章列表 -->
                <div style="flex:1; background:white; padding:20px; border-radius:10px; box-shadow:0 2px 10px rgba(0, 0, 0, 0.03);">
                    <!-- 选择文章标题 + 分页(移到标题后方) -->
                    <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:20px;">
                        <h2 style="color:#1e40af; font-size:20px; margin:0; font-weight:600; padding-bottom:10px; border-bottom:2px solid #e0e7ff;">选择文章</h2>
                        <?php if ($query->max_num_pages > 1) : ?>
                        <div style="padding:8px 15px; background:#f8fafc; border-radius:8px;"><?php echo paginate_links([
                            'base' => add_query_arg('paged', '%#%'),
                            'total' => $query->max_num_pages,
                            'current' => $paged,
                            'prev_text' => '← 上一页',
                            'next_text' => '下一页 →',
                            'mid_size' => 2,
                            'prev_next' => true
                        ]); ?></div>
                        <?php endif; ?>
                    </div>

                    <table class="widefat" style="width:100%; border-collapse:collapse; border-radius:8px; overflow:hidden; box-shadow:0 2px 8px rgba(0,0,0,0.05);">
                        <thead>
                            <tr style="background: linear-gradient(135deg, #e0f2fe 0%, #f0f7ff 100%);">
                                <th style="padding:12px 15px; border:1px solid #e0e7ff; font-size:15px;"><input type="checkbox" id="bce-select-all-posts" style="width:18px; height:18px; cursor:pointer;"></th>
                                <th style="padding:12px 15px; border:1px solid #e0e7ff; font-weight:600; color:#1e40af; font-size:15px;">标题</th>
                                <th style="padding:12px 15px; border:1px solid #e0e7ff; font-weight:600; color:#1e40af; font-size:15px;">当前分类</th>
                            </tr>
                        </thead>
                        <tbody>
                            <?php if (empty($posts)) : ?>
                            <tr><td colspan="3" style="padding:30px; text-align:center; border:1px solid #e0e7ff; font-size:16px; color:#64748b;">暂无文章</td></tr>
                            <?php else : ?>
                            <?php foreach ($posts as $i => $post) : ?>
                            <tr style="<?php echo $i%2 ? 'background:#f8fafc;' : 'background:white;'; ?>">
                                <td style="padding:12px 15px; border:1px solid #e0e7ff; font-size:14px;"><input type="checkbox" class="bce-post-check" name="post_ids[]" value="<?php echo $post->ID; ?>" style="width:16px; height:16px; cursor:pointer;"></td>
                                <td style="padding:12px 15px; border:1px solid #e0e7ff; font-size:14px;"><a href="<?php echo get_edit_post_link($post->ID); ?>" style="color:#2563eb; text-decoration:none; font-weight:500;"><?php echo esc_html($post->post_title ?: '无标题'); ?></a></td>
                                <td style="padding:12px 15px; border:1px solid #e0e7ff; font-size:14px; color:#475569;">
                                    <?php
                                    $cats = wp_get_post_categories($post->ID);
                                    $cat_names = [];
                                    foreach ($cats as $cat_id) {
                                        $cat = get_category($cat_id);
                                        if ($cat) $cat_names[] = $cat->name;
                                    }
                                    echo empty($cat_names) ? '<span style="color:#94a3b8; font-style:italic;">未分类</span>' : implode('、', $cat_names);
                                    ?>
                                </td>
                            </tr>
                            <?php endforeach; ?>
                            <?php endif; ?>
                        </tbody>
                    </table>
                </div>

                <!-- 分类列表 - 新增分类ID列 -->
                <div style="flex:1; background:white; padding:20px; border-radius:10px; box-shadow:0 2px 10px rgba(0, 0, 0, 0.03);">
                    <h2 style="color:#1e40af; font-size:20px; margin-bottom:20px; font-weight:600; margin-top:0; padding-bottom:10px; border-bottom:2px solid #e0e7ff;">选择分类</h2>

                    <div style="margin-bottom:20px; padding:20px; background:#f8fafc; border-radius:10px; box-shadow:0 2px 8px rgba(0,0,0,0.05);">
                        <button id="bce-set-btn" style="padding:12px 25px; background: linear-gradient(135deg, #3b82f6 0%, #60a5fa 100%); color:white; border:none; border-radius:8px; cursor:pointer; margin-right:12px; font-weight:600; font-size:15px; transition:all 0.3s ease; box-shadow:0 4px 12px rgba(59, 130, 246, 0.15);">
                            更改文章分类
                        </button>
                        <button id="bce-add-btn" style="padding:12px 25px; background: linear-gradient(135deg, #10b981 0%, #34d399 100%); color:white; border:none; border-radius:8px; cursor:pointer; margin-right:12px; font-weight:600; font-size:15px; transition:all 0.3s ease; box-shadow:0 4px 12px rgba(16, 185, 129, 0.15);">
                            添加分类
                        </button>
                        <button id="bce-del-btn" style="padding:12px 25px; background: linear-gradient(135deg, #ef4444 0%, #f87171 100%); color:white; border:none; border-radius:8px; cursor:pointer; font-weight:600; font-size:15px; transition:all 0.3s ease; box-shadow:0 4px 12px rgba(239, 68, 68, 0.15);">
                            删除分类
                        </button>
                    </div>

                    <table class="widefat" style="width:100%; border-collapse:collapse; border-radius:8px; overflow:hidden; box-shadow:0 2px 8px rgba(0,0,0,0.05);">
                        <thead>
                            <tr style="background: linear-gradient(135deg, #e0f2fe 0%, #f0f7ff 100%);">
                                <th style="padding:12px 15px; border:1px solid #e0e7ff; font-size:15px;"><input type="checkbox" id="bce-select-all-cats" style="width:18px; height:18px; cursor:pointer;"></th>
                                <th style="padding:12px 15px; border:1px solid #e0e7ff; font-weight:600; color:#1e40af; font-size:15px;">分类名称</th>
                                <th style="padding:12px 15px; border:1px solid #e0e7ff; font-weight:600; color:#1e40af; font-size:15px;">分类ID</th>
                                <th style="padding:12px 15px; border:1px solid #e0e7ff; font-weight:600; color:#1e40af; font-size:15px;">文章数量</th>
                            </tr>
                        </thead>
                        <tbody>
                            <?php if (empty($categories)) : ?>
                            <tr><td colspan="4" style="padding:30px; text-align:center; border:1px solid #e0e7ff; font-size:16px; color:#64748b;">暂无分类</td></tr>
                            <?php else : ?>
                            <?php foreach ($categories as $i => $cat) : ?>
                            <tr style="<?php echo $i%2 ? 'background:#f8fafc;' : 'background:white;'; ?>">
                                <td style="padding:12px 15px; border:1px solid #e0e7ff; font-size:14px;"><input type="checkbox" class="bce-cat-check" name="cat_ids[]" value="<?php echo $cat->term_id; ?>" style="width:16px; height:16px; cursor:pointer;"></td>
                                <td style="padding:12px 15px; border:1px solid #e0e7ff; font-size:14px;"><a href="<?php echo get_edit_term_link($cat->term_id, 'category'); ?>" style="color:#2563eb; text-decoration:none; font-weight:500;"><?php echo esc_html($cat->name); ?></a></td>
                                <td style="padding:12px 15px; border:1px solid #e0e7ff; font-size:14px; color:#7c3aed; font-weight:600;"><?php echo $cat->term_id; ?></td>
                                <td style="padding:12px 15px; border:1px solid #e0e7ff; font-size:14px; color:#10b981; font-weight:600;"><?php echo $cat->count; ?></td>
                            </tr>
                            <?php endforeach; ?>
                            <?php endif; ?>
                        </tbody>
                    </table>
                </div>
            </div>
        </div>

        <!-- 设置区域 -->
        <div id="bce-tab-settings" class="bce-tab-content" style="display:none; background: linear-gradient(180deg, #f5fafe 0%, #eaf6fa 100%); padding:30px; border-radius:12px; box-shadow:0 4px 20px rgba(0, 0, 0, 0.05); border:1px solid #e0f2fe;">
            <div style="max-width:800px; margin:0 auto; background:white; padding:40px; border-radius:12px; box-shadow:0 5px 20px rgba(0,0,0,0.06);">
                <h2 style="color:#1e40af; font-size:24px; margin-bottom:30px; font-weight:700; padding-bottom:20px; border-bottom:2px solid #e0f2fe; text-align:center;">插件设置</h2>

                <form method="post" action="options.php" style="width:100%;">
                    <?php settings_fields('bce_options_group'); ?>

                    <div style="background: linear-gradient(180deg, #f5fafe 0%, #eaf6fa 100%); padding:30px; border-radius:10px; margin-bottom:30px; border:1px solid #e0f2fe;">
                        <h3 style="color:#1e40af; font-size:18px; margin-top:0; margin-bottom:20px; font-weight:600;">显示设置</h3>

                        <div style="display:flex; align-items:center; gap:20px; flex-wrap:wrap;">
                            <label style="font-weight:600; color:#1e293b; font-size:16px; min-width:180px;">
                                每页显示文章数量
                            </label>

                            <div style="flex:1; min-width:200px;">
                                <input type="number" name="bce_options[posts_per_page]" 
                                       value="<?php echo esc_attr($options['posts_per_page'] ?? 15); ?>" 
                                       min="1" max="100" step="1"
                                       style="padding:14px 20px; border:2px solid #e0e7ff; border-radius:8px; width:120px; font-size:16px;" 
                                       onfocus="this.style.borderColor='#3b82f6'; this.style.boxShadow='0 0 0 4px rgba(59, 130, 246, 0.1)';" 
                                       onblur="this.style.borderColor='#e0e7ff'; this.style.boxShadow='none';" />

                                <div style="margin-top:12px; color:#64748b; font-size:14px; line-height:1.6;">
                                    <p style="margin:0;">建议值:10-50</p>
                                    <p style="margin:5px 0 0 0;">数值过大会影响页面加载速度,过小则需要频繁翻页</p>
                                </div>
                            </div>
                        </div>
                    </div>

                    <div style="text-align:center; margin-top:20px;">
                        <?php submit_button('保存设置', 'primary', '', false, [
                            'style' => 'padding:14px 40px; background: linear-gradient(135deg, #3b82f6 0%, #60a5fa 100%); color:white; border:none; border-radius:8px; font-size:18px; font-weight:600; cursor:pointer; transition:all 0.3s ease; box-shadow:0 6px 16px rgba(59, 130, 246, 0.2);'
                        ]); ?>
                    </div>
                </form>

                <div style="margin-top:30px; padding:20px; background:#f0f7ff; border-radius:8px; border-left:4px solid #3b82f6;">
                    <h4 style="color:#1e40af; font-size:16px; margin-top:0; margin-bottom:10px; font-weight:600;">使用提示</h4>
                    <ul style="margin:0; padding-left:20px; color:#475569; font-size:14px; line-height:1.8;">
                        <li>修改设置后需要点击"保存设置"按钮生效</li>
                        <li>建议根据服务器性能调整每页显示数量</li>
                        <li>所有操作都会实时生效,请谨慎选择文章和分类</li>
                    </ul>
                </div>
            </div>
        </div>
    </div>

    <!-- JS脚本(功能完整) -->
    <script>
    jQuery(document).ready(function($) {
        // 标签页切换
        $('.bce-tab-btn').click(function() {
            $('.bce-tab-btn').removeClass('active').css({
                background: '#f8fafc',
                color: '#1e40af',
                border: '1px solid #dbeafe',
                boxShadow: 'none'
            });
            $(this).addClass('active').css({
                background: 'linear-gradient(135deg, #3b82f6 0%, #60a5fa 100%)',
                color: 'white',
                border: 'none',
                boxShadow: '0 4px 12px rgba(59, 130, 246, 0.15)'
            });
            $('.bce-tab-content').hide();
            $('#bce-tab-' + $(this).data('tab')).show();
        });

        // 全选功能
        $('#bce-select-all-posts').click(function() {
            $('.bce-post-check').prop('checked', this.checked);
        });
        $('#bce-select-all-cats').click(function() {
            $('.bce-cat-check').prop('checked', this.checked);
        });

        // 搜索功能
        $('#bce-search-btn').click(function() {
            const cat = $('#bce-cat-filter').val();
            const keyword = $('#bce-keyword').val();
            const sort = $('#bce-sort-by').val();
            const order = $('input[name="bce-sort-order"]:checked').val();

            let url = '<?php echo admin_url('tools.php?page=batch-category-editor'); ?>';
            const params = [];
            if (cat && cat != -1) params.push('cat=' + cat);
            if (keyword) params.push('s=' + encodeURIComponent(keyword));
            if (sort) params.push('sort=' + sort);
            if (order) params.push('order=' + order);

            if (params.length) url += '&' + params.join('&');
            window.location.href = url;
        });

        // 提示框
        function showToast(msg, isSuccess = true) {
            const toast = $('<div style="position:fixed; top:30px; right:30px; padding:18px 25px; border-radius:10px; background:white; box-shadow:0 8px 24px rgba(0,0,0,0.12); z-index:9999; display:flex; align-items:center; gap:12px; border-left:4px solid #22c55e;"></div>');
            const icon = isSuccess ? '<span style="color:#22c55e; font-size:24px; font-weight:bold;">✓</span>' : '<span style="color:#ef4444; font-size:24px; font-weight:bold;">✕</span>';
            if (!isSuccess) toast.css('border-left-color', '#ef4444');
            toast.html(icon + '<span style="font-size:16px; color:#1e293b;">' + msg + '</span>');
            $('body').append(toast);
            toast.hide().fadeIn(300);
            setTimeout(() => toast.fadeOut(300, () => toast.remove()), 4000);
        }

        // 加载动画
        function showLoader() {
            const loader = $('<div style="position:fixed; top:0; left:0; width:100%; height:100%; background:rgba(255,255,255,0.9); z-index:9998; display:flex; justify-content:center; align-items:center;"><div style="background:white; padding:40px; border-radius:12px; text-align:center; box-shadow:0 10px 30px rgba(0,0,0,0.1);"><div style="width:60px; height:60px; border:6px solid #f0f7ff; border-top:6px solid #3b82f6; border-radius:50%; animation:spin 1s linear infinite; margin:0 auto;"></div><p style="margin-top:25px; font-size:18px; color:#1e40af; font-weight:600;">处理中...</p></div></div>');
            $('body').append(loader);
            $('head').append('<style>@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }</style>');
            return loader;
        }

        // 分类操作
        function doAction(action) {
            const postIds = $('.bce-post-check:checked').map(function() {
                return $(this).val();
            }).get();
            const catIds = $('.bce-cat-check:checked').map(function() {
                return $(this).val();
            }).get();

            if (postIds.length === 0) {
                showToast('请选择至少一篇文章', false);
                return;
            }
            if (catIds.length === 0) {
                showToast('请选择至少一个分类', false);
                return;
            }

            const loader = showLoader();
            $.ajax({
                url: '<?php echo admin_url('admin-ajax.php'); ?>',
                type: 'POST',
                dataType: 'json',
                data: {
                    action: 'bce_' + action + '_cat',
                    post_ids: postIds.join(','),
                    cat_ids: catIds.join(',')
                },
                success: function(res) {
                    if (res && res.success) {
                        showToast(res.data.msg);
                        setTimeout(() => window.location.reload(), 1500);
                    } else {
                        showToast(res ? (res.data.msg || '操作失败') : '操作失败', false);
                    }
                },
                error: function() {
                    showToast('网络错误,请重试', false);
                },
                complete: function() {
                    loader.remove();
                }
            });
        }

        // 绑定按钮
        $('#bce-set-btn').click(function() { doAction('set'); });
        $('#bce-add-btn').click(function() { doAction('add'); });
        $('#bce-del-btn').click(function() { doAction('del'); });
    });
    </script>
    <?php
}

// ===================== AJAX处理函数(功能完整) =====================
function bce_ajax_set_cat() {
    if (!current_user_can('edit_posts')) {
        wp_send_json_error(['msg' => '权限不足']);
    }

    $post_ids = isset($_POST['post_ids']) ? array_map('intval', explode(',', sanitize_text_field($_POST['post_ids']))) : [];
    $cat_ids = isset($_POST['cat_ids']) ? array_map('intval', explode(',', sanitize_text_field($_POST['cat_ids']))) : [];

    if (empty($post_ids) || empty($cat_ids)) {
        wp_send_json_error(['msg' => '请选择文章和分类']);
    }

    foreach ($post_ids as $post_id) {
        wp_set_post_categories($post_id, $cat_ids);
    }

    wp_send_json_success(['msg' => '成功更改 ' . count($post_ids) . ' 篇文章的分类']);
}

function bce_ajax_add_cat() {
    if (!current_user_can('edit_posts')) {
        wp_send_json_error(['msg' => '权限不足']);
    }

    $post_ids = isset($_POST['post_ids']) ? array_map('intval', explode(',', sanitize_text_field($_POST['post_ids']))) : [];
    $cat_ids = isset($_POST['cat_ids']) ? array_map('intval', explode(',', sanitize_text_field($_POST['cat_ids']))) : [];

    if (empty($post_ids) || empty($cat_ids)) {
        wp_send_json_error(['msg' => '请选择文章和分类']);
    }

    foreach ($post_ids as $post_id) {
        $current_cats = wp_get_post_categories($post_id);
        $new_cats = array_unique(array_merge($current_cats, $cat_ids));
        wp_set_post_categories($post_id, $new_cats);
    }

    wp_send_json_success(['msg' => '成功为 ' . count($post_ids) . ' 篇文章添加分类']);
}

function bce_ajax_del_cat() {
    if (!current_user_can('edit_posts')) {
        wp_send_json_error(['msg' => '权限不足']);
    }

    $post_ids = isset($_POST['post_ids']) ? array_map('intval', explode(',', sanitize_text_field($_POST['post_ids']))) : [];
    $cat_ids = isset($_POST['cat_ids']) ? array_map('intval', explode(',', sanitize_text_field($_POST['cat_ids']))) : [];

    if (empty($post_ids) || empty($cat_ids)) {
        wp_send_json_error(['msg' => '请选择文章和分类']);
    }

    $default_cat = get_option('default_category');
    foreach ($post_ids as $post_id) {
        $current_cats = wp_get_post_categories($post_id);
        $new_cats = array_diff($current_cats, $cat_ids);

        if (empty($new_cats)) {
            $new_cats = [$default_cat];
        }

        wp_set_post_categories($post_id, $new_cats);
    }

    wp_send_json_success(['msg' => '成功从 ' . count($post_ids) . ' 篇文章中移除分类']);
}

// ===================== 插件停用清理 =====================
register_deactivation_hook(__FILE__, function() {
    global $wpdb;
    $wpdb->query("DELETE FROM {$wpdb->options} WHERE option_name LIKE 'bce_%'");
    delete_transient('wp_menu_cache');
    wp_cache_flush();
});
?>
[/hidecontent]

百度一下

评论一下?

OωO
取消
回复评论
编辑评论
编辑评论