3

Introduction:

I have created several post type for my theme. To display a post from a post-type I need to go in appearance/menu and then add the post manually.

My Goal:

I want to add two radio buttons in the post add/edit page to choose whether the current post will be in menu.

Attempts:

So I have created the checkbox in post-type add/edit page. Looks like enter image description here

Everything works fine, the status is saved, now I want before saving to add/remove it in the menu list as sub-menu with for parent its post-type, how could I achieve that?

Here is what I have done so far:

// create post type
add_action( 'init', 'create_post_type' );
function create_post_type() {

    $conf = array(
        'public' => true,
        'has_archive' => true,
        'menu_position' => 5,
        'show_in_nav_menus' => true,
        'hierarchical' => true,
        'has_archive' => true,
        'supports' => array('title', 'editor', 'content', 'page-attributes'),
        'taxonomies' => array('category', 'post_tag'),

        );

    $conf['labels'] = array(
        'name' => __( 'Architecte Posts' ),
        'singular_name' => __( 'Architecte' )
        );
    $conf['rewrite'] = array('slug' => 'architect');

    register_post_type( 'architect_subpage',$conf);


    $conf['labels'] = array(
        'name' => __( 'Interior Posts' ),
        'singular_name' => __( 'Interior' )
        );
    $conf['rewrite'] = array('slug' => 'interior');
    register_post_type( 'interior_subpage',$conf);
}

// remove posts menu since it's not in use
function remove_menus () {
    global $menu;
    $restricted = array(__('Posts'));
    end ($menu);
    while (prev($menu)){
        $value = explode(' ',$menu[key($menu)][0]);
        if(in_array($value[0] != NULL?$value[0]:"" , $restricted)){unset($menu[key($menu)]);}
    }
}
add_action('admin_menu', 'remove_menus');




/* Define the custom box */
add_action( 'add_meta_boxes', 'wpse_61041_add_custom_box' );

/* Do something with the data entered */
add_action( 'save_post', 'wpse_61041_save_postdata' );

/* Adds a box to the main column on the Post and Page edit screens */
function wpse_61041_add_custom_box() {
    add_meta_box(
        'wpse_61041_sectionid',
        'Publish in Menu',
        'wpse_61041_inner_custom_box',
        'architect_subpage',
        'side',
        'high'
    );
}

/* Prints the box content */
function wpse_61041_inner_custom_box($post)
{
    // Use nonce for verification
    wp_nonce_field( 'wpse_61041_wpse_61041_field_nonce', 'wpse_61041_noncename' );

    // Get saved value, if none exists, "default" is selected
    $saved = get_post_meta( $post->ID, 'in_menu', true);
    if( !$saved )
        $saved = 'no';

    $fields = array(
        'yes'       => __('Yes', 'wpse'),
        'no'     => __('No', 'wpse'),
    );

    foreach($fields as $key => $label)
    {
        printf(
            '<input type="radio" name="in_menu" value="%1$s" id="in_menu[%1$s]" %3$s />'.
            '<label for="in_menu[%1$s]"> %2$s ' .
            '</label><br>',
            esc_attr($key),
            esc_html($label),
            checked($saved, $key, false)
        );
    }
}

/* When the post is saved, saves our custom data */
function wpse_61041_save_postdata( $post_id )
{
      // verify if this is an auto save routine.
      // If it is our form has not been submitted, so we dont want to do anything
      if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
          return;

      // verify this came from the our screen and with proper authorization,
      // because save_post can be triggered at other times
      if ( !wp_verify_nonce( $_POST['wpse_61041_noncename'], 'wpse_61041_wpse_61041_field_nonce' ) )
          return;

      if ( isset($_POST['in_menu']) && $_POST['in_menu'] != "" ){

            update_post_meta( $post_id, 'in_menu', $_POST['in_menu'] );

      }
}

https://gist.github.com/roine/4994447

4
  • Welcome to WordPress Stack Exchange! Would you be able to post the code you have so far? It would be a big help
    – shea
    Feb 20 '13 at 10:07
  • @bungeshea yep I added a gist Feb 20 '13 at 10:10
  • I don't get this: "add/remove it in the menu list as sub-menu with for parent its post-type"... Are you referring to a Nav-Menu?
    – brasofilo
    Feb 24 '13 at 17:08
  • @brasofilo, yes Feb 25 '13 at 1:48
1

The following is just a proof of concept and needs to be adapted/improved to work per the Question requirements.

It creates a meta box with a dropdown listing all available Navigation Menus. On post save, it is added to the selected menu.

This Q&A was used as starting point: Programmatically add a Navigation menu and menu items. The relevant functions are wp_get_nav_menus and wp_update_nav_menu_item. I'm not sure how to remove a menu item, but probably wp_delete_post must be used.

add_action( 'add_meta_boxes', 'add_custom_box_wpse_87594' );
add_action( 'save_post', 'save_postdata_wpse_87594', 10, 2 );

