Skip to content

Instantly share code, notes, and snippets.

@sawwd
Last active November 27, 2017 00:36
Show Gist options
  • Save sawwd/b701676bcbb4ab11daeb34c7bcc3b14e to your computer and use it in GitHub Desktop.
Save sawwd/b701676bcbb4ab11daeb34c7bcc3b14e to your computer and use it in GitHub Desktop.
Standalone version of WordPress Menu Walker
<?php
class Walker_Menu {
public function __construct($elements) {
return $this->walk($elements, 0, array(
'menu' => '',
'container' => 'div',
'container_class' => 'menu-container',
'container_id' => '',
'menu_class' => 'menu',
'menu_id' => '',
'before' => '',
'after' => '',
'link_before' => '',
'link_after' => '',
'items_wrap' => '<ul id = "%1$s" class = "%2$s">%3$s</ul>',
'depth' => 0,
'walker' => '',
));
}
/**
* Starts the list before the elements are added.
*
* The $args parameter holds additional values that may be used with the child
* class methods. This method is called at the start of the output list.
*
* @since 2.1.0
* @abstract
*
* @param string $output Passed by reference. Used to append additional content.
* @param int $depth Depth of the item.
* @param array $args An array of additional arguments.
*/
public function start_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat( "\t", $depth );
$output .= "\n$indent<ul role=\"menu\" class=\"dropdown-menu-depth-{$depth} dropdown-menu\">\n";
}
/**
* Ends the list of after the elements are added.
*
* The $args parameter holds additional values that may be used with the child
* class methods. This method finishes the list at the end of output of the elements.
*
* @since 2.1.0
* @abstract
*
* @param string $output Passed by reference. Used to append additional content.
* @param int $depth Depth of the item.
* @param array $args An array of additional arguments.
*/
public function end_lvl( &$output, $depth = 0, $args = array() ) {
// if ( isset( $args->item_spacing ) && 'discard' === $args->item_spacing ) {
// $t = '';
// $n = '';
// } else {
$t = "\t";
$n = "\n";
// }
$indent = str_repeat( $t, $depth );
$output .= "$indent</ul>{$n}";
}
/**
* Start the element output.
*
* The $args parameter holds additional values that may be used with the child
* class methods. Includes the element output also.
*
* @since 2.1.0
* @abstract
*
* @param string $output Passed by reference. Used to append additional content.
* @param object $object The data object.
* @param int $depth Depth of the item.
* @param array $args An array of additional arguments.
* @param int $current_object_id ID of the current item.
*/
public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
$queried_page = $this->model_catalog_information->getInformation($item['id']);
/**
* Dividers, Headers or Disabled
* =============================
* Determine whether the item is a Divider, Header, Disabled or regular
* menu item. To prevent errors we use the strcasecmp() function to so a
* comparison that is not case sensitive. The strcasecmp() function returns
* a 0 if the strings are equal.
*/
/*if ( strcasecmp( $item->attr_title, 'divider' ) == 0 && $depth === 1 ) {
$output .= $indent . '<li role="presentation" class="divider">';
} else if ( strcasecmp( $item['title'], 'divider') == 0 && $depth === 1 ) {
$output .= $indent . '<li role="presentation" class="divider">';
} else if ( strcasecmp( $item->attr_title, 'dropdown-header') == 0 && $depth === 1 ) {
$output .= $indent . '<li role="presentation" class="dropdown-header">' . $item['title'];
} else if ( strcasecmp($item->attr_title, 'disabled' ) == 0 ) {
$output .= $indent . '<li role="presentation" class="disabled"><a href="#">' . $item['title'] . '</a>';
} else {*/
$class_names = $value = '';
$classes = empty( $item['classes'] ) ? array() : ( array ) $item['classes'];
$classes[] = 'menu-item-' . $item['id'];
$class_names = join( ' ', array_filter( $classes ) );
if ( $args['has_children'] )
$class_names .= ' dropdown';
if ( in_array( 'current-menu-item', $classes ) )
$class_names .= ' menu-item--active active';
$class_names = $class_names ? ' class="' . $class_names . '"' : '';
$id = 'menu-item-'. $item['id'];
$id = $id ? ' id="' . $id . '"' : '';
$output .= $indent . '<li' . $id . $value . $class_names .'>';
if ( isset($queried_page['title'])) {
$item['title'] = $queried_page['title'];
}
// $title = ! empty( $item['title'] ) ? $item['title'] : ! empty( $title ) ? $title : $item['title'];
if ( isset($queried_page['information_id'])) {
$item['url'] = $this->url->link('information/information', 'information_id=' . $queried_page['information_id']);
}
// $url = ! empty( $item['url'] ) ? $item['url'] : ! empty( $url ) ? $url : $item['url'];
$atts = array();
$atts['class'] = 'menu-item__link';
$atts['title'] = $item['title'];
$atts['target'] = ! empty( $item['target'] ) ? $item['target'] : '';
// $atts['rel'] = ! empty( $item->xfn ) ? $item->xfn : '';
// If item has_children add atts to a.
if ( $args['has_children'] ) {
$atts['href'] = $item['url'];
$atts['data-toggle'] = 'dropdown';
$atts['class'] .= ' dropdown-toggle';
$atts['aria-haspopup'] = 'true';
} else {
$atts['href'] = $item['url'];
}
$attributes = '';
foreach ( $atts as $attr => $value ) {
if ( ! empty( $value ) ) {
$value = ( 'href' === $attr ) ? $value : $value;
$attributes .= ' ' . $attr . '="' . $value . '"';
}
}
$item_output = $args['before'];
/*
* Glyphicons
* ===========
* Since the the menu item is NOT a Divider or Header we check the see
* if there is a value in the attr_title property. If the attr_title
* property is NOT null we apply it as the class name for the glyphicon.
*/
// if ( ! empty( $item->attr_title ) )
// $item_output .= '<a'. $attributes .'><span class="glyphicon ' . $item->attr_title . '"></span>&nbsp;';
// else
$item_output .= '<a'. $attributes .'>';
$item_output .= $args['link_before'] . $item['title'] . $args['link_after'];
$item_output .= ( $args['has_children'] ) ? ' <span class="caret"></span></a>' : '</a>';
$item_output .= $args['after'];
$output .= $item_output;
// }
}
/**
* Ends the element output, if needed.
*
* @since 3.0.0
*
* @see Walker::end_el()
*
* @param string $output Passed by reference. Used to append additional content.
* @param WP_Post $item Page data object. Not used.
* @param int $depth Depth of page. Not Used.
* @param stdClass $args An object of wp_nav_menu() arguments.
*/
public function end_el( &$output, $item, $depth = 0, $args = array() ) {
// if ( isset( $args->item_spacing ) && 'discard' === $args->item_spacing ) {
// $t = '';
// $n = '';
// } else {
$t = "\t";
$n = "\n";
// }
$output .= "</li>{$n}";
}
/**
* Traverse elements to create list from elements.
*
* Display one element if the element doesn't have any children otherwise,
* display the element and its children. Will only traverse up to the max
* depth and no ignore elements under that depth. It is possible to set the
* max depth to include all depths, see walk() method.
*
* This method should not be called directly, use the walk() method instead.
*
* @since 2.5.0
*
* @param object $element Data object.
* @param array $children_elements List of elements to continue traversing.
* @param int $max_depth Max depth to traverse.
* @param int $depth Depth of current element.
* @param array $args An array of arguments.
* @param string $output Passed by reference. Used to append additional content.
*/
public function display_element( $element, &$children_elements, $max_depth, $depth, $args, &$output ) {
if ( ! $element ) {
return;
}
$id = $element['id'];
//display this element
if ( isset( $args[0] ) && is_array( $args[0] ) ) {
$args[0]['has_children'] = ! empty( $children_elements[ $id ] ); // Back-compat.
}
$cb_args = array_merge( array(&$output, $element, $depth), $args);
call_user_func_array(array($this, 'start_el'), $cb_args);
// descend only when the depth is right and there are childrens for this element
if ( ($max_depth == 0 || $max_depth > $depth+1 ) && isset( $children_elements[$id]) ) {
foreach ( $children_elements[ $id ] as $child ){
if ( !isset($newlevel) ) {
$newlevel = true;
//start the child delimiter
$cb_args = array_merge( array(&$output, $depth), $args);
call_user_func_array(array($this, 'start_lvl'), $cb_args);
}
$this->display_element( $child, $children_elements, $max_depth, $depth + 1, $args, $output );
}
unset( $children_elements[ $id ] );
}
if ( isset($newlevel) && $newlevel ){
//end the child delimiter
$cb_args = array_merge( array(&$output, $depth), $args);
call_user_func_array(array($this, 'end_lvl'), $cb_args);
}
//end this element
$cb_args = array_merge( array(&$output, $element, $depth), $args);
call_user_func_array(array($this, 'end_el'), $cb_args);
}
/**
* Display array of elements hierarchically.
*
* Does not assume any existing order of elements.
*
* $max_depth = -1 means flatly display every element.
* $max_depth = 0 means display all levels.
* $max_depth > 0 specifies the number of display levels.
*
* @since 2.1.0
*
* @param array $elements An array of elements.
* @param int $max_depth The maximum hierarchical depth.
* @return string The hierarchical item output.
*/
public function walk( $elements, $max_depth ) {
$args = array_slice(func_get_args(), 2);
$output = '';
//invalid parameter or nothing to walk
if ( $max_depth < -1 || empty( $elements ) ) {
return $output;
}
// flat display
if ( -1 == $max_depth ) {
$empty_array = array();
foreach ( $elements as $e )
$this->display_element( $e, $empty_array, 1, 0, $args, $output );
return $output;
}
/*
* Need to display in hierarchical order.
* Separate elements into two buckets: top level and children elements.
* Children_elements is two dimensional array, eg.
* Children_elements[10][] contains all sub-elements whose parent is 10.
*/
$top_level_elements = array();
$children_elements = array();
foreach ( $elements as $e) {
if ( empty( $e['parent'] ) )
$top_level_elements[] = $e;
else
$children_elements[ $e['parent'] ][] = $e;
}
/*
* When none of the elements is top level.
* Assume the first one must be root of the sub elements.
*/
if ( empty($top_level_elements) ) {
$first = array_slice( $elements, 0, 1 );
$root = $first[0];
$top_level_elements = array();
$children_elements = array();
foreach ( $elements as $e) {
if ( $root['parent'] == $e['parent'] )
$top_level_elements[] = $e;
else
$children_elements[ $e['parent'] ][] = $e;
}
}
foreach ( $top_level_elements as $e )
$this->display_element( $e, $children_elements, $max_depth, 0, $args, $output );
/*
* If we are displaying all levels, and remaining children_elements is not empty,
* then we got orphans, which should be displayed regardless.
*/
if ( ( $max_depth == 0 ) && count( $children_elements ) > 0 ) {
$empty_array = array();
foreach ( $children_elements as $orphans )
foreach ( $orphans as $op )
$this->display_element( $op, $empty_array, 1, 0, $args, $output );
}
return $output;
}
}
new Walker_Menu($elements);
<?php
$elements = array(
// Solutions
array(
'id' => 24,
'parent' => 0,
'title' => '',
'target' => '',
'url' => '',
'classes' => '',
),
// General Purpose Mounting Solutions
array(
'id' => 9,
'parent' => 24,
'title' => '',
'target' => '',
'url' => '',
'classes' => '',
),
// Machine Tools Solutions
array(
'id' => 7,
'parent' => 24,
'title' => 'Machine Tools Solutions',
'target' => '',
'url' => '',
'classes' => '',
),
// Press Installation Solutions
array(
'id' => 31,
'parent' => 24,
'title' => 'Press Installation Solutions',
'target' => '',
'url' => '',
'classes' => '',
),
// Foundation Isolation Solutions
array(
'id' => 26,
'parent' => 24,
'title' => 'Foundation Isolation Solutions',
'target' => '',
'url' => '',
'classes' => '',
),
// Anchoring Solutions
array(
'id' => 32,
'parent' => 24,
'title' => 'Anchoring Solutions',
'target' => '',
'url' => '',
'classes' => '',
),
// Grouting Solutions
array(
'id' => 33,
'parent' => 24,
'title' => 'Grouting Solutions',
'target' => '',
'url' => '',
'classes' => '',
),
// Industries
array(
'id' => 34,
'parent' => 0,
'title' => '',
'target' => '',
'url' => '',
'classes' => '',
),
// Machine Tools Solutions
array(
'id' => 34991,
'parent' => 34,
'title' => 'Machine Tools Solutions',
'target' => '',
'url' => '#machine-tools-solutions',
'classes' => '',
),
// Machine Tools Solutions
array(
'id' => 9999, // fake page id to prevent recursion
'parent' => 34991,
'title' => '',
'target' => '',
'url' => '',
'classes' => '',
),
// Foundation Isolation Solutions
array(
'id' => 26,
'parent' => 34991,
'title' => 'Foundation Isolation Solutions',
'target' => '',
'url' => '#Foundation Isolation Solutions',
'classes' => '',
),
// Anchoring Solutions
array(
'id' => 32,
'parent' => 34991,
'title' => 'Anchoring Solutions',
'url' => '#Anchoring Solutions',
'target' => '',
'classes' => '',
),
// Grouting Solutions
array(
'id' => 33,
'parent' => 34991,
'title' => 'Grouting Solutions',
'target' => '',
'url' => '#Grouting Solutions',
'classes' => '',
),
// Services
array(
'id' => 14,
'parent' => 0,
'title' => '',
'target' => '',
'url' => '',
'classes' => '',
),
// Application Consulting
array(
'id' => 29,
'parent' => 14,
'title' => '',
'target' => '',
'url' => '',
'classes' => '',
),
// Engineering Design
array(
'id' => 28,
'parent' => 14,
'title' => '',
'target' => '',
'url' => '',
'classes' => '',
),
// Vibration Analysis
array(
'id' => 22,
'parent' => 14,
'title' => '',
'target' => '',
'url' => '',
'classes' => '',
),
// Training & Support
array(
'id' => 23,
'parent' => 14,
'title' => '',
'target' => '',
'url' => '',
'classes' => '',
),
// Technical Info
array(
'id' => 18,
'parent' => 0,
'title' => '',
'target' => '',
'url' => '',
'classes' => '',
),
// Literature
array(
'id' => 27,
'parent' => 18,
'title' => '',
'target' => '',
'url' => '',
'classes' => '',
),
// FAQs
array(
'id' => 20,
'parent' => 18,
'title' => '',
'target' => '',
'url' => '',
'classes' => '',
),
// About
array(
'id' => 21,
'parent' => 0,
'title' => '',
'target' => '',
'url' => '',
'classes' => '',
),
// Contact
array(
'id' => 30,
'parent' => 0,
'title' => '',
'target' => '',
'url' => '',
'classes' => '',
),
// Locate a Rep
array(
'id' => 3099,
'parent' => 30,
'title' => 'Locate a Rep',
'target' => '',
'url' => 'contact/#find-a-rep',
'classes' => '',
),
// Support
array(
'id' => 30999,
'parent' => 30,
'title' => 'Support',
'target' => '',
'url' => 'contact/#support',
'classes' => '',
),
);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment