✨专业 WordPress 开发,定制建站,高效上线,合作即享优化服务!🚀
功能说明
功能一:将所有文章分类同步为 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(' ', $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
}