How to Create a Custom WordPress Navigation Menu with Unique HTML Structure
As a WordPress developer, you may find that the default wp_nav_menu()
function doesn't always generate the HTML structure you need for your website's navigation menu. Maybe you want to follow a specific naming convention, such as the BEM (Block, Element, Modifier) methodology, or maybe you just have a unique design in mind that requires a different markup.
Fortunately, there's a way to create a custom WordPress navigation menu with a unique HTML structure. In this article, we'll walk through the process of using the BEM method and the bem_menu()
function to build a custom navigation menu that fits your specific needs.
Understanding the BEM Methodology
BEM is a front-end naming convention that helps you create reusable, modular components. It stands for:
- Block: The top-level abstraction of a component.
- Element: A part of a Block that has no standalone meaning and is semantically tied to its Block.
- Modifier: A variation or extension of a Block or Element.
By using this naming convention, you can create a more semantic and maintainable codebase, which can be especially helpful when working with complex user interfaces.
In the context of a WordPress navigation menu, the BEM methodology can be applied as follows:
- Block: The entire navigation menu.
- Element: Individual menu items, such as links or dropdown menus.
- Modifier: Variations of the menu, such as an active state or a specific menu location.
Customizing the BEM-style HTML Structure
To customize the BEM-style HTML structure, you'll need to create a custom walker class that extends the BEM_Walker_Nav_Menu
class provided by the WordPress BEM Menu plugin. This will allow you to modify the generated HTML output to fit your specific needs.
Here's an example of how you can create a custom walker class:
class Custom_BEM_Walker extends BEM_Walker_Nav_Menu {
/**
* Starts the list before the elements are added.
*
* @param string $output Passed by reference. Used to append additional content.
* @param int $depth Depth of menu item. Used for padding.
* @param array $args An array of arguments. @see wp_nav_menu()
*/
public function start_lvl(&$output, $depth = 0, $args = array()) {
$indent = str_repeat("\t", $depth);
$output .= "\n$indent<ul class=\"navigation__submenu\">\n";
}
/**
* Outputs the beginning of the current level in the tree.
*
* @param string $output Passed by reference. Used to append additional content.
* @param int $depth Depth of menu item. Used for padding.
* @param array $args An array of arguments. @see wp_nav_menu()
*/
public function start_el(&$output, $item, $depth = 0, $args = array(), $id = 0) {
$indent = ($depth) ? str_repeat("\t", $depth) : '';
$classes = empty($item->classes) ? array() : (array) $item->classes;
$classes[] = 'navigation__item';
if ($args->has_children) {
$classes[] = 'navigation__item--has-children';
}
$class_names = join(' ', apply_filters('nav_menu_css_class', array_filter($classes), $item, $args));
$output .= "$indent<li class=\"{$class_names}\">";
$atts = array();
$atts['title'] = ! empty($item->attr_title) ? $item->attr_title : '';
$atts['target'] = ! empty($item->target) ? $item->target : '';
$atts['rel'] = ! empty($item->xfn) ? $item->xfn : '';
$atts['href'] = ! empty($item->url) ? $item->url : '';
$atts = apply_filters('nav_menu_link_attributes', $atts, $item, $args);
$attributes = '';
foreach ($atts as $attr => $value) {
if (! empty($value)) {
$value = ('href' === $attr) ? esc_url($value) : esc_attr($value);
$attributes .= ' ' . $attr . '="' . $value . '"';
}
}
$item_output = $args->before;
$item_output .= '<a'. $attributes .'>';
$item_output .= $args->link_before . apply_filters('the_title', $item->title, $item->ID) . $args->link_after;
$item_output .= '</a>';
$item_output .= $args->after;
$output .= apply_filters('walker_nav_menu_start_el', $item_output, $item, $depth, $args);
}
}
In this example, we've created a Custom_BEM_Walker
class that extends the BEM_Walker_Nav_Menu
class. We've overridden the start_lvl()
and start_el()
methods to customize the HTML structure.
The start_lvl()
method is responsible for generating the opening tag for a sub-menu. In our example, we've changed the class name from navigation__sub-menu
to navigation__submenu
.
The start_el()
method is responsible for generating the HTML for a single menu item. Here, we've added the navigation__item
class to each menu item, and we've added the navigation__item--has-children
class to menu items that have children.
To use the custom walker, you'll need to update the bem_menu()
function call in your theme's template file:
bem_menu(array(
'theme_location' => 'custom-menu',
'menu_class' => 'navigation',
'container' => 'nav',
'container_class'=> 'navigation__container',
'walker' => new Custom_BEM_Walker()
));
Now, the generated HTML structure will follow the custom BEM-style classes you've defined in the Custom_BEM_Walker
class.
Conclusion
The WordPress wp_nav_menu()
function is a convenient way to display a navigation menu, but it may not always produce the HTML structure you need. By using the WordPress BEM Menu plugin and creating a custom walker class, you can generate a custom WordPress navigation menu with a unique HTML structure that follows the BEM methodology.
This approach allows you to create a more semantic and maintainable codebase, which can be especially helpful when working with complex user interfaces. Additionally, the custom menu structure can be easily integrated into your theme's CSS, making it easier to style and customize the navigation menu to fit your design.
Remember, the key to a successful custom navigation menu implementation is to strike a balance between flexibility and maintainability. By following best practices and using the right tools, you can create a WordPress navigation menu that meets your specific requirements and delivers a great user experience.
For more information on how Flowpoint.ai can help you identify and fix technical issues that are impacting your website's conversion rates, visit Flowpoint.ai