Custom walker menu for wordpress not working - php

The reason for posting this here (and not on wordpress stackexchange) is because I have a feeling that this might be related to invalid PHP. It seems more users are familiar with php coding here.
I have a strange problem where I am not able to add an image to a post through the media library. I am able to upload an image, but wordpress does not display the previously uploaded images in the media library, so I cannot insert any of them to a new post. Basically the media library does not fetch any images.
So far I have found out that this problem is spesific to my theme, and that removing this line: require get_template_directory() . '/inc/css_menu_walker.php'; from my functions.php solves the problem.
However I need to load the custom walker to render the menu. So what is wrong here? As far as I can see I have loaded the template properly and I cannot find any errors in css_menu_walker.php:
<?php
class CSS_Menu_Maker_Walker extends Walker {
var $db_fields = array( 'parent' => 'menu_item_parent', 'id' => 'db_id' );
function start_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat("\t", $depth);
$output .= "\n$indent<ul>\n";
}
function end_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat("\t", $depth);
$output .= "$indent</ul>\n";
}
function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
global $wp_query;
$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
$class_names = $value = '';
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
/* Add active class */
if(in_array('current-menu-item', $classes)) {
$classes[] = 'active';
unset($classes['current-menu-item']);
}
/* Check for children */
$children = get_posts(array('post_type' => 'nav_menu_item', 'nopaging' => true, 'numberposts' => 1, 'meta_key' => '_menu_item_menu_item_parent', 'meta_value' => $item->ID));
if (!empty($children)) {
$classes[] = 'has-sub';
}
$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args ) );
$class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
$id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args );
$id = $id ? ' id="' . esc_attr( $id ) . '"' : '';
$output .= $indent . '<li' . $id . $value . $class_names .'>';
$attributes = ! empty( $item->attr_title ) ? ' title="' . esc_attr( $item->attr_title ) .'"' : '';
$attributes .= ! empty( $item->target ) ? ' target="' . esc_attr( $item->target ) .'"' : '';
$attributes .= ! empty( $item->xfn ) ? ' rel="' . esc_attr( $item->xfn ) .'"' : '';
$attributes .= ! empty( $item->url ) ? ' href="' . esc_attr( $item->url ) .'"' : '';
$item_output = $args->before;
$item_output .= '<a'. $attributes .'><span>';
$item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
$item_output .= '</span></a>';
$item_output .= $args->after;
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
function end_el( &$output, $item, $depth = 0, $args = array() ) {
$output .= "</li>\n";
}
}
I did not write the custom walker myself. I got it from here: http://cssmenumaker.com/blog/wordpress-3-drop-down-menu-tutorial and it seems this page has not been updated since 2013. This leads me to think that the code might be outdated and incompatible with the current version of wordpress.
Wordpress version does not matter. I have the same problem in 4.5.2 and 4.4.3.

In my functions.php I replaced:
// Include the custom walker navigation
require get_template_directory() . '/inc/css_menu_walker.php';
with
/**
* Custom walker navigation
*/
require get_template_directory() . '/inc/css-menu-walker.php';
Complete difference here: https://www.diffnow.com/?report=ba2d5
I also had some indentation before <?php at the start of my css-menu-walker.php which I removed. This fixed the problem.

Related

Walker_Nav_Menu() for top level links only

I have a menu in the WordPress backend that looks like this:
What we do
Solutions
Solution 1
Solution 2
Services
Service 1
Contact
Items What we do and Contact are top level links and I only want these level 1 links to show in my main header.
As such, I created a custom walker to achieve this:
<?php
class simple_header extends Walker_Nav_Menu{
/*
* start_lvl : Responsible for start of a new level, such as <ul>
* end_lvl : Responsible for end of a level, such as </ul>
* start_el : Responsible for start of inner element, such as <li>
* end_el : Responsible for end of inner element, such as <\li>
*/
public function start_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat("\t", $depth);
}
public function end_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat("\t", $depth);
}
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[] = $item->ID;
$class_names = 'header__nav-menu-li';
if (in_array('current-menu-item', $classes)) {
$class_names .= ' header__nav-menu-li--active';
}
$class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
if ($depth === 0) {
$output .= $indent . '<li data-test' . $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 : '';
// New
if ($depth === 0) {
$atts['class'] = 'header__nav-menu-anchor link-header';
}
if (in_array('current-menu-item', $item->classes)) {
$atts['class'] .= ' link-header--active';
}
$atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth );
$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 .'>';
/** This filter is documented in wp-includes/post-template.php */
$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 );
}
public function end_el( &$output, $item, $depth = 0, $args = array() ) {
if ($depth === 0) {
$output .= "</li>\n";
}
}
}
?>
However, with the above walker, it still prints out the child markup. The HTML looks like this:
<li class="header__nav-menu-li header__nav-menu-li--active">
What we do
Solutions
Services
</li>
I have defined $depth === 0 in my walker, so unsure why it's printing child links?
Normally, at the start_lvl and end_lvl you would output <ul> and </ul> tags respectively to start and end a new list.
Every item in your menu consists of an anchor tag wrapped inside a list item:
<li>Target</li>
In your code you only have an 'if' statement around the code that adds the list item tags to the output.
On the last line of your start_el function you still add the anchor.
Instead of wrapping an if statement around the parts where you want to output markup, my advice would be to add the following line of code as the first line of your start_el function:
if($depth !== 0) { return; }
That way you skip execution of code for items that are not in the first level.

