TL;DR
PR #803 (merged) fixes Kit URL replacement, but customer purchases at https://kursopro.com (production WP Ultimo multisite, ~250+ subsites) still produce broken clones daily. Customers see wrong colors, missing logos, broken menus, "TU LOGO AQUÍ" placeholders.
I built a 774-line mu-plugin (kp-elementor-css-on-clone.php v2.9) that patches everything on our end. It's been running in production since 2026-04-13 with zero failures. I'd love for this logic to live inside Multisite Ultimate natively so I can retire the patch.
Full code (production-tested): https://gist.github.com/kenedytorcatt/7a0341f56a092466a3a039463a2518c7
The 4 bugs that survive PR #803
After MUCD_Data::copy_data() finishes (regardless of whether it's called via MUCD_Duplicate::duplicate_blog() or via WP Ultimo's class-site-duplicator.php), these postmeta rows are missing in the cloned site:
Bug 1 — Kit _elementor_page_settings not fully copied
Bug 2 — nav_menu_item postmeta not copied
- Symptom: menus render as empty
<li> tags with no titles, no URLs
- Diagnosis: nav_menu_item POSTS are copied (same IDs preserved) but their postmeta rows are NOT
- Missing keys:
_menu_item_type, _menu_item_object_id, _menu_item_object, _menu_item_url, _menu_item_menu_item_parent, _menu_item_target, _menu_item_classes, _menu_item_xfn
Bug 3 — attachment postmeta not copied
- Symptom: logos, default icons, Kit images render as broken/missing
- Missing keys:
_wp_attached_file, _wp_attachment_metadata, _wp_attachment_image_alt
Bug 4 — elementor_library CPT postmeta not copied
- Symptom: custom headers, footers, popups render as skeletons or default placeholder text
- Real case: clone of "plantilla4" → shopmariana.kursopro.com showed "TU LOGO AQUI" text instead of header logo
- Diagnosis: plantilla4 has 43 posts with
_elementor_data, clone had only 10 (13 elementor_library templates were missing all postmeta)
Critical insight (took me a week to figure out)
WP Ultimo customer purchases do NOT fire mucd_after_copy_data because class-site-duplicator.php calls MUCD_Data::copy_data() directly (not MUCD_Duplicate::duplicate_blog()). Instead, WP Ultimo fires its own wu_duplicate_site hook AFTER duplication.
This means:
- The correct hook for WP Ultimo flows is
wu_duplicate_site (priority must be before your Elementor_Compat::regenerate_css which runs at default 10)
mucd_after_copy_data only fires for manual admin duplications
- Both paths need coverage
Also: the source template ID passed to MUCD's hooks is hardcoded by the duplication call, but the customer's REAL template choice is in get_site_meta($to, 'wu_template_id'). Always prefer the meta over hook params.
How to integrate this into Multisite Ultimate natively
I'm not asking you to copy my mu-plugin verbatim. Here's the minimum integration that would let me retire it:
Step 1 — In class-site-duplicator.php, after MUCD_Data::copy_data() returns, run a postmeta backfill pass:
// Pseudo-code — adapt to your codebase style
$this->backfill_missing_postmeta($from_site_id, $to_site_id, [
'nav_menu_item' => [
'_menu_item_type', '_menu_item_object_id', '_menu_item_object',
'_menu_item_url', '_menu_item_menu_item_parent', '_menu_item_target',
'_menu_item_classes', '_menu_item_xfn',
],
'attachment' => [
'_wp_attached_file', '_wp_attachment_metadata', '_wp_attachment_image_alt',
],
'elementor_library' => '_elementor_*', // wildcard match
'page' => '_elementor_*',
'post' => '_elementor_*',
]);
$this->backfill_active_kit_settings($from_site_id, $to_site_id);
Step 2 — backfill_active_kit_settings() implementation:
private function backfill_active_kit_settings($from_site_id, $to_site_id) {
switch_to_blog($from_site_id);
$kit_id_from = (int) get_option('elementor_active_kit', 3);
$kit_settings = get_post_meta($kit_id_from, '_elementor_page_settings', true);
restore_current_blog();
if (empty($kit_settings)) return;
switch_to_blog($to_site_id);
$kit_id_to = (int) get_option('elementor_active_kit', 3);
// CRITICAL: must be update_post_meta (overwrite) — not INSERT NOT EXISTS
update_post_meta($kit_id_to, '_elementor_page_settings', $kit_settings);
delete_post_meta($kit_id_to, '_elementor_css'); // force regen
if (class_exists('\Elementor\Core\Files\CSS\Post')) {
(new \Elementor\Core\Files\CSS\Post($kit_id_to))->update();
}
restore_current_blog();
}
Step 3 — Add post-clone verification (catches edge cases):
// After backfill, verify the kit settings actually got copied
private function verify_kit_integrity($from_site_id, $to_site_id) {
// compare bytes of _elementor_page_settings between source and clone
// if clone < 80% of source bytes -> re-run backfill + schedule retry
}
Step 4 — In class-site-duplicator.php, when resolving the source for cloning:
// Always prefer wu_template_id meta over the explicit param
$meta_template = (int) get_site_meta($to_site_id, 'wu_template_id', true);
if ($meta_template > 0) {
$from_site_id = $meta_template;
}
This eliminates the hardcoded source bug where MUCD passes a different blog ID than the customer actually selected.
Reference implementation
Full production code in this Gist (774 lines, copy whatever you need):
https://gist.github.com/kenedytorcatt/7a0341f56a092466a3a039463a2518c7
Key functions to look at:
kp_run_complete_clone_fix() — universal entry point with double-execution guard
kp_fix_kit_postmeta_on_clone() — Bug 1 fix (uses update_post_meta not INSERT)
kp_fix_nav_menu_postmeta_on_clone() — Bug 2 fix
kp_fix_attachment_postmeta_on_clone() — Bug 3 fix
kp_fix_all_elementor_postmeta_on_clone() — Bug 4 fix (catch-all for any _elementor_* meta)
kp_verify_and_fix_kit() — post-clone verification + auto-retry at T+15s
Hook setup (triple safety):
add_action('wu_duplicate_site', 'kp_run_complete_clone_fix', 5); // PRIMARY (WP Ultimo)
add_action('mucd_after_copy_data', 'kp_run_complete_clone_fix', 10, 2); // FALLBACK (manual MUCD)
add_action('wu_pending_site_published', 'kp_run_complete_clone_fix', 9999); // SAFETY NET
Why this is urgent
We're losing customers. Every broken clone = customer support ticket + refund risk. PR #803 was a great start but doesn't cover the postmeta layer. Once you integrate this, I retire 2 mu-plugins from our stack (the patch + a defensive backup layer).
Happy to test any branch you put up. Can also provide more production logs / screenshots if useful.
Thanks David — your work on Multisite Ultimate is what makes our SaaS possible.
— Kenedy / KursoPro
TL;DR
PR #803 (merged) fixes Kit URL replacement, but customer purchases at https://kursopro.com (production WP Ultimo multisite, ~250+ subsites) still produce broken clones daily. Customers see wrong colors, missing logos, broken menus, "TU LOGO AQUÍ" placeholders.
I built a 774-line mu-plugin (
kp-elementor-css-on-clone.phpv2.9) that patches everything on our end. It's been running in production since 2026-04-13 with zero failures. I'd love for this logic to live inside Multisite Ultimate natively so I can retire the patch.Full code (production-tested): https://gist.github.com/kenedytorcatt/7a0341f56a092466a3a039463a2518c7
The 4 bugs that survive PR #803
After
MUCD_Data::copy_data()finishes (regardless of whether it's called viaMUCD_Duplicate::duplicate_blog()or via WP Ultimo'sclass-site-duplicator.php), these postmeta rows are missing in the cloned site:Bug 1 — Kit
_elementor_page_settingsnot fully copiedsystem_colors+custom_colorsarrays)INSERT NOT EXISTSand silently skips overwritingBug 2 —
nav_menu_itempostmeta not copied<li>tags with no titles, no URLs_menu_item_type,_menu_item_object_id,_menu_item_object,_menu_item_url,_menu_item_menu_item_parent,_menu_item_target,_menu_item_classes,_menu_item_xfnBug 3 —
attachmentpostmeta not copied_wp_attached_file,_wp_attachment_metadata,_wp_attachment_image_altBug 4 —
elementor_libraryCPT postmeta not copied_elementor_data, clone had only 10 (13 elementor_library templates were missing all postmeta)Critical insight (took me a week to figure out)
WP Ultimo customer purchases do NOT fire
mucd_after_copy_databecauseclass-site-duplicator.phpcallsMUCD_Data::copy_data()directly (notMUCD_Duplicate::duplicate_blog()). Instead, WP Ultimo fires its ownwu_duplicate_sitehook AFTER duplication.This means:
wu_duplicate_site(priority must be before yourElementor_Compat::regenerate_csswhich runs at default 10)mucd_after_copy_dataonly fires for manual admin duplicationsAlso: the source template ID passed to MUCD's hooks is hardcoded by the duplication call, but the customer's REAL template choice is in
get_site_meta($to, 'wu_template_id'). Always prefer the meta over hook params.How to integrate this into Multisite Ultimate natively
I'm not asking you to copy my mu-plugin verbatim. Here's the minimum integration that would let me retire it:
Step 1 — In
class-site-duplicator.php, afterMUCD_Data::copy_data()returns, run a postmeta backfill pass:Step 2 —
backfill_active_kit_settings()implementation:Step 3 — Add post-clone verification (catches edge cases):
Step 4 — In
class-site-duplicator.php, when resolving the source for cloning:This eliminates the hardcoded source bug where MUCD passes a different blog ID than the customer actually selected.
Reference implementation
Full production code in this Gist (774 lines, copy whatever you need):
https://gist.github.com/kenedytorcatt/7a0341f56a092466a3a039463a2518c7
Key functions to look at:
kp_run_complete_clone_fix()— universal entry point with double-execution guardkp_fix_kit_postmeta_on_clone()— Bug 1 fix (usesupdate_post_metanot INSERT)kp_fix_nav_menu_postmeta_on_clone()— Bug 2 fixkp_fix_attachment_postmeta_on_clone()— Bug 3 fixkp_fix_all_elementor_postmeta_on_clone()— Bug 4 fix (catch-all for any_elementor_*meta)kp_verify_and_fix_kit()— post-clone verification + auto-retry at T+15sHook setup (triple safety):
Why this is urgent
We're losing customers. Every broken clone = customer support ticket + refund risk. PR #803 was a great start but doesn't cover the postmeta layer. Once you integrate this, I retire 2 mu-plugins from our stack (the patch + a defensive backup layer).
Happy to test any branch you put up. Can also provide more production logs / screenshots if useful.
Thanks David — your work on Multisite Ultimate is what makes our SaaS possible.
— Kenedy / KursoPro