Instantly share code, notes, and snippets.
Last active
November 30, 2020 20:14
-
Save mrmu/0b00bec641ae528cd7401af362756d46 to your computer and use it in GitHub Desktop.
WordPress Bootstrap Mega Menu Nav Walker
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* Usage: | |
* 至後台建立選單,並勾選 Mega menu,自訂的 Walker 會將第二層選項建成 .row .col 的形式 | |
* 第二層選單的 css class 設為 mega-col,會自動註冊對應的「小工具容器」 (widget sidebar) | |
* 就能以小工具形式自訂 mega menu 的欄位內容。 | |
*/ | |
// 自訂 walker: Mu_Bootstrap_Mega_Menu_Nav_Walker | |
class Mu_Bootstrap_Mega_Menu_Nav_Walker extends Walker_Nav_Menu { | |
public function start_lvl(&$output, $depth = 0, $args = array()) { | |
// 排版用 | |
$indent = str_repeat( "\t", $depth ); | |
// 讓第一層子選單加上 caontainer > row | |
if ($depth === 0) { | |
$output .= "\n".$indent.'<ul class="dropdown-menu start-lvl mu-mega-wrap">'; | |
$output .= "\n\t".$indent.'<div class="container mega-content">'; | |
$output .= "\n\t\t".$indent.'<div class="row">'."\n"; | |
}else{ | |
$output .= "\n".$indent.'<ul class="start-lvl">'."\n"; | |
} | |
} | |
public function start_el(&$output, $item, $depth = 0, $args = array(), $id = 0) { | |
$item_html = ''; | |
// parent values (call by ref) | |
parent::start_el($item_html, $item, $depth, $args); | |
if ($item->is_dropdown && ($depth === 0)) { | |
$item_html = str_replace('<a', '<a class="dropdown-toggle" data-toggle="dropdown" data-target="#"', $item_html); | |
$item_html = str_replace('</a>', ' <b class="caret"></b></a>', $item_html); | |
} | |
$item_html = apply_filters('roots_wp_nav_menu_item', $item_html); | |
$output .= $item_html; | |
} | |
public function display_element($element, &$children_elements, $max_depth, $depth = 0, $args, &$output) { | |
$element->is_dropdown = ( | |
( | |
!empty($children_elements[$element->ID]) && | |
( | |
($depth + 1) < $max_depth || | |
($max_depth === 0) | |
) | |
) | |
); | |
if ($element->is_dropdown) { | |
$element->classes[] = 'dropdown has-children'; | |
} | |
// 第二層選項: 自動加上 .col 作為 megamenu 的 columns | |
if ($element && ($depth === 1)) { | |
$element->classes[] = 'col'; | |
} | |
// 第二層選項: 若後台有設 .mega-col 類別,就去載入對應的 widget 內容 | |
if ($element && ($depth === 1) && in_array('mega-col', $element->classes)) { | |
$output .= '<li class="col depth_'.$depth.'">'; | |
$output .= '<ul>'; | |
ob_start(); | |
dynamic_sidebar( 'mega-col-' . $element->ID ); | |
$dynamicSidebar = ob_get_contents(); | |
ob_end_clean(); | |
$output .= $dynamicSidebar; | |
$output .= '</ul>'; | |
$output .= '</li>'; | |
}else{ | |
parent::display_element($element, $children_elements, $max_depth, $depth, $args, $output); | |
} | |
} | |
public function end_lvl(&$output, $depth = 0, $args = array()) { | |
$indent = str_repeat( "\t", $depth ); | |
if ($depth === 0) { | |
$output .= "\n\t\t".$indent.'</div>'."\n"; | |
$output .= "\n\t".$indent.'</div>'."\n"; | |
$output .= "\n".$indent.'</ul>'."\n"; | |
}else{ | |
$output .= "\n".$indent.'</ul>'."\n"; | |
} | |
} | |
} | |
// 移除 nav menu item 的 id 和 簡化 class (非必要) | |
add_filter('nav_menu_item_id', '__return_null'); | |
add_filter('nav_menu_css_class', 'mu_mega_trim_roots_nav_menu_css_class', 10, 2); | |
function mu_mega_trim_roots_nav_menu_css_class($classes, $item) { | |
$slug = sanitize_title($item->title); | |
$classes = preg_replace('/(current(-menu-|[-_]page[-_])(item|parent|ancestor))/', 'active-${3}', $classes); | |
$classes = preg_replace('/(active-item)/', 'active', $classes); | |
$classes = preg_replace('/^((menu|page)[-_\w+]+)+/', '', $classes); | |
// 視情況自訂各個 menu item 的 class | |
// $classes[] = 'menu-' . $slug; | |
$classes = array_unique($classes); | |
return array_filter($classes); | |
} | |
// 自動註冊 mega menu 的自訂 widget | |
add_action('widgets_init', 'mu_mega_custom_cols_init'); | |
function mu_mega_custom_cols_init() { | |
// 自訂選單location: mega_menu | |
register_nav_menus( array( | |
'mega_menu' => 'Mega Menu', | |
) ); | |
$location = 'mega_menu'; | |
$css_class = 'mega-col'; | |
$locations = get_nav_menu_locations(); | |
if ( isset( $locations[ $location ] ) ) { | |
$menu = get_term( $locations[ $location ], 'nav_menu' ); | |
if ( $items = wp_get_nav_menu_items( $menu->name ) ) { | |
foreach ( $items as $item ) { | |
// 在 mega_menu 選單裡的選項若有 .mega-col 類別,就自動註冊一個 widget sidebar | |
if ( in_array( $css_class, $item->classes ) ) { | |
register_sidebar( | |
array( | |
'id' => 'mega-col-' . $item->ID, | |
'description' => 'Mega Menu Column', | |
'name' => $item->title . ' - Mega column', | |
'before_widget' => '<li id="%1$s" class="mega-menu-item">', | |
'after_widget' => '</li>', | |
) | |
); | |
} | |
} | |
} | |
} | |
} | |
add_action('wp_head', 'mu_mega_styles'); | |
function mu_mega_styles() { | |
?> | |
<style> | |
.mu-mega-wrap{ | |
width: 100%; | |
} | |
.mu-mega-wrap .navbar-nav, .navbar .collapse, .navbar-nav li { | |
position: static; | |
} | |
</style> | |
<?php | |
} | |
// 顯示選單 | |
function mu_mega_nav_menu() { | |
$args = array( | |
'theme_location' => 'mega_menu', | |
'depth' => 0, | |
'menu_class' => 'navbar-nav mr-auto', | |
'walker' => new Mu_Bootstrap_Mega_Menu_Nav_Walker() | |
); | |
wp_nav_menu($args); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment