✨ Professional WordPress development, custom website builder, efficient on-line, cooperate and enjoy optimization services! 🚀

Batch Convert Posts to WooCommerce Products Plugin

功能说明

功能一:将所有文章分类同步为 WooCommerce 商品分类(保留层级结构)

  • 使用文章分类的名称和 slug 创建 product_cat

  • 保留父子层级

  • 自动跳过已存在分类

  • 可从后台点击按钮一键执行

功能二:批量将文章转换为 WooCommerce 商品

  • 多选文章分类进行批量转换

  • 绑定已同步的商品分类(按 slug 匹配)

  • 支持分页处理防止超时

  • 跳过已转换文章(使用 _converted_from_post 标记)


🧾 文件:batch-convert-posts-to-products.php

你可以将这份文件内容保存为插件:

<?php
/**
 * Plugin Name: 批量将文章转换为商品
 * Description: 将 WordPress 文章批量转换为 WooCommerce 商品,保持分类结构。
 * Version: 1.0
 * Author: 半岛
 */

// 添加后台工具菜单
add_action('admin_menu', function() {
    add_management_page(
        '文章转商品工具',
        '文章转商品工具',
        'manage_options',
        'batch-convert-posts-to-products',
        'render_batch_convert_page'
    );
});

// 渲染后台页面
function render_batch_convert_page() {
    $categories = get_categories(['hide_empty' => false]);
    ?>
    <div class="wrap">
        <h1>批量将文章转换为商品</h1>
        <h2>步骤 1:同步文章分类为商品分类(保留层级)</h2>
        <button id="sync-categories" class="button">同步文章分类到商品分类</button>
        <div id="sync-result" style="margin-top:10px;"></div>

        <h2 style="margin-top:40px;">步骤 2:选择分类批量转换文章为商品</h2>
        <form id="convert-form">
            <div style="max-height:300px; overflow:auto; border:1px solid #ccc; padding:10px;">
                <?= render_category_checkboxes($categories); ?>
            </div>
            <br>
            <button type="button" id="start-convert" class="button button-primary">开始转换</button>
        </form>
        <div id="convert-status" style="margin-top:20px; font-weight:bold;"></div>
    </div>

    <script>
    (function(){
        let offset = 0;
        let convertedTotal = 0;
        let selectedCats = [];

        // 同步分类按钮事件
        document.getElementById('sync-categories').addEventListener('click', function(){
            const btn = this;
            btn.disabled = true;
            btn.textContent = '同步中...';
            fetch(ajaxurl + '?action=sync_post_categories_to_product_cat')
                .then(res => res.json())
                .then(data => {
                    if (data.success) {
                        document.getElementById('sync-result').innerHTML = '✅ 同步完成,共同步分类:' + data.count;
                    } else {
                        document.getElementById('sync-result').innerHTML = '❌ 同步失败:' + data.message;
                    }
                    btn.disabled = false;
                    btn.textContent = '同步文章分类到商品分类';
                });
        });

        function updateStatus(msg) {
            document.getElementById('convert-status').innerHTML = msg;
        }

        function convertBatch() {
            if (!selectedCats.length) {
                updateStatus('请先选择分类');
                document.getElementById('start-convert').disabled = false;
                return;
            }

            const data = new URLSearchParams();
            data.append('action', 'ajax_batch_convert_posts_to_products');
            data.append('offset', offset);
            selectedCats.forEach(cat => data.append('cats[]', cat));

            fetch(ajaxurl, {
                method: 'POST',
                body: data,
                credentials: 'same-origin',
                headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
            }).then(res => res.json())
              .then(data => {
                  if (data.success) {
                      convertedTotal += data.converted;
                      offset += data.converted;
                      updateStatus(`已转换文章:${convertedTotal}`);
                      if (data.has_more) {
                          convertBatch();
                      } else {
                          updateStatus(`✅ 转换完成,总共转换文章:${convertedTotal}`);
                          document.getElementById('start-convert').disabled = false;
                      }
                  } else {
                      updateStatus('转换失败: ' + data.message);
                      document.getElementById('start-convert').disabled = false;
                  }
              }).catch(err => {
                  updateStatus('请求失败: ' + err.message);
                  document.getElementById('start-convert').disabled = false;
              });
        }

        document.getElementById('start-convert').addEventListener('click', function(){
            const checkedBoxes = document.querySelectorAll('input[name="post_cats[]"]:checked');
            selectedCats = Array.from(checkedBoxes).map(cb => cb.value);
            offset = 0;
            convertedTotal = 0;
            this.disabled = true;
            updateStatus('开始转换中...');
            convertBatch();
        });
    })();
    </script>
    <?php
}

