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 for wp_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 for wp_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:

  1. Create each menu item with a temporary parent ID of 0
  2. Update each item so parent-child relationships point to the newly duplicated item IDs

This means:

  • cc_duplicate_menu_item_args runs during the first pass
  • cc_duplicate_menu_item_update_args runs 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_meta
  • cc_duplicate_menu_skip_meta_keys
  • cc_duplicate_menu_skip_meta_key
  • cc_duplicate_menu_meta_value
  • cc_duplicate_menu_after_item_meta_copy