Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

Anyone know of a plugin that can, or have an idea how to, allow a user to drop in separators/dividers between certain nav menu items?

Google only seems to bring up rookie CSS tips for first/last child selectors, I'm after something very much like Firefox bookmarks ;)

UPDATE:

I do appreciate all input so far, but I'll elaborate to avoid any further confusion;

  • I've written many plugins & themes, and have a good understanding of all the basics (hooking into WordPress, implementing extended functionality, handling & saving data etc.)
  • I'm specifically after advice on extending the nav menus admin UI, which would allow users to drop in 'separators' (nothing more than markers) between items in the menu, and how best to store that data & then render it in some shape or form on output with wp_nav_menu

Usually I would delve in & just get to work. But since this is only a possible requirement for an upcoming project, I thought I'd see if anyone's already tried something similar.

Plus I thought it might actually be useful for others, and would post my own feedback/results if I proceed with it.

share|improve this question
    
#nav-menu li { border-right: 1px solid #fff; } #nav-menu li:last-child { border-right: none; } –  Chris_O Jan 8 '12 at 13:11
    
Did anyone read my question? I need to allow the end user to drop in separators at any point of their choosing. –  TheDeadMedic Jan 8 '12 at 13:14
    
"allow a user to drop in separators/dividers between certain nav menu items" kinda implies end user. And I'm entirely aware of CSS/HTML requirements, this question is directed at suggested plugin techniques to build the required functionality. –  TheDeadMedic Jan 8 '12 at 14:34
add comment

3 Answers

up vote 3 down vote accepted

Use a custom walker. Extend start_el() to print <li class="menu_separator"><hr></li> if the menu title is just a '-'.

functions.php

function wpse38241_setup_menu()
{
    register_nav_menu( 'main-menu', 'Main Menu' );
}
add_action( 'after_setup_theme', 'wpse38241_setup_menu' );


/**
 * Replaces items with '-' as title with li class="menu_separator"
 *
 * @author Thomas Scholz (toscho)
 */
class Wpse38241_Separator_Walker extends Walker_Nav_Menu
{
    /**
     * Start the element output.
     *
     * @param  string $output Passed by reference. Used to append additional content.
     * @param  object $item   Menu item data object.
     * @param  int $depth     Depth of menu item. May be used for padding.
     * @param  array $args    Additional strings.
     * @return void
     */
    public function start_el( &$output, $item, $depth, $args )
    {
        if ( '-' === $item->title )
        {
            // you may remove the <hr> here and use plain CSS.
            $output .= '<li class="menu_separator"><hr>';
        }
        else
        {
            parent::start_el( &$output, $item, $depth, $args );
        }
    }
}

Create the menu

Now create your usual menu. Add an item with '-' as title:

enter image description here Full size image

Call the menu in your template

wp_nav_menu(
    array (
        'menu'            => 'main-menu',
        'container'       => FALSE,
        'container_id'    => FALSE,
        'menu_class'      => '',
        'menu_id'         => FALSE,
        'walker'          => new Wpse38241_Separator_Walker
    )
);

Output

(reformatted for readability)

<ul id="menu-separated" class="">
  <li id="menu-item-92" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-92">
    <a href="http://wordpress.stackexchange.com/questions/38241/nav-menu-separators">Nav menu separators?</a>
  </li>
  <li class="menu_separator">
    <hr>
  </li>
  <li id="menu-item-93" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-93">
    <a href="http://wordpress.stackexchange.com/">wordpress.stackexchange.com</a>
  </li>
</ul>

This works even without JavaScript and CSS.

share|improve this answer
    
Hmm liking that idea, quick and simple. Would still plan to bring in a new box on the left where the user could drag 'markers', which look & behave differently to standard menu items. –  TheDeadMedic Jan 8 '12 at 14:55
2  
Yes, absolutely. See this answer for custom meta boxes on nav-menu.php. –  toscho Jan 8 '12 at 15:03
add comment