How can I display the parent menu item's description using Wordpress walkers?

Is there any way to pass a variable from start_el to start_lvl? I want to place the menu description in the wrapper of the submenu items.
class submenu_walker extends Walker_Nav_Menu
{
function start_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat("\t", $depth);
$output .= "\n$indent<ul class='sub-menu'><div class='menu-image-container'><div class='menu-image'></div></div>\n";
}
function end_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat("\t", $depth);
$output .= "$indent<div class='clear'></div></ul>\n";
}
}
I've tried to store the description as a variable in start_el, and access it using global in start_lvl... but it returns nothing.
I'm really desperate for help on this, as so far I've had no results, or responses to this question in terms of answers.
Can someone please help me with this? There are definitely some of you who know how to use the Wordpress walker menu.
Here is the way to use this code and it will display the parent description.
Steps for using of it.
1: Copy the below class and past into the functions.php file.
2: Call the menu like
wp_nav_menu(array(
'menu_id'=>'',
'menu_class'=>'',
'container'=>'',
'theme_location'=>'#enter theme location#',
'walker'=> new customize_menu_walker()
));
<br/>
3:See the result.
class customize_menu_walker extends Walker_Nav_Menu
{
function start_el(&$output, $item, $depth, $args)
{
global $wp_query;
$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
$class_names = $value = '';
// $dbclasses=$item->classes;
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
$dbclasses=$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) );
$class_names = ' class="'. esc_attr( $class_names ) . '"';
$attributes = ! empty( $item->attr_title ) ? ' title="' . esc_attr( $item->attr_title ) .'"' : '';
$attributes .= ! empty( $item->target ) ? ' target="' . esc_attr( $item->target ) .'"' : '';
$attributes .= ! empty( $item->xfn ) ? ' rel="' . esc_attr( $item->xfn ) .'"' : '';
$attributes .= ! empty( $item->url ) ? ' href="' . esc_attr( $item->url ) .'"' : '';
$item_output = $args->before;
//specially for two menu
//specially for two menu
//convert string to array
$dbclassesArr = explode(" ",$dbclasses);
$item_output .= '<a'. $attributes .'>';
if(in_array("menu-item-has-children", $dbclassesArr)){
$description = ! empty( $item->description ) ? '<span>'.esc_attr( $item->description ).'</span>' : '';//description display here.
}
$item_output .= $args->link_before .apply_filters( 'the_title', $item->title, $item->ID );
$item_output .= $description.$args->link_after;
$item_output .= ' '.'</a>';
$item_output .= $args->after;
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
}
Now after updating this function, your menu will show the parent menu description.
Here is the code.
Thanking you.
I have managed to find the solution to this question that seemed to go unanswered for days here - How can I add parent menu description to my Wordpress menu?

Is it possible to create custom menus in WordPress with titles without links?