// 显示分类多选框(带层级)
function render_category_checkboxes($categories, $parent = 0, $level = 0) {
    $html = '';
    foreach ($categories as $cat) {
        if ($cat->parent == $parent) {
            $indent = str_repeat('&nbsp;&nbsp;&nbsp;', $level);
            $html .= '<label style="display:block; margin-left:' . ($level * 20) . 'px;">';
            $html .= '<input type="checkbox" name="post_cats[]" value="' . esc_attr($cat->term_id) . '"> ';
            $html .= $indent . esc_html($cat->name);
            $html .= '</label>';
            $html .= render_category_checkboxes($categories, $cat->term_id, $level + 1);
        }
    }
    return $html;
}

// AJAX: 同步分类
add_action('wp_ajax_sync_post_categories_to_product_cat', function() {
    $post_categories = get_categories(['hide_empty' => false, 'orderby' => 'term_id']);
    $synced = 0;
    $cat_map = [];

    usort($post_categories, fn($a, $b) => $a->parent - $b->parent);

    foreach ($post_categories as $cat) {
        if (!$cat || is_wp_error($cat)) continue;

        $parent_product_cat_id = 0;
        if ($cat->parent && isset($cat_map[$cat->parent])) {
            $parent_product_cat_id = $cat_map[$cat->parent];
        }

        $term = get_term_by('slug', $cat->slug, 'product_cat');
        if (!$term) {
            $term = wp_insert_term($cat->name, 'product_cat', [
                'slug'   => $cat->slug,
                'parent' => $parent_product_cat_id,
            ]);
            if (is_wp_error($term)) continue;
            $term_id = $term['term_id'];
        } else {
            $term_id = $term->term_id;
            if ($term->parent != $parent_product_cat_id) {
                wp_update_term($term_id, 'product_cat', ['parent' => $parent_product_cat_id]);
            }
        }

        $cat_map[$cat->term_id] = $term_id;
        $synced++;
    }

    wp_send_json_success(['count' => $synced]);
});

// AJAX: 文章转商品
add_action('wp_ajax_ajax_batch_convert_posts_to_products', function() {
    $cats = isset($_POST['cats']) ? array_map('intval', $_POST['cats']) : [];
    $offset = isset($_POST['offset']) ? intval($_POST['offset']) : 0;
    $limit = 10;

    if (empty($cats)) {
        wp_send_json_error(['message' => '未选择分类']);
    }

    $posts = get_posts([
        'post_type'      => 'post',
        'posts_per_page' => $limit,
        'offset'         => $offset,
        'post_status'    => 'publish',
        'category__in'   => $cats,
        'orderby'        => 'ID',
        'order'          => 'ASC',
    ]);

    $converted = 0;

    foreach ($posts as $post) {
        $existing = get_posts([
            'post_type'  => 'product',
            'meta_key'   => '_converted_from_post',
            'meta_value' => $post->ID,
            'fields'     => 'ids',
            'posts_per_page' => 1,
        ]);
        if (!empty($existing)) continue;

        $product_id = wp_insert_post([
            'post_title'   => $post->post_title,
            'post_content' => $post->post_content,
            'post_excerpt' => $post->post_excerpt,
            'post_status'  => 'publish',
            'post_type'    => 'product',
        ]);
        if (is_wp_error($product_id)) continue;

        update_post_meta($product_id, '_converted_from_post', $post->ID);
        wp_set_object_terms($product_id, 'simple', 'product_type');

        $category_ids = wp_get_post_categories($post->ID);
        $product_cats = [];
        foreach ($category_ids as $catid) {
            $cat = get_category($catid);
            if ($cat && !is_wp_error($cat)) {
                $term = get_term_by('slug', $cat->slug, 'product_cat');
                if ($term) {
                    $product_cats[] = $term->term_id;
                }
            }
        }
        if (!empty($product_cats)) {
            wp_set_object_terms($product_id, $product_cats, 'product_cat');
        }

        $thumb_id = get_post_thumbnail_id($post->ID);
        if ($thumb_id) {
            set_post_thumbnail($product_id, $thumb_id);
        }

        $converted++;
    }

    $has_more = count($posts) === $limit;
    wp_send_json_success(['converted' => $converted, 'has_more' => $has_more]);
});

 

附加:一键删除指定文章分类下所有文章的完整 PHP 代码,可以放到主题的 functions.php 或自定义插件里,后台会添加一个菜单页面,输入文章分类 slug 或 ID,点击按钮即可删除该分类下所有文章。