You're gonna have to have 2 tiers to this, a PHP script to store the user's preference and recreate it upon reentry and a JS script to allow them to place it. How you handle placing it is up to you, I'd probably go with a drag-and-drop interface. My script would go something like the following:

add_action( 'wp_enqueue_scripts', 'my_divider_enqueue' );
add_action( 'wp_ajax_insert-divider', 'ajax_insert_divider' );

// enqueue the script
function my_divider_enqueue() {
    // register the script elsewhere, preferably in an init hook
    wp_enqueue_script( 'divider-js' );
    $passed_vars = array(
        'ajaxurl' => admin_url('admin-ajax.php' ),
        'nonce'   => wp_create_nonce( 'divider-ajax-nonce' )
    );
    if( is_user_logged_in() )
        $passed_vars['prev'] => get_user_meta( $current_user->ID, 'divider_location', true ); // you shouldn't need to declare $current_user, but you may
    wp_localize_script( 'divider-js', 'divider', $passed_vars );
}
// handle the js
function ajax_insert_divider() {
    if( !wp_verify_nonce( $_POST['divider_nonce'], 'divider-ajax-nonce' ) ) {
        header("HTTP/1.0 401 Internal Server Error", true, 401);
        exit;
    } else {
        //may not be necessary, you can test this
        global $current_user;
        get_currentuserinfo();

        //update user meta
        update_user_meta( $current_user->ID, 'divider_location', $_POST['divider_location'] );
    }
    exit;
}

Docs: wp_register_script(), wp_enqueue_script(), wp_localize_script(), wp_create_nonce(), is_user_logged_in(), get_user_meta(), wp_verify_nonce(), get_currentuserinfo(), update_user_meta()

and then after that have some javascript/jQuery to handle when the user changes (this is pseudocode, since implementation is something you'll need to decide on)

jQuery(document).ready(function(){
    //when the user releases the divider in the desired location, do some stuff
    jQuery('.divider').mouseup(function() {
        if( divider_is_valid() ) {
            place_divider();
        } else {
            reset_divider();
        }
    });
    //using divider.prev, place the desired dividers
});
function reset_divider() {
    //put the divider back where it started, either in a holder for unused dividers or where it was in the menu previously
}
function place_divider() {
    //place divider where it's going
    jQuery.post(
        divider.ajaxurl,
        {
            action        : 'insert-divider',
            divider_nonce : divider.nonce,
            location      : //some representation of the location that you can call later
        },
        function( response ) {
            //execute any actions you need to do on response
        }
    );
}

Script is entirely untested (I wrote it directly into the answer editor lol), but it should get you going in the right direction.

share|improve this answer
    
Thanks for your input. However, I think I should be a little clearer with my requirement, question updated. –  TheDeadMedic Jan 8 '12 at 14:50
    
Can you clarify a bit as to what specifically about this implementation is not to your liking, because as I read it it seems to meet all the requirements...clearly I'm reading something wrong lol –  m0r7if3r Jan 8 '12 at 15:02
    
Firstly, I really do appreciate your time. But if I'm to be honest, all you've effectively shown me is how to implement an AJAX callback and save user meta data which a) doesn't really address my question at all and b) is something I've now made clear in my answer that I'm capable of (though I understand this was not at the time you provided your answer). –  TheDeadMedic Jan 8 '12 at 15:25
    
Are you looking for something that will tie to the individual user and be customizable by that user, or something that will be site-wide? –  m0r7if3r Jan 8 '12 at 16:05
add comment

I'd use jQuery's .before() and .after() function, unless you are against it.

share|improve this answer
2  
And how does this allow a user to place separators wherever they require them? –  TheDeadMedic Jan 8 '12 at 13:15
    
By writing a plugin? Otherwise use custom menu and add empty links, which you then will style with CSS following your vision. –  Asko Jan 8 '12 at 13:23
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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