wordpress怎么把主网站的分类目录、导航菜单、页面、文章同步到子网站上面?
下面给你做一套完整的 WordPress Multisite 主站栏目 + 导航菜单自动同步系统。
按照你确认的要求,采用:
-
网站环境:WordPress Multisite 多站点。
-
服务器:宝塔面板 + Nginx。
-
程序语言:PHP。
-
部署方式:MU 插件(必须使用插件)。
-
同步范围:文章分类目录 + 网站导航菜单。
-
同步方向:主站 → 所有子站点。
-
删除策略:主站删除栏目或菜单,子站点保留原有内容。
-
第三方插件:不需要。
这套代码不需要修改 WordPress 核心文件,也不需要修改数据库结构。

一、最终实现效果
假设你的 WordPress 多站点有一个主站和三个子站点。
主站(统一管理)
文章分类目录
-
外汇资讯
-
外汇知识
-
交易平台
-
行业动态
网站导航菜单 -
首页
-
关于我们
-
新闻资讯
-
联系我们
PHP 自动同步
子站点 A
分类目录
导航菜单
子站点 B
分类目录
导航菜单
子站点 C
分类目录
导航菜单
具体效果:
| 操作 | 子站点是否同步 |
|---|---|
| 主站新增分类 | 自动创建 |
| 主站修改分类名称 | 自动修改 |
| 主站修改分类别名 | 自动修改 |
| 主站新增子分类 | 自动创建并关联父分类 |
| 主站删除分类 | 子站点保留 |
| 主站新增导航菜单 | 自动创建 |
| 主站修改导航菜单 | 自动更新 |
| 主站新增菜单项目 | 自动添加 |
| 主站删除菜单 | 子站点保留 |
另外,还会提供一个手动同步按钮,方便第一次部署时将主站现有的所有分类和菜单同步到子站点。
需要特别说明: 导航菜单同步的是菜单结构和菜单项目,不会自动复制页面、文章或媒体文件。菜单链接指向的页面和分类需要在子站点存在,代码会根据页面路径、分类别名进行匹配。
二、第一步:进入宝塔面板,找到网站目录
首先登录宝塔面板。
-
点击左侧「网站」。
-
找到你的 WordPress 主站。
-
点击「根目录」。
-
找到 WordPress 程序目录。
正常情况下,目录结构如下:
/www/wwwroot/你的域名/
│
├── wp-admin/
├── wp-content/
│ ├── plugins/
│ ├── themes/
│ ├── uploads/
│ └── mu-plugins/
│
├── wp-includes/
├── wp-config.php
└── index.php
我们要使用的是:
wp-content/mu-plugins/
注意:mu-plugins 是 WordPress 的特殊插件目录,默认情况下可能不存在,需要自己创建。
1. 创建 mu-plugins 文件夹
进入:
/www/wwwroot/你的域名/wp-content/
点击宝塔文件管理器的「新建目录」。
目录名称填写:
mu-plugins
最终得到:
/www/wwwroot/你的域名/wp-content/mu-plugins/
2. 创建 PHP 文件
进入刚刚创建的 mu-plugins 文件夹。
新建文件:
multisite-category-menu-sync.php
完整路径:
/www/wwwroot/你的域名/wp-content/mu-plugins/multisite-category-menu-sync.php
文件名称可以保持不变,后面所有代码都放在这个文件中。
三、第二步:配置 PHP 自动同步代码
下面是核心代码。
请将下面的代码完整复制到 multisite-category-menu-sync.php 文件中。不要遗漏开头和结尾。
<?php
/**
* Plugin Name: Multisite Category & Menu Sync
* Description: Synchronize main-site categories and navigation menus to all subsites.
* Version: 1.0.0
* Author: Custom
*/
if (!defined('ABSPATH')) {
exit;
}
if (!is_multisite()) {
return;
}
/**
* 全局同步锁,防止子站点同步时再次触发同步。
*/
$GLOBALS['mscms_syncing'] = false;
/**
* 获取主站 ID。
*/
function mscms_main_blog_id() {
return (int) get_main_site_id();
}
/**
* 判断当前是否为主站。
*/
function mscms_is_main_site() {
return get_current_blog_id() === mscms_main_blog_id();
}
/**
* 获取主站分类目录数据。
*/
function mscms_get_source_term($term_id) {
$main_id = mscms_main_blog_id();
switch_to_blog($main_id);
$term = get_term($term_id, 'category');
if (!$term || is_wp_error($term)) {
restore_current_blog();
return false;
}
$data = array(
'term_id' => (int) $term->term_id,
'name' => $term->name,
'slug' => $term->slug,
'description' => $term->description,
'parent' => (int) $term->parent,
);
restore_current_blog();
return $data;
}
/**
* 将主站分类同步到当前目标子站点。
* 支持多级分类及父子关系。
*/
function mscms_sync_category_recursive($term_id, $target_blog_id) {
$source_blog_id = mscms_main_blog_id();
$data = mscms_get_source_term($term_id);
if (!$data) {
return false;
}
// 先同步父分类,确保父子关系正确。
$parent_id = 0;
if (!empty($data['parent'])) {
$parent_id = mscms_sync_category_recursive(
$data['parent'],
$target_blog_id
);
if (!$parent_id) {
return false;
}
}
$map_option = 'mscms_term_map_' . $source_blog_id;
$mapping = get_option($map_option, array());
$source_id = (int) $data['term_id'];
$dest_id = isset($mapping[$source_id])
? (int) $mapping[$source_id]
: 0;
$dest_term = $dest_id
? get_term($dest_id, 'category')
: false;
$args = array(
'slug' => $data['slug'],
'description' => $data['description'],
'parent' => $parent_id,
);
// 已有映射的分类:更新。
if ($dest_term && !is_wp_error($dest_term)) {
$result = wp_update_term(
$dest_id,
'category',
array_merge($args, array(
'name' => $data['name'],
))
);
} else {
// 没有映射时,优先寻找同 slug 分类,避免重复创建。
$existing = term_exists(
$data['slug'],
'category'
);
if ($existing) {
$dest_id = is_array($existing)
? (int) $existing['term_id']
: (int) $existing;
$result = wp_update_term(
$dest_id,
'category',
array_merge($args, array(
'name' => $data['name'],
))
);
} else {
// 不存在时创建分类。
$result = wp_insert_term(
$data['name'],
'category',
$args
);
}
}
if (is_wp_error($result)) {
error_log(
'[Mscms] Category sync error: ' .
$result->get_error_message()
);
return false;
}
$dest_id = is_array($result)
? (int) $result['term_id']
: (int) $dest_id;
// 保存主站分类 ID 与子站点分类 ID 的对应关系。
$mapping[$source_id] = $dest_id;
update_option($map_option, $mapping, false);
return $dest_id;
}
/**
* 同步单个分类到指定子站点。
*/
function mscms_sync_category($term_id, $target_blog_id) {
if ($GLOBALS['mscms_syncing']) {
return;
}
$GLOBALS['mscms_syncing'] = true;
switch_to_blog($target_blog_id);
try {
mscms_sync_category_recursive(
(int) $term_id,
$target_blog_id
);
} finally {
restore_current_blog();
$GLOBALS['mscms_syncing'] = false;
}
}
/**
* 读取主站全部菜单及菜单项目。
* 同时记录页面、分类的 slug,便于在子站点匹配。
*/
function mscms_get_source_menus() {
$main_id = mscms_main_blog_id();
switch_to_blog($main_id);
$menus = wp_get_nav_menus();
$locations = get_nav_menu_locations();
$result = array();
foreach ($menus as $menu) {
$items = wp_get_nav_menu_items($menu->term_id);
$menu_items = array();
foreach ((array) $items as $item) {
$object_slug = '';
if ($item->type === 'post_type') {
$post = get_post($item->object_id);
if ($post) {
$object_slug = $post->post_name;
}
} elseif ($item->type === 'taxonomy') {
$term = get_term(
$item->object_id,
$item->object
);
if ($term && !is_wp_error($term)) {
$object_slug = $term->slug;
}
}
$menu_items[] = array(
'id' => (int) $item->ID,
'title' => $item->title,
'type' => $item->type,
'object' => $item->object,
'object_id' => (int) $item->object_id,
'url' => $item->url,
'description' => $item->description,
'attr_title' => $item->attr_title,
'target' => $item->target,
'classes' => (array) $item->classes,
'xfn' => $item->xfn,
'parent' => (int) $item->menu_item_parent,
'order' => (int) $item->menu_order,
'object_slug' => $object_slug,
);
}
$result[] = array(
'id' => (int) $menu->term_id,
'name' => $menu->name,
'slug' => $menu->slug,
'items' => $menu_items,
);
}
restore_current_blog();
return array(
'menus' => $result,
'locations' => $locations,
);
}
/**
* 将主站菜单项目所指向的对象,
* 转换成目标子站点中的对象 ID。
*/
function mscms_get_target_menu_object_id($item) {
if ($item['type'] === 'custom') {
return 0;
}
if ($item['type'] === 'post_type') {
$post = get_page_by_path(
$item['object_slug'],
OBJECT,
$item['object']
);
return $post ? (int) $post->ID : false;
}
if ($item['type'] === 'taxonomy') {
$term = get_term_by(
'slug',
$item['object_slug'],
$item['object']
);
return $term ? (int) $term->term_id : false;
}
return false;
}
/**
* 将主站所有导航菜单同步到指定子站点。
*/
function mscms_sync_menus_to_blog($target_blog_id) {
$source_data = mscms_get_source_menus();
$menus = $source_data['menus'];
$source_locations = $source_data['locations'];
$GLOBALS['mscms_syncing'] = true;
switch_to_blog($target_blog_id);
try {
$menu_mapping = get_option(
'mscms_menu_map_' . mscms_main_blog_id(),
array()
);
$item_mapping = get_option(
'mscms_menu_item_map_' . mscms_main_blog_id(),
array()
);
$dest_menu_ids = array();
foreach ($menus as $menu) {
$source_menu_id = $menu['id'];
// 根据 slug 找到目标菜单。
$dest_menu = wp_get_nav_menu_object(
$menu['slug']
);
if (!$dest_menu) {
// 不存在时创建菜单。
$new_menu_id = wp_update_nav_menu_object(
0,
array(
'menu-name' => $menu['name'],
)
);
if (is_wp_error($new_menu_id)) {
continue;
}
$dest_menu_id = (int) $new_menu_id;
} else {
$dest_menu_id = (int) $dest_menu->term_id;
// 更新菜单名称。
wp_update_nav_menu_object(
$dest_menu_id,
array(
'menu-name' => $menu['name'],
)
);
}
$menu_mapping[$source_menu_id] = $dest_menu_id;
$dest_menu_ids[$menu['slug']] = $dest_menu_id;
// 按菜单顺序排列,尽量确保父项目先创建。
usort($menu['items'], function($a, $b) {
return $a['order'] <=> $b['order'];
});
foreach ($menu['items'] as $item) {
$source_item_id = $item['id'];
$dest_item_id = isset(
$item_mapping[$source_item_id]
)
? (int) $item_mapping[$source_item_id]
: 0;
// 转换菜单项目对应的页面或分类 ID。
$object_id = mscms_get_target_menu_object_id(
$item
);
// 目标站点没有对应页面或分类时跳过。
if ($object_id === false) {
continue;
}
// 处理父菜单项目关系。
$parent_id = 0;
if (!empty($item['parent'])) {
$parent_id = isset(
$item_mapping[$item['parent']]
)
? (int) $item_mapping[$item['parent']]
: 0;
}
$args = array(
'menu-item-title' => $item['title'],
'menu-item-type' => $item['type'],
'menu-item-object' => $item['object'],
'menu-item-object-id' => $object_id,
'menu-item-url' => $item['url'],
'menu-item-description' => $item['description'],
'menu-item-attr-title' => $item['attr_title'],
'menu-item-target' => $item['target'],
'menu-item-classes' => $item['classes'],
'menu-item-xfn' => $item['xfn'],
'menu-item-parent-id' => $parent_id,
'menu-item-position' => $item['order'],
'menu-item-status' => 'publish',
);
// 已有项目更新,没有则创建。
$result = wp_update_nav_menu_item(
$dest_menu_id,
$dest_item_id,
$args
);
if (!is_wp_error($result) && $result) {
$item_mapping[$source_item_id] =
(int) $result;
}
}
}
update_option(
'mscms_menu_map_' . mscms_main_blog_id(),
$menu_mapping,
false
);
update_option(
'mscms_menu_item_map_' . mscms_main_blog_id(),
$item_mapping,
false
);
// 同步主题导航菜单位置。
$current_locations = get_nav_menu_locations();
$registered_locations = get_registered_nav_menus();
foreach ($source_locations as $location => $source_menu_id) {
if (!isset($registered_locations[$location])) {
continue;
}
$source_menu = wp_get_nav_menu_object(
$source_menu_id
);
if (!$source_menu) {
continue;
}
if (isset($dest_menu_ids[$source_menu->slug])) {
$current_locations[$location] =
$dest_menu_ids[$source_menu->slug];
}
}
set_theme_mod(
'nav_menu_locations',
$current_locations
);
} finally {
restore_current_blog();
$GLOBALS['mscms_syncing'] = false;
}
}
/**
* 同步主站全部分类和菜单到所有子站点。
*/
function mscms_sync_all_sites() {
if (!is_multisite()) {
return;
}
$main_id = mscms_main_blog_id();
// 获取主站全部分类。
switch_to_blog($main_id);
$categories = get_terms(array(
'taxonomy' => 'category',
'hide_empty' => false,
));
restore_current_blog();
// 获取网络内所有站点。
$sites = get_sites(array(
'number' => 0,
'deleted' => 0,
'archived' => 0,
'spam' => 0,
));
$count = 0;
foreach ($sites as $site) {
$target_blog_id = (int) $site->blog_id;
// 跳过主站。
if ($target_blog_id === $main_id) {
continue;
}
// 逐个同步分类。
if (!is_wp_error($categories)) {
foreach ($categories as $category) {
mscms_sync_category(
$category->term_id,
$target_blog_id
);
}
}
// 同步导航菜单。
mscms_sync_menus_to_blog(
$target_blog_id
);
$count++;
}
update_site_option(
'mscms_last_sync',
current_time('mysql')
);
update_site_option(
'mscms_last_sync_count',
$count
);
return $count;
}
/**
* 主站新增分类时自动同步。
*/
function mscms_category_created($term_id) {
if (
$GLOBALS['mscms_syncing'] ||
!mscms_is_main_site()
) {
return;
}
$sites = get_sites(array(
'number' => 0,
'deleted' => 0,
'archived' => 0,
'spam' => 0,
));
foreach ($sites as $site) {
if ((int) $site->blog_id === mscms_main_blog_id()) {
continue;
}
mscms_sync_category(
$term_id,
(int) $site->blog_id
);
}
}
add_action(
'created_category',
'mscms_category_created',
20,
1
);
/**
* 主站修改分类时自动同步。
*/
add_action(
'edited_category',
'mscms_category_created',
20,
1
);
/**
* 主站更新菜单时同步。
*/
function mscms_menu_changed($menu_id = 0) {
if (
$GLOBALS['mscms_syncing'] ||
!mscms_is_main_site()
) {
return;
}
$sites = get_sites(array(
'number' => 0,
'deleted' => 0,
'archived' => 0,
'spam' => 0,
));
foreach ($sites as $site) {
if ((int) $site->blog_id === mscms_main_blog_id()) {
continue;
}
mscms_sync_menus_to_blog(
(int) $site->blog_id
);
}
}
add_action(
'wp_update_nav_menu',
'mscms_menu_changed',
20,
1
);
add_action(
'wp_update_nav_menu_item',
'mscms_menu_changed',
20,
3
);
/**
* 新建子站点后,自动执行同步。
*/
function mscms_new_site_created($new_site) {
if (
$GLOBALS['mscms_syncing'] ||
!is_object($new_site)
) {
return;
}
$blog_id = (int) $new_site->blog_id;
if ($blog_id === mscms_main_blog_id()) {
return;
}
$GLOBALS['mscms_syncing'] = true;
try {
switch_to_blog($blog_id);
restore_current_blog();
// 这里延后到站点初始化完成后执行。
// 由后续的同步任务或手动同步完成首次同步。
} finally {
$GLOBALS['mscms_syncing'] = false;
}
}
add_action(
'wp_initialize_site',
'mscms_new_site_created',
100,
1
);
/**
* 网络管理后台添加同步管理页面。
*/
function mscms_add_network_admin_page() {
add_submenu_page(
'settings.php',
'多站点栏目菜单同步',
'栏目菜单同步',
'manage_network',
'mscms-sync',
'mscms_admin_page'
);
}
add_action(
'network_admin_menu',
'mscms_add_network_admin_page'
);
/**
* 管理页面。
*/
function mscms_admin_page() {
if (!current_user_can('manage_network')) {
wp_die('没有权限访问此页面。');
}
$last_sync = get_site_option(
'mscms_last_sync',
'尚未同步'
);
$last_count = get_site_option(
'mscms_last_sync_count',
0
);
?>
<div class="wrap">
<h1>WordPress 多站点栏目菜单同步</h1>
<p>
此功能将主站文章分类目录和导航菜单同步到所有子站点。
</p>
<table class="widefat striped" style="max-width:700px">
<tr>
<td><strong>同步方向</strong></td>
<td>主站 → 所有子站点</td>
</tr>
<tr>
<td><strong>同步内容</strong></td>
<td>文章分类目录 + 导航菜单</td>
</tr>
<tr>
<td><strong>删除策略</strong></td>
<td>保留子站点已有分类和菜单项目</td>
</tr>
<tr>
<td><strong>上次同步时间</strong></td>
<td><?php echo esc_html($last_sync); ?></td>
</tr>
<tr>
<td><strong>上次同步子站点数量</strong></td>
<td><?php echo esc_html($last_count); ?></td>
</tr>
</table>
<h2>手动执行全站同步</h2>
<p>
点击下面的按钮,将主站现有的分类和导航菜单同步到所有子站点。
</p>
<form method="post"
action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
<input type="hidden"
name="action"
value="mscms_manual_sync">
<?php wp_nonce_field('mscms_manual_sync'); ?>
<?php submit_button('立即同步所有子站点'); ?>
</form>
<?php if (isset($_GET['mscms_done'])) : ?>
<div class="notice notice-success is-dismissible">
<p>同步任务已执行,请检查子站点分类和导航菜单。</p>
</div>
<?php endif; ?>
</div>
<?php
}
/**
* 手动同步处理。
*/
function mscms_manual_sync_handler() {
if (!current_user_can('manage_network')) {
wp_die('没有权限执行此操作。');
}
check_admin_referer('mscms_manual_sync');
mscms_sync_all_sites();
wp_safe_redirect(
add_query_arg(
'mscms_done',
'1',
network_admin_url('settings.php?page=mscms-sync')
)
);
exit;
}
add_action(
'admin_post_mscms_manual_sync',
'mscms_manual_sync_handler'
);
四、第三步:补充新建子站点自动同步功能
上面代码还需要补充一个小地方:新建子站点时,不应该只等待你手动同步,而应该自动执行首次同步。
请在 PHP 文件中找到下面这段:
function mscms_new_site_created($new_site) {
从这个函数开始,一直到它后面的:
add_action(
'wp_initialize_site',
'mscms_new_site_created',
100,
1
);
将这一整段替换为下面的代码:
/**
* 新建子站点后,自动同步主站分类和菜单。
*/
function mscms_new_site_created($new_site) {
if (
empty($new_site->blog_id) ||
!is_multisite()
) {
return;
}
$target_blog_id = (int) $new_site->blog_id;
if ($target_blog_id === mscms_main_blog_id()) {
return;
}
// 获取主站全部分类。
$main_id = mscms_main_blog_id();
switch_to_blog($main_id);
$categories = get_terms(array(
'taxonomy' => 'category',
'hide_empty' => false,
));
restore_current_blog();
// 同步分类。
if (!is_wp_error($categories)) {
foreach ($categories as $category) {
mscms_sync_category(
$category->term_id,
$target_blog_id
);
}
}
// 同步导航菜单。
mscms_sync_menus_to_blog($target_blog_id);
}
add_action(
'wp_initialize_site',
'mscms_new_site_created',
100,
1
);
这样,新建子站点并完成 WordPress 初始化后,就会自动同步主站已有的分类目录和导航菜单。
五、第四步:保存代码并检查部署
现在进行保存。
-
回到宝塔文件管理器。
-
打开
multisite-category-menu-sync.php。 -
检查代码是否完整。
-
点击保存。
文件位置:
/www/wwwroot/你的域名/wp-content/mu-plugins/multisite-category-menu-sync.php
检查 PHP 版本
建议使用:
-
PHP 7.4
-
PHP 8.0
-
PHP 8.1
-
PHP 8.2
建议优先使用 PHP 8.1 或 8.2,并确保 WordPress 本身兼容。
本代码使用 PHP 7 及以上语法。
检查插件是否加载
登录 WordPress 主站后台:
进入:
「插件 → 已安装插件 → 必须使用的插件」
正常情况下应该看到:
Multisite Category & Menu Sync
必须使用的插件(MU Plugins)
PHP 文件已成功加载
多站点环境检测通过
注意:MU 插件不需要点击启用,它只要放在正确的目录中就会自动加载。
六、第五步:第一次手动同步
这是非常重要的一步。
代码部署完成后,第一次需要手动执行全站同步。
操作路径:
WordPress 主站后台
↓
我的站点(My Sites)
↓
网络管理(Network Admin)
↓
设置(Settings)
↓
栏目菜单同步
也可以尝试直接访问:
https://你的主站域名/wp-admin/network/settings.php?page=mscms-sync
进入后,你会看到:
WordPress 多站点栏目菜单同步
同步方向
主站 → 所有子站点
同步内容
分类目录 + 导航菜单
删除策略
保留子站点原有数据
手动执行全站同步
第一次部署时,点击按钮将主站现有栏目和菜单同步到所有子站点。
立即同步所有子站点
这是后台操作界面的示意图
点击「立即同步所有子站点」。
系统会依次执行:
-
读取主站所有文章分类。
-
检查每个子站点是否存在对应分类。
-
存在则更新,不存在则创建。
-
按照父子关系同步多级分类。
-
读取主站全部导航菜单。
-
在子站点创建或更新菜单。
-
匹配菜单项目对应的页面和分类。
-
尝试同步主题导航位置。
完成后,后台会显示上次同步时间和执行过的子站点数量。
注意: 当前代码是逐个站点同步,适合一般规模的多站点网络。如果子站点非常多(例如上百个),建议后续增加分批任务和失败重试机制。
七、第六步:测试自动同步是否正常
建议不要直接在正式网站上大规模操作,先拿一个子站点进行测试。
假设:
主站:https://www.example.com
子站点1:https://site1.example.com
子站点2:https://site2.example.com
以上域名只是测试示例。
测试一:主站新增分类
登录主站后台:
「文章 → 分类目录」
新建以下分类:
| 名称 | 别名(Slug) |
|---|---|
| 外汇资讯 | forex-news |
| 外汇知识 | forex-knowledge |
| 交易平台 | trading-platform |
| 行业动态 | industry-news |
点击添加分类。
然后分别登录子站点后台:
「文章 → 分类目录」
检查是否出现上述四个分类。
所有子站点都自动出现相同的分类。
测试二:测试多级分类
在主站建立:
外汇资讯
├── 行业新闻
├── 市场分析
└── 平台动态
其中:
-
外汇资讯:父分类。
-
行业新闻:子分类。
-
市场分析:子分类。
-
平台动态:子分类。
保存后,登录子站点检查。
预期结果:
外汇资讯
├── 行业新闻
├── 市场分析
└── 平台动态
父子级关系应该保持一致。
测试三:测试修改分类
在主站将:
外汇资讯
修改成:
外汇市场资讯
同时修改 Slug:
forex-news
修改后检查子站点。
预期结果:
-
分类名称自动修改。
-
Slug 自动修改。
-
原有子分类仍然保留。
-
不会重复创建一个新的分类。
测试四:测试删除分类
在主站删除:
行业动态
然后登录子站点。
预期结果:
子站点仍然保留:
行业动态
这是按照你要求的删除策略设计的。
测试五:测试导航菜单
登录主站后台:
「外观 → 菜单」
创建一个菜单:
主导航
添加以下菜单项目:
首页
关于我们
新闻资讯
联系我们
保存菜单。
然后检查子站点:
「外观 → 菜单」
预期结果:
-
自动创建主导航菜单。
-
自动添加菜单项目。
-
尽可能匹配对应页面。
-
保持菜单项目顺序。
-
保持父子级菜单关系。
-
尝试匹配相同名称的主题菜单位置。
注意:子站点必须存在对应的页面,否则代码会跳过无法匹配的页面菜单项,不会自动创建页面。
八、第七步:两个建议修改的小地方
为了让系统更稳定,我建议再做两个调整。
1. 修正网络后台提交地址
在代码中找到:
action="<?php echo esc_url(admin_url('admin-post.php')); ?>"
改成:
action="<?php echo esc_url(network_admin_url('admin-post.php')); ?>"
这样在网络管理后台执行同步时,会使用网络管理的正确地址。
2. 优先使用菜单 ID 映射,防止菜单重复创建
在 mscms_sync_menus_to_blog() 中,找到:
// 根据 slug 找到目标菜单。
$dest_menu = wp_get_nav_menu_object(
$menu['slug']
);
替换成:
// 优先根据保存的映射查找菜单。
$mapped_menu_id = isset(
$menu_mapping[$source_menu_id]
)
? (int) $menu_mapping[$source_menu_id]
: 0;
$dest_menu = $mapped_menu_id
? wp_get_nav_menu_object($mapped_menu_id)
: false;
// 如果映射不存在,再通过 slug 查找。
if (!$dest_menu) {
$dest_menu = wp_get_nav_menu_object(
$menu['slug']
);
}
这样可以减少菜单名称或别名发生变化时重复创建菜单的情况。
九、常见问题及解决办法
| 问题 | 可能原因 | 解决办法 |
|---|---|---|
| MU 插件没有显示 | 文件路径错误 | 检查 mu-plugins 目录 |
| 主站新增分类不自动同步 | PHP 报错或 Hook 未执行 | 查看 PHP 错误日志 |
| 子站点没有分类 | 子站点被排除或同步失败 | 手动全站同步 |
| 分类重复创建 | 旧分类映射缺失 | 检查分类 slug 和映射 |
| 导航菜单没有出现 | 菜单创建失败 | 检查菜单同步日志 |
| 菜单项目缺失 | 子站点不存在对应页面 | 先创建对应页面 |
| 菜单位置没有变化 | 子站点主题位置不同 | 检查主题注册的菜单位置 |
宝塔查看 PHP 错误日志
进入:
宝塔面板
↓
网站
↓
你的 WordPress 网站
↓
日志
也可以查看 PHP 错误日志。
代码中已经加入了分类同步错误记录:
error_log(
'[Mscms] Category sync error: ' .
$result->get_error_message()
);
如果遇到分类同步失败,可以通过日志定位问题。
十、上线前特别注意的事项
这套代码已经覆盖基本的分类和菜单同步流程,但正式投入 SEO 网站使用之前,有几个细节需要了解:
-
不会同步文章内容:只同步分类目录和导航菜单。
-
不会同步页面内容:菜单引用的页面需要在子站点提前创建。
-
不会删除子站点原有菜单项目:主站删除菜单项目后,子站点保留。
-
不会自动同步其他自定义分类法:目前只处理 WordPress 默认的
category。 -
导航菜单位置需要主题兼容:主站和子站点最好使用相同主题,并注册相同的菜单位置。
-
大规模站点需要分批处理:如果子站点达到几十至上百个,建议增加 WP-Cron 或队列处理,避免 PHP 执行超时。
另外,建议先备份数据库和 wp-content,再部署到正式网站。
十一、我建议你下一步完善的功能
目前这套属于第一版基础同步系统。如果你准备长期运营多个 SEO 子站点,我建议后续升级到 V2 版本:
| 功能 | V1 基础版 | V2 增强版 |
|---|---|---|
| 分类自动同步 |
支持
|
支持 |
| 菜单自动同步 |
支持
|
支持 |
| 多级分类 |
支持
|
支持 |
| 同步日志记录 | 基础 PHP 日志 | 独立日志后台 |
| 同步失败重试 | 不支持 | 支持 |
| 指定子站点同步 | 不支持 | 支持 |
| 定时自动校验 | 不支持 | 支持 |
| 菜单删除同步 | 保留子站点 | 可配置 |
| 分类与菜单映射管理 | 数据库存储 | 后台可视化管理 |
我的建议: 如果你的主要目的是运营多个 SEO 网站,最好升级成 V2,尤其是增加同步日志、失败重试、指定子站点和后台管理功能。
这样以后你只需要登录主站后台,就能统一管理所有子站点的栏目和导航,不需要每个网站单独操作。
部署完成后,我也可以继续帮你检查 PHP 错误日志和同步结果,确保这套系统真正运行正常。
本文标题:wordpress怎么把主网站的分类目录、导航菜单、页面、文章同步到子网站上面?,收录于EC Markets外汇官网平台:【新闻资讯】栏目,本文禁止任何商业性转载、分享,如需转载需联系小编并注明来源;部分内容整理自网络,如有侵权请联系删除。