// 删除指定文章分类下所有文章的函数
function delete_all_posts_in_category($category_slug_or_id) {
    $args = [
        'post_type'      => 'post',
        'posts_per_page' => -1,
        'post_status'    => 'any',
        'category__in'   => is_numeric($category_slug_or_id) ? [$category_slug_or_id] : [],
    ];

    // 如果传入的是 slug,则先查出对应分类 ID
    if (!is_numeric($category_slug_or_id)) {
        $cat = get_category_by_slug($category_slug_or_id);
        if ($cat && !is_wp_error($cat)) {
            $args['category__in'] = [$cat->term_id];
        } else {
            return new WP_Error('invalid_category', '分类不存在');
        }
    }

    $posts = get_posts($args);
    $deleted = 0;

    foreach ($posts as $post) {
        wp_delete_post($post->ID, true); // 强制永久删除
        $deleted++;
    }

    return $deleted;
}

// 后台菜单
add_action('admin_menu', function() {
    add_submenu_page(
        'edit.php',
        '清空文章分类',
        '清空文章分类',
        'manage_options',
        'delete-posts-by-category',
        'render_delete_posts_page'
    );
});

// 后台页面内容
function render_delete_posts_page() {
    $deleted_count = null;
    $error_message = '';

    if (isset($_POST['post_cat_slug'])) {
        $cat_slug_or_id = sanitize_text_field($_POST['post_cat_slug']);
        $result = delete_all_posts_in_category($cat_slug_or_id);
        if (is_wp_error($result)) {
            $error_message = $result->get_error_message();
        } else {
            $deleted_count = $result;
        }
    }
    ?>
    <div class="wrap">
        <h1>清空文章分类下所有文章</h1>
        <form method="post">
            <p>
                <label for="post_cat_slug">输入文章分类 Slug 或 ID:</label><br>
                <input type="text" name="post_cat_slug" id="post_cat_slug" style="width:300px;" required>
            </p>
            <p>
                <button class="button button-primary" type="submit">立即删除该分类下所有文章</button>
            </p>
        </form>
        <?php if ($deleted_count !== null): ?>
            <div style="margin-top:20px;">
                ✅ 共删除了 <strong><?php echo intval($deleted_count); ?></strong> 篇文章。
            </div>
        <?php elseif ($error_message): ?>
            <div style="margin-top:20px; color:red;">
                ❌ 错误:<?php echo esc_html($error_message); ?>
            </div>
        <?php endif; ?>
    </div>
    <?php
}

 

WordPress Support Team
WordPress Support Team

💻 A sincere and meticulous young developer 🎓 specializing in the field of custom foreign trade website development.
🌟 specializes in WordPress website design customization and full-service development. Our unique advantage is not only proficient in website development technology, but also the international mainstream art design elements 🎨 skillful integration, while developing accurate and effective brand marketing strategy 📈.
💡 Services covered:
🔍 WordPress Theme Development for a unique website visual style and user experience.
💻 WordPress website customization, tailor-made exclusive website according to your foreign trade business needs.
Whether it's website architecture construction, interface aesthetic design, or brand promotion strategy, we can provide you with one-stop quality solutions to help your foreign trade business stand out on the Internet and step into the global market 🚀.

Articles: 45

Leave a Reply

Your email address will not be published. Required fields are marked *

Submit your request

Quote Collection Form

💥Website Builder | Strengths speak for themselves, not false!

Treasure, we say, a lot of parties are not happy with their own sites are peers copying homework, which is like you open a store, certainly do not want others to know your sources of supply is a reason, right? So, in order to give customers a full sense of security, we did not put any customer case work on the site of the link ha, this is our protection of customer privacy.

📌 But if there is a sincere desire to do the site of the boss, or treasure you just want to look at our case, then hurry up to add the contact information of our website, we snappy send you a few look at, the main one sincere!

If you have not decided to do what style of website, but also simple, you find a few peers of the site sent to us, according to do on the end of the matter. We choose to imitate the site does not mean that no skill, we just can not stand that kind of invalid communication and cumbersome to make people crazy process. Some parties to do a corporate display site, have to find dozens of suppliers to roll, to be honest, no real technology companies will be there to lick the party. We are not the same, we want to be down-to-earth to the customer to make cost-effective, so that customers are satisfied with the site straight pat. Those kneeling work, let those who only play lip service, no technology companies to do it, we do not serve! # Website Development

# Party A Party B # Rejected Inside Coil

Contact the WordPress Technical Team

We look forward to hearing from you.

Submit your request

Quote Collection Form