We are building a theme on WordPress 3.5.1 and we created two custom menus - one for the header and one for the footer. In the footer the titles are not linkable, therefore we created custom links with href "#" and then changed the href to "". The result are empty links with <a>. I know it's possible to change the cursor of these empty links with CSS:
.footer-content #sitemap ul.menu > li.menu-item > a {
cursor: text;
}
and I also found out a way to remove these empty links with JavaScript and jQuery:
$('.footer-content #sitemap ul.menu > li.menu-item > a').each(function() {
// If href is empty, remove <a> element.
var href = $(this).attr('href');
var href_length = 0;
if (!(typeof href === 'undefined')) {
var href_length = href.length;
}
if (href_length === 0) {
var contents = $(this).contents();
$(this).replaceWith(contents);
}
});
(the footer menu is inside the .footer-content #sitemap elements:
<div class="footer-content">
<div id="sitemap" class="not_mobile">
)
but is it possible to remove the empty <a> elements from the HTML without using JavaScript? The function that creates the footer menu is:
<?php wp_nav_menu( array( 'theme_location' => 'footer_menu' ) ); ?>
Thanks,
Uri # Initech.
Yes, It is possible. You can use the walker. Put the following class in your functions.php file
class themeslug_walker_nav_menu extends Walker_Nav_Menu {
// add main/sub classes to li's and links
function start_el( &$output, $item, $depth, $args ) {
global $wp_query;
$indent = ( $depth > 0 ? str_repeat( "\t", $depth ) : '' ); // code indent
// depth dependent classes
$depth_classes = array(
( $depth == 0 ? 'main-menu-item' : 'sub-menu-item' ),
( $depth >=2 ? 'sub-sub-menu-item' : '' ),
( $depth % 2 ? 'menu-item-odd' : 'menu-item-even' ),
'menu-item-depth-' . $depth
);
$depth_class_names = esc_attr( implode( ' ', $depth_classes ) );
// passed classes
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
$class_names = esc_attr( implode( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) ) );
// build html
$output .= $indent . '<li id="nav-menu-item-'. $item->ID . '" class="' . $depth_class_names . ' ' . $class_names . '">';
// link attributes
$attributes = ! empty( $item->attr_title ) ? ' title="' . esc_attr( $item->attr_title ) .'"' : '';
$attributes .= ! empty( $item->target ) ? ' target="' . esc_attr( $item->target ) .'"' : '';
$attributes .= ! empty( $item->xfn ) ? ' rel="' . esc_attr( $item->xfn ) .'"' : '';
$attributes .= ! empty( $item->url ) ? ' href="' . esc_attr( $item->url ) .'"' : '';
$attributes .= ' class="menu-link ' . ( $depth > 0 ? 'sub-menu-link' : 'main-menu-link' ) . '"';
if($depth == 0) {
$item_output = sprintf( '%1$s%2$s%3$s%4$s%5$s',
$args->before,
$args->link_before,
apply_filters( 'the_title', $item->title, $item->ID ),
$args->link_after,
$args->after
);
} else {
$item_output = sprintf( '%1$s<a%2$s>%3$s%4$s%5$s</a>%6$s',
$args->before,
$attributes,
$args->link_before,
apply_filters( 'the_title', $item->title, $item->ID ),
$args->link_after,
$args->after
);
}
// build html
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
}
and add this walker in your wp_nav_menu function
<?php wp_nav_menu( array( 'theme_location' => 'footer_menu', 'walker' => new themeslug_walker_nav_menu ) ); ?>
This will remove the anchor tag <a> from each menu item.
OK, I found a solution. I searched and found out function start_el(...) on class Walker_Nav_Menu, then copied it and changed only the last part of it:
class themeslug_walker_nav_menu extends Walker_Nav_Menu {
/**
* #see Walker::start_el()
* #since 3.0.0
*
* #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. Used for padding.
* #param int $current_page Menu item ID.
* #param object $args
*/
function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
$class_names = $value = '';
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
$classes[] = 'menu-item-' . $item->ID;
$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args ) );
$class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';
$id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args );
$id = $id ? ' id="' . esc_attr( $id ) . '"' : '';
$output .= $indent . '<li' . $id . $value . $class_names .'>';
$attributes = ! empty( $item->attr_title ) ? ' title="' . esc_attr( $item->attr_title ) .'"' : '';
$attributes .= ! empty( $item->target ) ? ' target="' . esc_attr( $item->target ) .'"' : '';
$attributes .= ! empty( $item->xfn ) ? ' rel="' . esc_attr( $item->xfn ) .'"' : '';
$attributes .= ! empty( $item->url ) ? ' href="' . esc_attr( $item->url ) .'"' : '';
$item_output = $args->before;
if (! empty( $item->url )) {
$item_output .= '<a'. $attributes .'>';
}
$item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
if (! empty( $item->url )) {
$item_output .= '</a>';
}
$item_output .= $args->after;
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
}
Then I changed the call to wp_nav_menu on footer.php:
<?php wp_nav_menu( array( 'theme_location' => 'footer_menu', 'walker' => new themeslug_walker_nav_menu ) ); ?>
It works and there are no <a> links when the href is empty (my changes are both ifs: if (! empty( $item->url )) {). Thanks to Mangesh Parte for the idea.
Uri.

How to check if a certain object ID is a page or post (from outside of the page/post itself)

I have a navigation menu loop that uses a custom walker which outputs:
<ul>
<li id="menu-item-2" class="menu-item-object-category">stuff</li>
<li id="menu-item-3" class="menu-item-object-category">stuff</li>
...
etc
And if a page is in the menu, it outputs:
<li id="menu-item-4" class="menu-item-object-page">stuff</li>
</ul>
Clearly wordpress somewhere detects that the entry in the menu is either a category or a page and assigns the appropriate class. How can I run that same check in my walker?
I simply want to do an
If ($item->object_id = page) { // special code}
I tried is_page(), but realized that that is a boolean function to detect if the current page you are on is a page or not.
Is there any easy way of checking each output in a walker for pages?
This is my walker code:
class Custom_Walker extends Walker_Nav_Menu
{
function start_el(&$output, $item, $depth, $args) {
global $wp_query;
$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
$class_names = $value = '';
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) );
$class_names = ' class="' . esc_attr( $class_names ) . '"';
$output .= $indent . '<li id="menu-item-'. $item->ID . '"' . $value . $class_names .'>';
$attributes = ! empty( $item->attr_title ) ? ' title="' . esc_attr( $item->attr_title ) .'"' : '';
$attributes .= ! empty( $item->target ) ? ' target="' . esc_attr( $item->target ) .'"' : '';
$attributes .= ! empty( $item->xfn ) ? ' rel="' . esc_attr( $item->xfn ) .'"' : '';
$attributes .= ! empty( $item->url ) ? ' href="' . esc_attr( $item->url ) .'"' : '';
$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 );
}
}
Thanks
You can use get_post function and check the type, for example:
<?php
$current_post = get_post($current_post_id);
if ($current_post->type == 'post') {
//Do the stuff with post
}
elseif ($current_post->type == 'page') {
//Do the stuff with page
}
else {
//Do the stuff with other post types
}