function add_custom_box_wpse_87594() 
{
    add_meta_box( 
        'section_id_wpse_87594',
        __( 'Available Nav-Menus' ),
        'inner_custom_box_wpse_87594',
        'post',
        'side'
    );
}

function inner_custom_box_wpse_87594() 
{
    $navmenus = wp_get_nav_menus( array( 'hide_empty' => false, 'orderby' => 'none' ) );

    // DEBUG
    // echo '<pre>' . print_r( $navmenus, true ) . '</pre>';

    wp_nonce_field( plugin_basename( __FILE__ ), 'noncename_wpse_87594' );

    echo '<select name="nav_menus_dropdown" id="nav_menus_dropdown">
        <option value="">- Select -</option>';

    foreach( $navmenus as $m ) 
    {
        printf( 
            '<option value="%s">%s</option>',
            $m->term_id,
            $m->name
        );
    }

    echo '</select>';   
}

function save_postdata_wpse_87594( $post_id, $post_object ) 
{
    // Auto save?
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )  
        return;

    // Security
    if ( 
        !isset( $_POST['noncename_wpse_87594'] ) 
        || !wp_verify_nonce( $_POST['noncename_wpse_87594'], plugin_basename( __FILE__ ) ) 
        )
        return;

    // Correct post_type
    if ( 'post' != $post_object->post_type )
        return;

    if( !empty( $_POST['nav_menus_dropdown'] ) )
    {
        wp_update_nav_menu_item(
            $_POST['nav_menus_dropdown'], 
            0, 
            array(
                'menu-item-title' => $_POST['post_title'],
                'menu-item-object' => 'page',
                'menu-item-object-id' => $_POST['ID'],
                'menu-item-type' => 'post_type',
                'menu-item-status' => 'publish'
            )
        );
    }       
}

Result:
navigation menus meta box

2
  • I really like this idea. I would be very interested in seeing the finished product. I think a feature like this could be added as a default function in WordPress and I think you should submit the idea to the powers that be
    – Jamie
    Mar 6 '13 at 15:27
  • Nice job @brasofilo Mar 7 '13 at 4:08
0

I have changed the code of brasofilo, and added the ability to add the post as a child

Here is the resivion: https://gist.github.com/roine/5105421/revisions

And here is the full code (also available here):

<?php
add_action( 'add_meta_boxes', 'add_custom_box_wpse_87594' );
add_action( 'save_post', 'save_postdata_wpse_87594', 10, 2 );

function add_custom_box_wpse_87594() 
{
    add_meta_box( 
        'section_id_wpse_87594',
        __( 'Available Nav-Menus' ),
        'inner_custom_box_wpse_87594',
        'post',
        'side'
    );
}

function inner_custom_box_wpse_87594() 
{
    $navmenus = wp_get_nav_menus( array( 'hide_empty' => false, 'orderby' => 'none' ) );

    // DEBUG
    // echo '<pre>' . print_r( $navmenus, true ) . '</pre>';

    wp_nonce_field( plugin_basename( __FILE__ ), 'noncename_wpse_87594' );

    echo '<select name="nav_menus_dropdown" id="nav_menus_dropdown">
        <option value="">- Select -</option>';

    foreach( $navmenus as $m ) 
    {
        echo "<optgroup label='$m->name'>";
        echo "<option value={$m->term_id}>&#8593; Add on top</option>";
        $items = wp_get_nav_menu_items( $m->term_id);
        foreach ($items as $key => $menu_item ) {
           if(!$menu_item->menu_item_parent){
              printf('<option value="%s-%s">%s</option>',
              $m->term_id,
              $menu_item->object_id,
              $menu_item->title);
           }
           echo "</optgroup>";
        }

    echo '</select>';   
    }
}

function save_postdata_wpse_87594( $post_id, $post_object ) 
{
    // Auto save?
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )  
        return;

    // Security
    if ( 
        !isset( $_POST['noncename_wpse_87594'] ) 
        || !wp_verify_nonce( $_POST['noncename_wpse_87594'], plugin_basename( __FILE__ ) ) 
        )
        return;

    // Correct post_type
    if ( 'post' != $post_object->post_type )
        return;

    if( !empty( $_POST['nav_menus_dropdown'] ) )
    {
        $parents = explode('-', $_POST['nav_menus_dropdown']);
        $item = array(
            'menu-item-title' => $_POST['post_title'],
            'menu-item-object' => 'page',
            'menu-item-object-id' => $_POST['ID'],
            'menu-item-type' => 'post_type',
            'menu-item-status' => 'publish'
        );
        if(count($parents) > 1){
           $item['menu-item-parent-id'] = $parents[1];
        }
        wp_update_nav_menu_item(
            $_POST['nav_menus_dropdown'], 
            0, 
            $item
        );
    }       
}

It works for me but still could be improved.

Behavior:

It will display the top level items of each menu in the dropdown list, also Add on top will add the post as a top level instead of as a child

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.