I am trying to add sequential numbering after each link in a menu in wordpress. They should be in tag and as a text. so i can style.
Tried this one below but since its CSS, I can't style those numbers.
How to add sequential numbering for wordpress menu
I've got no knowledge of JS. so I did this in navwalker.php
if(! empty( $item->attr_title )){
$item_output .= '<a'. $attributes .'><i class="' . esc_attr( $item->attr_title ) . '"></i> ';
} else {
$item_output .= '<a'. $attributes .'>';
}
$item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
$item_output .= ($args->has_children && $depth == 0) ? ' <span class="caret"></span></a>' : '</a>';
$item_output .= $args->after . '<span class="navnum">' . str_pad(esc_attr( $item->menu_order ), 2, "0", STR_PAD_LEFT) . '.</span>';
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
}
And it works.
Only problem it counts childs (submenus) in a collapsable menu, so it creates something like this:
01
03
04
07
08
Any idea about how to number only parents?
(If solution is JS I would appreciate if you explain it very simple)
If what you are trying to do is number only the top-level menu, you can just test for depth.
Change:
$item_output .= $args->after . '<span class="navnum">' . str_pad(esc_attr( $item->menu_order ), 2, "0", STR_PAD_LEFT) . '.</span>';
to:
$item_output .= $args->after . ($depth == 0 ? '<span class="navnum">' . str_pad(esc_attr( $item->menu_order ), 2, "0", STR_PAD_LEFT) : '') . '.</span>';
To number the menu items sequentially, set up your own global counter when a new level starts:
public function start_lvl( &$output, $depth = 0, $args = array() ) {
if (!isset($_GLOBALS['menu_counter'])) {
$GLOBALS['menu_counter'] = array();
}
$GLOBALS['menu_counter'][$depth] = 0;
$indent = str_repeat("\t", $depth);
$output .= "\n$indent<ul class=\"sub-menu\">\n";
}
Then in start_el:
public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
global $menu_counter;
....
and in the code example you gave in your question:
$item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
$item_output .= ($args->has_children && $depth == 0) ? ' <span class="caret"></span></a>' : '</a>';
$item_output .= $args->after . '<span class="navnum">' . str_pad(++$menu_order[$depth], 2, "0", STR_PAD_LEFT) . '.</span>';
What this does is set a variable, starting at zero, when you set a new level. Then, for each item at that level, it adds one to that variable and uses the result as the number of the menu item.
Related
I've created a custom WordPress menu using the WordPress walker function. I've managed to do all the necessary HTML I need except adding the top-level menu title to just after one of the divs in the "start_lvl" section in the function.
Output should look like this:
<ul>
<li>Title
<div class="mega-menu">
<div class="mega-menu-inner">
<h2 class="fz-40">DISPLAY TOP MENU TITLE HERE</h2>
<ul class="mega-menu-accordion-wrap">
<li class="mega-menu-accordion">
<div class="mega-menu-accordion-inner">
<ul>
<li>
<div class="sub-mega-menu-wrap">
<ul>
<li></li>
</ul>
</div>
</li>
</ul>
</div>
</li>
</ul>
</div>
</div>
</li>
</ul>
This is what I have so far for the WP nav walker:
wp_nav_menu( array(
'theme_location' => "header-menu",
'walker' => new WPDocs_Walker_Nav_Menu() ) );
/**
* Custom walker class.
*/
class WPDocs_Walker_Nav_Menu extends Walker_Nav_Menu {
/**
* Starts the list before the elements are added.
*
* Adds classes to the unordered list sub-menus.
*
* #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()
*/
function start_lvl( &$output, $depth = 0, $args = array() ) {
// Depth-dependent classes.
$indent = ( $depth > 0 ? str_repeat( "\t", $depth ) : '' ); // code indent
$display_depth = ( $depth + 1); // because it counts the first submenu as 0
$classes = array(
'sub-menu',
( $display_depth % 2 == 0 ? 'menu-odd' : 'mega-menu-accordion-wrap' ),
( $display_depth >=2 ? 'sub-sub-menu' : '' ),
'menu-depth-' . $display_depth
);
$class_names = implode( ' ', $classes );
// Build HTML for output.
if( $display_depth === 1):
global $title;
$output .= '<div class="mega-menu">';
$output .= '<div class="mega-menu-container-wrap">';
$output .= '<div class="mega-menu-help-bar"><figure> <img src="'.get_template_directory_uri().'/svg/search-white.svg" alt=""></figure>Need some help?</div>';
$output .= '<div class="mega-menu-inner">';
$output .= '<h2 class="fz-40">Need the Title Here''</h2>';
$output .= "\n" . $indent . '<ul class="' . $class_names . '">' . "\n";
elseif( $display_depth % 3 === 0):
$output .= "\n" . $indent . '<div class="sub-mega-menu-wrap">' . "\n";
$output .= "\n" . $indent . '<ul class="' . $class_names . '">' . "\n";
elseif( $display_depth % 2 === 0):
$output .= "\n" . $indent . '<div class="mega-menu-accordion-inner">' . "\n";
$output .= "\n" . $indent . '<ul class="' . $class_names . '">' . "\n";
else:
$output .= "\n" . $indent . '<ul class="' . $class_names . '">' . "\n";
endif;
}
/**
* Start the element output.
*
* Adds main/sub-classes to the list items and links.
*
* #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 array $args An array of arguments. #see wp_nav_menu()
* #param int $id Current item ID.
*/
function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
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 == 0 ? 'menu-item-odd' : 'mega-menu-accordion' ),
'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.
if( $depth % 2 === 0):
$output .= $indent . '<li id="nav-menu-item-'. $item->ID . '" class="' . $depth_class_names . ' ' . $class_names . ' ">';
else:
$output .= $indent . '<li id="nav-menu-item-'. $item->ID . '" class="' . $depth_class_names . ' ' . $class_names . '">';
endif;
// 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' ) . '"';
// Build HTML output and pass through the proper filter.
$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
);
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
}
Solved this shortly after my post,
for anyone who requires this, I did the following:
Add this to the functions.php file:
function add_menu_title( $item_output, $item, $depth, $args ) {
global $menuTitle;
$menuTitle = $item->title;
return $item_output;
}
add_filter( 'walker_nav_menu_start_el', 'add_menu_title', 10, 4);
Then in your header template just add this to the section you would like it display. In my example I updated the depth===1 to the following:
if( $display_depth === 1):
global $menuTitle;
$output .= '<div class="mega-menu">';
$output .= '<div class="mega-menu-container-wrap">';
$output .= '<div class="mega-menu-help-bar"><figure> <img src="'.get_template_directory_uri().'/svg/search-white.svg" alt=""></figure>Need some help?</div>';
$output .= '<div class="mega-menu-inner">';
$output .= '<h2 class="fz-40">'.$menuTitle.'</h2>';
$output .= "\n" . $indent . '<ul class="' . $class_names . '">' . "\n";
I want to add numbers in front of each item in my Wordpress Menu.
01 Home
02 About
03 Portfolio
04 Contact
etc.
I know you have to use a walker but I haven't been able to get the counter to work right.
<?php
class my_nav_walker extends Walker {
// Tell Walker where to inherit it's parent and id values
var $db_fields = array(
'parent' => 'menu_item_parent',
'id' => 'db_id'
);
function start_lvl( &$output, $depth = 0, $args = array() ) {
if (!isset($_GLOBALS['menu_counter'])) {
$GLOBALS['menu_counter'] = array();
}
$GLOBALS['menu_counter'][$depth] = 0;
$indent = str_repeat("\t", $depth);
$output .= "\n$indent<ul class=\"sub-menu\">\n";
}
/**
* At the start of each element, output a <li> and <a> tag structure.
*
* Note: Menu objects include url and title properties, so we will use those.
*/
function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
global $menu_counter;
$item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
$item_output .= ($args->has_children && $depth == 0) ? ' <span class="caret"></span></a>' : '</a>';
$item_output .= $args->after . '<span class="navnum">' . str_pad(++$menu_order[$depth], 2, "0", STR_PAD_LEFT) . '.</span>';
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}
}
This what I tried to piece together from others.
This out puts:
Home01 About01 Portfolio01 Contact01
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.
I wanted to add number of posts for menu items that are categories.
For example:
Category 1 (5)
Category 2 (8)
Category 3 (2)
etc...
I edit walker:
get number:
$item_count = $depth == 0 ? get_posts( array(
'post_type' => 'post',
'numberposts' => -1,
'orderby' => 'category',
'order' => 'ASC'
) ) : false;
output:
$item_output .= $item_count ? ' <span>(' . count( $item_count ) . ')</span>' : '';
The result is a postscript to each menu item the number of all posts.
How to modify?
use wp_list_categories
<?php wp_list_categories(array('show_count' => true)); ?>
UPDATE for your instance:
with the full code from the link you provided in the comments we add an if statement right before the closing <a>
if($item->type == 'taxonomy'){
$cat = get_category( $item->object_id);
$item_output .= ' ('.$cat->count.')</a>';
}
FULL CODE:
/* Bootstrap_Walker for Wordpress
* Author: George Huger, Illuminati Karate, Inc
* More Info: http://illuminatikarate.com/blog/bootstrap-walker-for-wordpress
*
* Formats a Wordpress menu to be used as a Bootstrap dropdown menu (http://getbootstrap.com).
*
* Specifically, it makes these changes to the normal Wordpress menu output to support Bootstrap:
*
* - adds a 'dropdown' class to level-0 <li>'s which contain a dropdown
* - adds a 'dropdown-submenu' class to level-1 <li>'s which contain a dropdown
* - adds the 'dropdown-menu' class to level-1 and level-2 <ul>'s
*
* Supports menus up to 3 levels deep.
*
*/
class Bootstrap_Walker extends Walker_Nav_Menu
{
/* Start of the <ul>
*
* Note on $depth: Counterintuitively, $depth here means the "depth right before we start this menu".
* So basically add one to what you'd expect it to be
*/
function start_lvl(&$output, $depth)
{
$tabs = str_repeat("\t", $depth);
// If we are about to start the first submenu, we need to give it a dropdown-menu class
if ($depth == 0 || $depth == 1) { //really, level-1 or level-2, because $depth is misleading here (see note above)
$output .= "\n{$tabs}<ul class=\"dropdown-menu\">\n";
} else {
$output .= "\n{$tabs}<ul>\n";
}
return;
}
/* End of the <ul>
*
* Note on $depth: Counterintuitively, $depth here means the "depth right before we start this menu".
* So basically add one to what you'd expect it to be
*/
function end_lvl(&$output, $depth)
{
if ($depth == 0) { // This is actually the end of the level-1 submenu ($depth is misleading here too!)
// we don't have anything special for Bootstrap, so we'll just leave an HTML comment for now
$output .= '<!--.dropdown-->';
}
$tabs = str_repeat("\t", $depth);
$output .= "\n{$tabs}</ul>\n";
return;
}
/* Output the <li> and the containing <a>
* Note: $depth is "correct" at this level
*/
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;
/* If this item has a dropdown menu, add the 'dropdown' class for Bootstrap */
if ($item->hasChildren) {
$classes[] = 'dropdown';
// level-1 menus also need the 'dropdown-submenu' class
if($depth == 1) {
$classes[] = 'dropdown-submenu';
}
}
/* This is the stock Wordpress code that builds the <li> with all of its attributes */
$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;
/* If this item has a dropdown menu, make clicking on this link toggle it */
if ($item->hasChildren && $depth == 0) {
$item_output .= '<a'. $attributes .' class="dropdown-toggle" data-toggle="dropdown">';
} else {
$item_output .= '<a'. $attributes .'>';
}
$item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
/* Output the actual caret for the user to click on to toggle the menu */
if ($item->hasChildren && $depth == 0) {
$item_output .= '<b class="caret"></b></a>';
}elseif($item->type == 'taxonomy'){
$cat = get_category( $item->object_id);
$item_output .= ' ('.$cat->count.')</a>';
} else {
$item_output .= '</a>';
}
$item_output .= $args->after;
$output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
return;
}
/* Close the <li>
* Note: the <a> is already closed
* Note 2: $depth is "correct" at this level
*/
function end_el (&$output, $item, $depth, $args)
{
$output .= '</li>';
return;
}
/* Add a 'hasChildren' property to the item
* Code from: http://wordpress.org/support/topic/how-do-i-know-if-a-menu-item-has-children-or-is-a-leaf#post-3139633
*/
function display_element ($element, &$children_elements, $max_depth, $depth = 0, $args, &$output)
{
// check whether this item has children, and set $item->hasChildren accordingly
$element->hasChildren = isset($children_elements[$element->ID]) && !empty($children_elements[$element->ID]);
// continue with normal behavior
return parent::display_element($element, $children_elements, $max_depth, $depth, $args, $output);
}
}
If you are using some custom post taxonomie you can change the code for this one :
if ($item->type == 'taxonomy'){
$term = get_term($item->object_id);
$item_output .= '<div class="meni-item-badge"> '.$term->count .'</div>';
}
Hope this help someone !!
Regards Mario
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;
}