*/ class MenuDuplicator { public function __construct() { add_action('admin_footer', [$this, 'add_duplicate_button'], 11); add_action('admin_footer', [$this, 'creating_menu_duplicate'], 6); // Duplicate Nav Menu Item add_action('admin_footer', [$this, 'duplicate_nav_menu_item'], 12); } /** * Duplicate Menu Button * * @return void */ public function add_duplicate_button() { // Only users who can manage menus may see/use the duplicate action. if ( ! current_user_can( 'edit_theme_options' ) ) { return; } $current_screen = get_current_screen(); $current_menu = (int) get_user_option('nav_menu_recently_edited'); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only check, no state change. if ($current_screen->id == 'nav-menus' && isset($_GET['menu']) && sanitize_text_field(wp_unslash($_GET['menu'])) != '0') { // CSRF protection: sign the duplicate action with a nonce tied to the menu id. $duplicate_url = wp_nonce_url( add_query_arg( 'adminify-menu-duplicate', $current_menu, admin_url( 'nav-menus.php' ) ), 'adminify_duplicate_menu_' . $current_menu ); $return = ''; $return .= '
' . __('Duplicate Menu', 'adminify') . ''; ?> id == 'nav-menus') { if (isset($_GET['adminify-menu-duplicate'])) { $id = intval(wp_unslash($_GET['adminify-menu-duplicate'])); // Authorization: only menu managers may duplicate. if ( ! current_user_can( 'edit_theme_options' ) ) { return; } // CSRF: verify the nonce that was attached to the duplicate link. $nonce = isset( $_GET['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ) : ''; if ( ! wp_verify_nonce( $nonce, 'adminify_duplicate_menu_' . $id ) ) { wp_die( esc_html__( 'Security check failed.', 'adminify' ) ); } $source = wp_get_nav_menu_object($id); $duplicate = $this->render_menu_duplicate($id, $source->name . ' ' . __('(Copy)', 'adminify')); if ($duplicate) { ?> render_menu_duplicate($id, $name . ' ' . __('(Copy)', 'adminify')); } if (!$new_id || is_array($new_id)) { return false; } // Key is the original db ID, val is the new $rel = []; $i = 1; foreach ($source_items as $menu_item) { $args = [ 'menu-item-db-id' => $menu_item->db_id, 'menu-item-object-id' => $menu_item->object_id, 'menu-item-object' => $menu_item->object, 'menu-item-position' => $i, 'menu-item-type' => $menu_item->type, 'menu-item-title' => $menu_item->title, 'menu-item-url' => $menu_item->url, 'menu-item-description' => $menu_item->description, 'menu-item-attr-title' => $menu_item->attr_title, 'menu-item-target' => $menu_item->target, 'menu-item-classes' => implode(' ', $menu_item->classes), 'menu-item-xfn' => $menu_item->xfn, 'menu-item-status' => $menu_item->post_status, ]; $parent_id = wp_update_nav_menu_item($new_id, 0, $args); $rel[$menu_item->db_id] = $parent_id; // did it have a parent? if so, we need to update with the NEW ID if ($menu_item->menu_item_parent) { $args['menu-item-parent-id'] = $rel[$menu_item->menu_item_parent]; $parent_id = wp_update_nav_menu_item($new_id, $parent_id, $args); } // allow developers to run any custom functionality they'd like do_action('pxlbsadminify_duplicate_menu_item', $menu_item, $args); $i++; } return $new_id; } /** * Duplicate Nav Menu Item * * @return void */ public function duplicate_nav_menu_item() { global $pagenow; if ($pagenow != 'nav-menus.php' || !current_user_can('edit_theme_options')) { return; } ?>