AJAX navigation menu - 02

No JS still

The first challenge was to make the AJAX navigation menu, inherently based on JavaScript, work without JavaScript at all. I really wanted the navigation menu to fallback to a usable version of itself to allow headless browsers, like the ones search engines use, to be able to traverse the pages in a script-free environment.
Some examples of drop down effects emulating the toggle and the drop down effect can be found with a quick Google search but I could not find something simple and re-usable enough to use in my project.
After some trial and error I could put together a working prototype to use as a guideline

the CSS is not in the scope of the project at the moment and I’ve styled the menu to minimum to get my point through. The menu will close when clicking real links or other menu items but will otherwise remain open. That’s not terrible but will break the “click out to close” usage pattern the web so well established. I’m not seeing millions of users not having JavaScript enabled and since the effect can easily be added later I’m leaving it behind at the moment.

The target markup

To implement the CSS-based behavior I’ve obtained in the fiddle I will need to bend the dynamic nature of WordPress to my will and make it output a markup comparable to the one I need

<nav class="menu">
    <div class="menu-item" id="g1">
        <a href="#g1" class="open">Group 1</a>
        <a href="#" class="close">Group 1</a>
        <div class="sub-menu">
            <div class="menu-item"><a href="#">Page 1.1</a></div>
            <div class="menu-item"><a href="#">Page 1.2</a></div>
            <div class="menu-item"><a href="#">Page 1.3</a></div>
            <div class="menu-item"><a href="#">Page 1.4</a></div>
        </div>
    </div>
    <div class="menu-item" id="g2">
        <a href="#g2" class="open">Group 2</a>
        <a href="#" class="close">Group 2</a>
        <div class="sub-menu">
            <div class="menu-item"><a href="#">Page 2.1</a></div>
            <div class="menu-item"><a href="#">Page 2.2</a></div>
            <div class="menu-item"><a href="#">Page 2.3</a></div>
            <div class="menu-item"><a href="#">Page 2.4</a></div>
        </div>
    </div>

    ...

</nav>

Simply calling the wp_nav_menu function with proper arguments won’t do: it’s time to implement a custom navigation menu walker.

The walker

I know the walker will need to get beyond this simple incarnation to fulfill the promise of an AJAX menu (pun intended) but I will be satisfied now to go from this menu structure [caption id=“attachment_886” align=“aligncenter” width=“976”]What the theme user is seeing What the theme user is seeing[/caption] to this output. [caption id=“attachment_887” align=“aligncenter” width=“1024”]The menu output The menu output[/caption] The current walker incarnation is very simple and will output a markup dynamically equal to the one presented above

<?php
namespace ajaxnav;

if (class_exists('Walker_Nav_Menu')) {
    class WalkerAjaxNavMenu extends \Walker_Nav_Menu
    {
        public function start_lvl(&$output, $depth = 0, $args = array())
        {
            $indent = str_repeat("\t", $depth);
            $output .= "\n$indent<div class=\"sub-menu\">\n";
        }

        public function end_lvl( &$output, $depth = 0, $args = array())
        {
            $indent = str_repeat("\t", $depth);
            $output .= "$indent</div>\n";
        }

        public function start_el(&$output, $item, $depth = 0, $args = array(), $id = 0)
        {
            $indent = str_repeat("\t", $depth);
            // if it is a container item
            if ($item->url == '') {
                $groupId = 'g-' . $item->ID;
                $groupName = $item->title;
                $output .= sprintf('%s<div class="menu-item" id="%s">', $indent, $groupId);
                $output .= sprintf('%s<a href="#%s" class="open">%s</a>', $indent . $indent, $groupId, $groupName);
                $output .= sprintf('%s<a href="#" class="close">%s</a>', $indent . $indent, $groupName);
            } else {
                // it's an element that actually links to something
                $output .= sprintf('%s<div class="menu-item"><a href="%s">%s</a>', $indent, $item->url, $item->title);
            }
        }

        public function end_el(&$output, $item, $depth = 0, $args = array()) {
            $output .= "</div>\n";
        }
    }
}

Echoing the menu to the page is now a simple matter of passing some ad-hoc parameters and the newly made walker to the wp_nav_menu function

$args = array(
    'theme_location' => $this->themeLocation,
    'container' => 'nav',
    'menu_class' => 'menu-ajax',
    'fallback_cb' => 'wp_page_menu',
    'items_wrap' => '<div class = "menu-ajax">%3$s</div>',
    'depth' => 2,
    'walker' => new \ajaxnav\WalkerAjaxNavMenu()
    );

$this->functions->wp_nav_menu( $args );

I’m omitting the defaulted parameters.

Next step

The next step will be to hook the JavaScript, jQuery really, to the menu to make it work in asynchronous mode like it should.