CC Duplicate Menu Hooks Reference
Last updated: 30th March 2026 for CC Duplicate Menu version 1.0
Overview
CC Duplicate Menu includes a number of hooks and filters that allow developers to customise how menu duplication works, how the admin button behaves and how menu item metadata is handled.
These hooks are intended to make the plugin flexible without requiring core plugin files to be edited.
This reference covers all actions and filters included in the first public release of CC Duplicate Menu.
Filters
cc_duplicate_menu_capability
Filters the required capability for duplicating menus.
By default, CC Duplicate Menu requires the edit_theme_options capability.
Parameters
$capability(string) – The required capability. Default:edit_theme_options
Return
- (
string) The capability that should be required
Example
add_filter( 'cc_duplicate_menu_capability', function( $capability ) {
return 'manage_options';
} );
cc_duplicate_menu_button_class
Filters the CSS classes applied to the Duplicate Menu button in the menu editor.
By default, the plugin uses the standard WordPress secondary button classes.
Parameters
$button_class(string) – Default button classes. Default:button button-secondary
Return
- (
string) CSS classes for the button
Example
add_filter( 'cc_duplicate_menu_button_class', function( $button_class ) {
return 'button button-secondary my-custom-duplicate-button';
} );
cc_duplicate_menu_button_position
Filters the button insertion position used by the admin JavaScript.
This is passed to the front end script and can be used by future enhancements or custom admin integrations.
Parameters
$position(string) – The insertion position string. Default:after-save-button
Return
- (
string) The button position identifier
Example
add_filter( 'cc_duplicate_menu_button_position', function( $position ) {
return 'before-delete-link';
} );
cc_duplicate_menu_show_in_header
Controls whether the Duplicate Menu button should also be shown in the header publishing actions area.
By default, this is disabled.
Parameters
$show(bool) – Whether to show the button in the header. Default:false
Return
- (
bool) Whether the button should be shown in the header
Example
add_filter( 'cc_duplicate_menu_show_in_header', '__return_true' );
cc_duplicate_menu_show_in_footer
Controls whether the Duplicate Menu button should be shown in the footer publishing actions area.
By default, this is enabled.
Parameters
$show(bool) – Whether to show the button in the footer. Default:true
Return
- (
bool) Whether the button should be shown in the footer
Example
add_filter( 'cc_duplicate_menu_show_in_footer', '__return_false' );
cc_duplicate_menu_redirect_to_new_menu
Filters whether the user should be redirected to the duplicated menu after the duplication process completes.
By default, the plugin redirects straight to the new menu.
Parameters
$redirect_to_new_menu(bool) – Whether to redirect to the new menu. Default:true$new_menu_id(int) – The new duplicated menu ID$menu_id(int) – The original source menu ID
Return
- (
bool) Whether to redirect to the duplicated menu
Example
add_filter( 'cc_duplicate_menu_redirect_to_new_menu', function( $redirect, $new_menu_id, $menu_id ) {
return false;
}, 10, 3 );
cc_duplicate_menu_new_menu_args
Filters the arguments passed to wp_update_nav_menu_object() when the duplicated menu is first created.
This can be used to alter the new menu name or pass additional arguments.
Parameters
$new_menu_args(array) – Arguments used to create the duplicated menu$menu(WP_Term) – The source menu object
Return
- (
array) Modified menu creation arguments
Example
add_filter( 'cc_duplicate_menu_new_menu_args', function( $args, $menu ) {
$args['menu-name'] = wp_slash( $menu->name . ' - Draft' );
return $args;
}, 10, 2 );
cc_duplicate_menu_skip_item
Filters whether an individual menu item should be skipped during duplication.
This runs during the first duplication pass before the new menu item is created.
Parameters
$skip_item(bool) – Whether to skip the item. Default:false$item(object) – The source menu item object$new_menu_id(int) – The new duplicated menu ID$menu_id(int) – The original source menu ID
Return
- (
bool) Whether to skip this menu item
Example
add_filter( 'cc_duplicate_menu_skip_item', function( $skip_item, $item ) {
if ( 'custom' === $item->type && ! empty( $item->url ) && false !== strpos( $item->url, '/private/' ) ) {
return true;
} return $skip_item;
}, 10, 2 );
cc_duplicate_menu_item_args
Filters the menu item arguments before the duplicated item is created in the first pass.
At this stage, all items are initially created with parent ID 0. Parent relationships are restored later.
Parameters
$args(array) – Menu item arguments forwp_update_nav_menu_item()$item(object) – The source menu item object$new_menu_id(int) – The new duplicated menu ID$menu_id(int) – The original source menu ID
Return
- (
array) Modified menu item arguments
Example
add_filter( 'cc_duplicate_menu_item_args', function( $args, $item ) {
if ( isset( $args['menu-item-title'] ) ) {
$args['menu-item-title'] = wp_slash( 'Copy: ' . wp_unslash( $args['menu-item-title'] ) );
} return $args;
}, 10, 2 );
cc_duplicate_menu_item_update_args
Filters the menu item arguments before the duplicated item is updated in the second pass.
This is the stage where parent-child relationships are restored using the new duplicated menu item IDs.
Parameters
$args(array) – Menu item arguments forwp_update_nav_menu_item()$item(object) – The source menu item object$new_parent_id(int) – The new parent menu item ID$new_menu_id(int) – The new duplicated menu ID$menu_id(int) – The original source menu ID
Return
- (
array) Modified menu item update arguments
Example
add_filter( 'cc_duplicate_menu_item_update_args', function( $args, $item, $new_parent_id ) {
$args['menu-item-parent-id'] = $new_parent_id;
return $args;
}, 10, 3 );
cc_duplicate_menu_copy_suffix
Filters the suffix appended to the original menu name when creating the duplicate.
By default, CC Duplicate Menu uses (copy).
Parameters
$suffix(string) – The suffix to append. Default:(copy)$original_name(string) – The original menu name
Return
- (
string) The suffix to use
Example
add_filter( 'cc_duplicate_menu_copy_suffix', function( $suffix, $original_name ) {
return ' (draft)';
}, 10, 2 );
cc_duplicate_menu_generated_name
Filters the final generated duplicate menu name after uniqueness checks have been applied.
This runs after the plugin has checked for name collisions and generated a final name.
Parameters
$name(string) – The final generated menu name$original_name(string) – The original menu name$base_name(string) – The base duplicate name before numbering
Return
- (
string) The final menu name to use
Example
add_filter( 'cc_duplicate_menu_generated_name', function( $name, $original_name, $base_name ) {
return $name . ' - staging';
}, 10, 3 );
cc_duplicate_menu_copy_item_meta
Filters whether additional non-core menu item metadata should be copied for an individual menu item.
By default, this is enabled.
Parameters
$copy_meta(bool) – Whether to copy extra item metadata. Default:true$old_item_id(int) – The original menu item ID$new_item_id(int) – The duplicated menu item ID$new_menu_id(int) – The new duplicated menu ID$menu_id(int) – The original source menu ID$item(object) – The source menu item object
Return
- (
bool) Whether to copy extra menu item metadata
Example
add_filter( 'cc_duplicate_menu_copy_item_meta', function( $copy_meta, $old_item_id, $new_item_id, $new_menu_id, $menu_id, $item ) {
if ( 'custom' === $item->type ) {
return false;
} return $copy_meta;
}, 10, 6 );
cc_duplicate_menu_skip_meta_keys
Filters the array of protected meta keys that should never be copied verbatim.
The plugin already excludes a number of internal WordPress and menu-related keys. This filter allows you to extend or replace that list.
Parameters
$protected_meta_keys(array) – Array of protected meta keys$old_item_id(int) – The original menu item ID$new_item_id(int) – The duplicated menu item ID$new_menu_id(int) – The new duplicated menu ID$menu_id(int) – The original source menu ID$item(object) – The source menu item object
Return
- (
array) Updated array of protected meta keys
Example
add_filter( 'cc_duplicate_menu_skip_meta_keys', function( $keys ) {
$keys[] = '_my_internal_menu_flag';
return $keys;
} );
cc_duplicate_menu_skip_meta_key
Filters whether a specific meta key should be skipped during menu item metadata copying.
This runs for each individual meta key after the protected key list has been checked.
Parameters
$skip_meta_key(bool) – Whether to skip the meta key. Default:false$meta_key(string) – The meta key being considered$values(array) – Raw stored values for this meta key$old_item_id(int) – The original menu item ID$new_item_id(int) – The duplicated menu item ID$new_menu_id(int) – The new duplicated menu ID$menu_id(int) – The original source menu ID$item(object) – The source menu item object
Return
- (
bool) Whether to skip the meta key
Example
add_filter( 'cc_duplicate_menu_skip_meta_key', function( $skip, $meta_key ) {
if ( '_temporary_plugin_cache' === $meta_key ) {
return true;
} return $skip;
}, 10, 2 );
cc_duplicate_menu_meta_value
Filters a copied menu item meta value before it is saved on the duplicated item.
This is useful if you need to reset or transform custom metadata during duplication.
Parameters
$meta_value(mixed) – The metadata value about to be copied$meta_key(string) – The meta key$old_item_id(int) – The original menu item ID$new_item_id(int) – The duplicated menu item ID$new_menu_id(int) – The new duplicated menu ID$menu_id(int) – The original source menu ID$item(object) – The source menu item object
Return
- (
mixed) The modified metadata value
Example
add_filter( 'cc_duplicate_menu_meta_value', function( $meta_value, $meta_key ) {
if ( '_menu_item_badge_text' === $meta_key ) {
return 'New';
} return $meta_value;
}, 10, 2 );
Actions
cc_duplicate_menu_before_duplicate
Fires before a menu duplication begins.
This is a good place to run custom validation, logging or setup routines.
Parameters
$menu_id(int) – The source menu ID$menu(WP_Term) – The source menu object
Example
add_action( 'cc_duplicate_menu_before_duplicate', function( $menu_id, $menu ) {
error_log( 'Duplicating menu: ' . $menu->name );
}, 10, 2 );
cc_duplicate_menu_after_item_create
Fires after an individual duplicate item has been created during the first duplication pass.
At this stage, parent-child relationships may not yet have been restored.
Parameters
$new_item_id(int) – The new duplicated menu item ID$new_menu_id(int) – The new duplicated menu ID$item(object) – The source menu item object$menu_id(int) – The original source menu ID
Example
add_action( 'cc_duplicate_menu_after_item_create', function( $new_item_id, $new_menu_id, $item, $menu_id ) {
// Custom logging or integration code here.
}, 10, 4 );
cc_duplicate_menu_after_item_meta_copy
Fires after additional menu item metadata has been copied from the source item to the duplicated item.
Parameters
$old_item_id(int) – The original menu item ID$new_item_id(int) – The duplicated menu item ID$new_menu_id(int) – The new duplicated menu ID$menu_id(int) – The original source menu ID$item(object) – The source menu item object
Example
add_action( 'cc_duplicate_menu_after_item_meta_copy', function( $old_item_id, $new_item_id ) {
update_post_meta( $new_item_id, '_copied_by_cc_duplicate_menu', 1 );
}, 10, 2 );
cc_duplicate_menu_after_duplicate
Fires after a menu has been duplicated.
This action fires whether the source menu contained items or not. If the source menu was empty, the old-to-new map will be an empty array.
Parameters
$new_menu_id(int) – The new duplicated menu ID$menu_id(int) – The original source menu ID$menu(WP_Term) – The source menu object$old_to_new_map(array) – Array mapping original item IDs to duplicated item IDs
Example
add_action( 'cc_duplicate_menu_after_duplicate', function( $new_menu_id, $menu_id, $menu, $map ) {
// Example: assign the duplicated menu to a custom workflow.
}, 10, 4 );
Notes on hook usage
Menu duplication happens in two passes
CC Duplicate Menu duplicates menu items in two stages:
- Create each menu item with a temporary parent ID of
0 - Update each item so parent-child relationships point to the newly duplicated item IDs
This means:
cc_duplicate_menu_item_argsruns during the first passcc_duplicate_menu_item_update_argsruns during the second pass
If you need to work with final hierarchy, the second-pass filter or the cc_duplicate_menu_after_duplicate action is usually the better choice.
Metadata copying is optional and filterable
The plugin copies non-core menu item metadata by default, but this behaviour is fully filterable.
If you are working with custom menu plugins or plugin-specific menu item fields, the following hooks are especially useful:
cc_duplicate_menu_copy_item_metacc_duplicate_menu_skip_meta_keyscc_duplicate_menu_skip_meta_keycc_duplicate_menu_meta_valuecc_duplicate_menu_after_item_meta_copy
