Is there an easy way to replace a custom menu link with a page or post?

Although this does not directly answer the question, the code on which it is based provides the functionality. The code set is:

function install_menus() {
    require_once dirname( __FILE__) . '/data.php';
    $menus = get_menus_data();
    if ( ! empty ( $menus ) ) foreach ( $menus as $menu ) {
        if ( $menu['build'] ) {
            $menu_id = create_nav_menu( $menu );
            add_items_to_menu( $menu_id, $menu['slug'], $menu['items'] );
        }
    }
}

function create_nav_menu( $menu ) {
    if ( $exists = wp_get_nav_menu_object( $menu['name'] ) ) {
        $menu_id = $exists -> term_id;
          if ( empty ( $menu_id ) ) {
            $menu_id = wp_create_nav_menu( $menu['name'] );
        } 
    }
    else {
        $menu_id = wp_create_nav_menu( $menu['name'] );
    }
    return $menu_id;
}
function add_items_to_menu( $menu_id, $slug, $items ) {
    if ( $items ) foreach ( $items as $item ) {
        if ( $item['build'] ) {
            $slug = ( $item['title'] == 'Home' ) ? 'home' : $item['slug'];
            if ( ! menu_item_exists( $slug, $menu_id ) ) {
                wp_update_nav_menu_item( $menu_id, 0, array (
                    'menu-item-title' =>  __( $item['title'] ),
                    'menu-item-classes' => '',
                    'menu-item-url' => home_url( $item['slug'] . "https://wordpress.stackexchange.com/" ), 
                    'menu-item-status' => 'publish'
                    ) );
            }
        }
    }
}
function menu_item_exists( $slug, $menu_id ) {
    $args = array(
        'order'                  => 'ASC',
        'orderby'                => 'menu_order',
        'post_type'              => 'nav_menu_item',
        'post_status'            => 'publish',
        'output'                 => ARRAY_A,
        'output_key'             => 'menu_order',
        'nopaging'               => true,
        'update_post_term_cache' => false ); 

    $existing = wp_get_nav_menu_items( $menu_id, $args );
    $found = false;
    foreach ( $existing as $exists ) {
        if( strpos( $exists->post_name, $slug ) !== FALSE  ) {  //pretty good search (not exact).
            $found = true;
            break;
        }

    }
    return $found;
}

and the data file is:

function get_menus_data() {
    $items = array ( 
        array ( 
            'name' => 'Main Menu', 'slug' => 'main-menu', 'build' => 1, 
            'items' => array (
                array ( 'title' => 'Home', 'slug' => '', 'build' => 1 ), //slug should be empty
                array ( 'title' => 'Blog', 'slug' => 'blog', 'build' => 1 ),
                array ( 'title' => 'About', 'slug' => 'about', 'build' => 1 ),
                array ( 'title' => 'Contact', 'slug' => 'contact', 'build' => 1 ),
                ),
        ),
        array ( 
            'name' => 'Secondary Menu', 'slug' => 'secondary-menu', 'build' => 0,
            'items' => array (
                array ( 'title' => 'Home', 'slug' => '', 'build' => 1 ),
                array ( 'title' => 'Blog', 'slug' => 'blog', 'build' => 1 ),
                array ( 'title' => 'About', 'slug' => 'about', 'build' => 1 ),
                array ( 'title' => 'Contact', 'slug' => 'contact', 'build' => 1 ),
                ),
        ),
        array ( 
            'name' => 'Footer Menu', 'slug' => 'footer-menu', 'build' => 1,
            'items' => array (
                array ( 'title' => 'Terms', 'slug' => 'terms', 'build' => 1 ),
                array ( 'title' => 'Privacy', 'slug' => 'privacy', 'build' => 1 ),
                array ( 'title' => 'Contact', 'slug' => 'contact', 'build' => 1 ),
                ),
            ) 
    );
    return $items;
}

An interface would need to be built on top of this to allow for the selection that is asked, but this code is working and tested.

Leave a Comment