Wordpress Post ID in wp_nav_menu?

I'm looking to add the post ID to the markup of wp_nav_menu but not sure how to approach it.
I've found this: http://wordpress.org/support/topic/output-the-post-id-of-wp_nav_menu-items
which suggests this, but putting it in my functions.php file doesnt do any thing.
// get menu item's content id
class pages_from_nav extends Walker_Nav_Menu
{
function start_el(&$output, $item, $depth, $args)
{
global $wp_query;
$item_output .= $item->object_id;
$item_output .= ',';
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
}
Any ideas on how I could get the post ID as either a class, an ID or a data attribute?
Have it figured out via some nice chaps on the WP forums.
Needed to create a walker, which is a custo nav structure:
// nav menu walker
class My_Walker extends Walker_Nav_Menu
{
function start_el(&$output, $item, $depth, $args) {
global $wp_query;
$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
$class_names = $value = '';
$classes = empty( $item->classes ) ? array() : (array) $item->classes;
$class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) );
$class_names = ' class="' . esc_attr( $class_names ) . '"';
$output .= $indent . '<li id="menu-item-'. $item->ID . '"' . $value . $class_names .'>';
$attributes = ! empty( $item->attr_title ) ? ' title="' . esc_attr( $item->attr_title ) .'"' : '';
$attributes .= ! empty( $item->target ) ? ' target="' . esc_attr( $item->target ) .'"' : '';
$attributes .= ! empty( $item->xfn ) ? ' rel="' . esc_attr( $item->xfn ) .'"' : '';
$attributes .= ! empty( $item->url ) ? ' href="' . esc_attr( $item->url ) .'"' : '';
$attributes .= ' data-id="'. esc_attr( $item->object_id ) .'"';
$attributes .= ' data-slug="'. esc_attr( basename(get_permalink($item->object_id )) ) .'"';
$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>'; /* This is where I changed things. */
$item_output .= $args->after;
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
}
Then just pass the walker into my menu when I call wp_nav_menu();
<?php
$walker = new My_Walker;
wp_nav_menu(array(
'echo' => true,
'menu' => 4,
'container' => '',
'theme_location' => 'primary',
'menu_class' => 'grid-10 omega',
'walker' => $walker
)); ?>
Seems like this was over complicated. All you really need is url_to_postid(); where the URL you pass will be the link for the menu item.
add_filter('nav_menu_link_attributes', 'menu_post_ids');
function menu_post_ids($val){
$postid = url_to_postid( $val['href'] );
$val['data-postid'] = $postid;
return $val;
}
You could also use this to query data from the post such as a featured image, etc., and further manipulate the menu on the front end using jQuery and whatever post related attributes you added.
add_filter('nav_menu_link_attributes', 'my_menu_images');
function my_menu_images($val){
$postid = url_to_postid( $val['href'] );
$val['data-image'] = get_the_post_thumbnail_url($postid);
return $val;
}

Categories