I am trying to output Wordpress' navigation menu items along with their CSS Classes.
I was able to get the menu items, but the classes are more complicated. the css classes come in an array but it's already inside a foreach() loop.
$menu_items = wp_get_nav_menu_items($menu->term_id);
$menu_list = '<ul id="menu-' . $menu_name . '">';
foreach ( (array) $menu_items as $key => $menu_item ) {
$title = $menu_item->title;
$url = $menu_item->url;
$classes = $menu_item->classes;
$menu_list .= '<li>';
$menu_list .= '<i class=""></i>';
$menu_list .= '' . $title . '';
$menu_list .= '</li>';
}
$menu_list .= '</ul>';
As you can see, inside the foreach() loop I am getting the $title and $url which are both strings. But then when I try to get the css classes associated with the menu item through $menu_item->classes it returns an array and I am not sure how to do this.
Because each menu item has 3 css classses fa fa-user fa-3x I can return the values using this
$classes[0] . $classes[1] . $classes[2]
But suppose I don't want the third class and I leave it out empty, I get a missing offset error.
I also tried doing a foreach within the original foreach
$menu_list .= '<li>';
foreach($classes as $class) {
$menu_list .= '<i class="'. $class .'"></i>';
}
$menu_list .= '' . $title . '';
$menu_list .= '</li>';
But this returns 3 separate <i> tags for each menu item, which is not what I want. The output looks like this
<i class="fa"></i>
<i class="fa-user"></i>
<i class="fa-3x"></i>
Simply use a nested Loop in place like so:
<?php
$menu_items = wp_get_nav_menu_items($menu->term_id);
$menu_list = '<ul id="menu-' . $menu_name . '">';
foreach ( (array) $menu_items as $key => $menu_item ) {
$title = $menu_item->title;
$url = $menu_item->url;
$classes = $menu_item->classes;
$comboClass = "";
// USING NESTED LOOP CONSTRUCT
foreach($classes as $class){
$comboClass .= $class . " "; // SEPARATE CLASS-NAME WITH A SPACE
}
$menu_list .= '<li>';
$menu_list .= '<i class="' .$comboClass . '"></i>';
$menu_list .= '' . $title . '';
$menu_list .= '</li>';
}
$menu_list .= '</ul>';
You can nest loops...
foreach(...) {
... html stuff ..
echo '<div class="';
foreach($classes as $class) {
echo $class, ' ';
}
echo '">...</div>';
}
Related
I've searched for hours and cannot come up with what I thought would be a simple thing. I am building my very first Wordpress site locally. I'm making a function for my functions.php file based on this howto but I need it to have submenus. I have created a custom menu inside Wordpress with 2 levels.
I need to add HTML code (not a CSS class) to an item if it is a parent item.
Bonus points if you can tell me how people know what attributes/properties are available to a menu item (such as title and url) - I can't find a reference to that anywhere!
Here is my current code, which is currently displaying all menu items as top-level items.
function clean_custom_main_menu() {
$menu_name = 'main-menu'; // specify custom menu slug
$menu_list = '<ul id="menu">' ."\n";
if ($menu_items = wp_get_nav_menu_items($menu_name)) {
$count = 0;
$submenu = false;
foreach ((array) $menu_items as $key => $menu_item) {
$title = $menu_item->title;
$url = $menu_item->url;
$classes = $menu_item->classes; // does not work
$has_children = $menu_item->has_children; //does not work
$parent_id = 0;
// check if this item is a parent item with children
//if ( $menu_item->menu_item_parent && $menu_item->menu_item_parent > 0 ) {
//if(in_array('menu-item-has-children', $classes)){
if ($has_children) {
$parent_id = $menu_item->ID;
}
// if this item has a parent ID, it's a second-level item
if ($parent_id != 0 && $parent_id == $menu_item->menu_item_parent ) {
$submenu = true;
}
if (!$has_children) {
// if this item has no submenu, write top-level code
$menu_list .= "\t". '<li>'. $title .'</li>' ."\n";
}
// the "else" is not currently being hit
//else {
// $menu_list .= "\t" . '<li>' . $title . '<span class="arrow-down"></span></li>' . "\n";
// $menu_list .= '<ul class="sub">';
// // foreach (child) do children
// $menu_list .= '</ul>';
// $menu_list .= '</li>';
//}
}
} else {
$menu_list .= '<!-- no list defined -->';
}
$menu_list .= "\t". '</ul>' ."\n";
echo $menu_list;
}
Desired output:
<ul id="menu">
<li>Home</li>
<li>
About <span class="arrow-down"></span>
<ul class="sub">
<li>Our Services</li>
<li>What We Do</li>
</ul>
</li>
<li>
Top-Level Item
</li>
<li>Top-Level Item with Children <span class="arrow-down"></span>
<ul class="sub">
<li>Sub Item 1</li>
<li>Sub Item 2</li>
<li>Sub Item 3</li>
<li>Sub Item 4</li>
</ul>
</li>
<li>Contact</li>
</ul>
Please note: I do not want to use walkers. I am certain it can be done somehow since I had this working at one point, but lost everything when Wordpress decided to update the theme I made - to a totally different one from web-land, erasing all my files. D'oh!
It turns out that people have contributed how to build items with submenus right on the Wordpress documentation for the function I was using, wp_get_nav_menu_items(). Those got me started but they weren't exactly quite right, since I had the extra span tags and wanted to close my A tags in different places, but I was able to ultimately get things working. Here is my final code based on those comments:
function clean_custom_main_menu() {
$menu_name = 'main-menu'; // specify custom menu slug
$menu_list = '<ul id="menu">' ."\n";
if ($menu_items = wp_get_nav_menu_items($menu_name)) {
$count = 0;
$submenu = false;
$parent_id = 0;
$previous_item_has_submenu = false;
foreach ((array) $menu_items as $key => $menu_item) {
$title = $menu_item->title;
$url = $menu_item->url;
// check if it's a top-level item
if ($menu_item->menu_item_parent == 0) {
$parent_id = $menu_item->ID;
// write the item but DON'T close the A or LI until we know if it has children!
$menu_list .= "\t". '<li><a href="'. $url .'">'. $title;
}
// if this item has a (nonzero) parent ID, it's a second-level (child) item
else {
if ( !$submenu ) { // first item
// add the dropdown arrow to the parent
$menu_list .= '<span class="arrow-down"></span></a>' . "\n";
// start the child list
$submenu = true;
$previous_item_has_submenu = true;
$menu_list .= "\t\t" . '<ul class="sub">' ."\n";
}
$menu_list .= "\t\t\t" . '<li>';
$menu_list .= ''.$title.'';
$menu_list .= '</li>' ."\n";
// if it's the last child, close the submenu code
if ( $menu_items[ $count + 1 ]->menu_item_parent != $parent_id && $submenu ){
$menu_list .= "\t\t" . '</ul></li>' ."\n";
$submenu = false;
}
}
// close the parent (top-level) item
if (empty($menu_items[$count + 1]) || $menu_items[ $count + 1 ]->menu_item_parent != $parent_id )
{
if ($previous_item_has_submenu)
{
// the a link and list item were already closed
$previous_item_has_submenu = false; //reset
}
else {
// close a link and list item
$menu_list .= "\t" . '</a></li>' . "\n";
}
}
$count++;
}
} else {
$menu_list .= '<!-- no list defined -->';
}
$menu_list .= "\t". '</ul>' ."\n";
echo $menu_list;
}
API
Try doing var_dump( $menu_items ) and you'll see that the menu items are posts of post_type "nav_menu_item" so they have the same api as post.
Count Children
https://wordpress.stackexchange.com/questions/9374/get-the-post-children-count-of-a-post shows a way of accessing child post count using $wpdb. You could do this with get_posts by setting the parent_id to the parent item and post_type to nav_menu_item and then count the results.
Classes
The post object has a classes array. Since this wasn't working for you, I'd double check how you are trying to access/use that array and if that doesn't help, try investigating the walker functions for help with your custom implementation.
I need to get currently active menu item (menu title like Home, About us, etc..) on each page in wordpress. I am using wordpress codes to display menu & it displayed correctly. Code is shown below,
$menu_name = 'primary';
if ( ( $locations = get_nav_menu_locations() ) && isset( $locations[ $menu_name ] ) )
{
$menu = wp_get_nav_menu_object( $locations[ $menu_name ] );
$menu_items = wp_get_nav_menu_items($menu->term_id);
$menu_list = '<ul id="menu-' . $menu_name . '" class="nav navbar-nav" style="width:100%;">';
foreach ( (array) $menu_items as $key => $menu_item )
{
$title = $menu_item->title;
$url = $menu_item->url;
$menu_list .= '<li class="menu-line">' . $title . '</li>';
}
$menu_list .= '</ul>';
} else {
$menu_list = '<ul><li>Menu "' . $menu_name . '" not defined.</li></ul>';
}
echo $menu_list;
But I am not able to identify which menu item is active now.
Any help appreciated!
update your code like this and add your css as per your requirement.
<?php
$menu_name = 'primary';
if ( ( $locations = get_nav_menu_locations() ) && isset( $locations[ $menu_name ] ) )
{
$menu = wp_get_nav_menu_object( $locations[ $menu_name ] );
$menu_items = wp_get_nav_menu_items($menu->term_id);
$menu_list = '<ul id="menu-' . $menu_name . '" class="nav navbar-nav" style="width:100%;">';
foreach ( (array) $menu_items as $key => $menu_item )
{
$title = $menu_item->title;
$url = $menu_item->url;
$active = '';
$actual_link = "http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
if($url == $actual_link)
{
$active = 'active';
}
else
{
$active = '';
}
$menu_list .= '<li class="menu-line">' . $title . '</li>';
}
$menu_list .= '</ul>';
} else {
$menu_list = '<ul><li>Menu "' . $menu_name . '" not defined.</li></ul>';
}
echo $menu_list;
?>
CSS as below
<style>
.active { border:1px solid #f00;}
</style>
It work fine for my code.
I have this code that produces a horizontal menu in wordpress. However, it produces invalid code because the html tags aren't closed. I have tried adding the closing tags in the loop but seems to mess up the menu bad.
foreach ( (array) $menu_items as $key => $menu_item ) {
$tiny_menu_list .= '<option value="'. $menu_item->url .'">'. $menu_item->title .'</option>';
if( !$menu_item->menu_item_parent ){
$menu_list .= '<li><div>' . $menu_item->title . '';
if( count($menu_items) > 1 )
$menu_list .= '<span>';
continue;
}
$menu_list .= '|' . $menu_item->title . '';
}
if( count($menu_items) > 1 )
$menu_list .= '</span>';
$menu_list .= '</div></li></ul>';
Here is what the code generates:
<li><div>Home Page
<span><li><div>About Us
<span>|Why Us ?|Compare Us
<li><div>Take A Tour
<span>|Frequently Asked Questions
<li><div>Free Options Videos
<span><li><div>Options Courses
<span>|Extended Options Course|Ultimate Options Course</span></span></div></li></ul>
As you can tell, each li & span & div are not closed. Thankfully browsers correct for this, but for the sake of being html5 compliant, could use the help in fixing it.
This is not due to html tags, this is happening because you are missing many closing </div> and </li> .
On formatting the code dumped by your loop it shows up like this:
<li>
<div>
Home Page</li>
<span>
<li>
<div>
About Us
<span>|Why Us ?|Compare Us
<li>
<div>
Take A Tour
<span>|Frequently Asked Questions
<li>
<div>
Free Options Videos
<span>
<li><div>Options Courses
<span>|Extended Options Course|Ultimate Options Course</span></span></div></li></ul>
You can check the error by pasting this code in html validator like this one
And it will show you the missing elements.
Maybe, you can try close your tags in the foreach-loop. Maybe like this:
$hasChildLinks = false
foreach ( (array) $menu_items as $key => $menu_item ) {
$tiny_menu_list .= '<option value="'. $menu_item->url .'">'. $menu_item->title .'</option>';
if( !$menu_item->menu_item_parent ){
$menu_list .= '<li><div>' . $menu_item->title . '';
if( count($menu_items) > 1 ) {
$menu_list .= '<span>'
$hasChildLinks = true;
} else {
$menu_list .= '</div></li>';
}
continue;
}
$menu_list .= '|' . $menu_item->title . '';
if( (count($menu_items) > 1) && ($hasChildLinks) ) {
$menu_list.= '</span>';
}
}
$menu_list .= '</ul>';
Hello I have a script that displays all categories in wordpress menu but I want to add subcategories to this menu too. How I can check if categories have subcategories then display them in submenu of category.
$items .= '<ul class="sub-menu">';
$categories = get_categories();
foreach ($categories as $category) {
$option = '<li><a href="'.get_category_link( $category->term_id ).'">';
$option .= $category->cat_name;
$option .= '</a></li>';
$items .= $option;
}
$items .= '</ul></li>';
get_categories() only fetches categories and subcategories those are assigned to any post(s) unless you pass array("hide_empty"=>0) as parameter to fetch inactive categories/subcategories too
try below
$items .= '<ul class="sub-menu">';
$categories = get_categories(array("hide_empty"=>0,'parent'=> '0'));
foreach ($categories as $category) {
$childrens = get_categories(array('child_of'=>$category->term_id,"hide_empty"=>0));
$subitems ='';
if(count($childrens)>0){
$subitems .= '<ul class="sub-menu">';
foreach($childrens as $children){
$opt = '<li><a href="'.get_category_link($children->term_id ).'">';
$opt .= $children->cat_name;
$opt .= '</a></li>';
$subitems .= $opt;
}
$subitems.= '</ul></li>';
}
$option = '<li><a href="'.get_category_link( $category->term_id ).'">';
$option .= $category->cat_name;
$option .= '</a>'.$subitems.'</li>';
$items .= $option;
}
$items .= '</ul></li>';
I know its a dirty way. Don't use "hide_empty"=>0 unless you really need it
I found a post on this site to add a custom "mytheme_list_pages" to the functions.php file in order to add the title attribute to a link. While this works to add the title attribute to the "href" output, it no longer preserves the order of the menu as wp_list_pages does. Can someone tell me how to order the output of the custom code below?
I'm calling the function from my page.php file like this:
<?php mytheme_list_pages('exclude=819&title_li='); ?>
The custom function below:
<?php
function mytheme_list_pages($param) {
$pages = get_pages($param);
foreach ( $pages as $page ) {
$li = '<li><a href="' . get_page_link( $page->ID ) . '" title="';
$li .= esc_attr($page->post_title);
$li .= '">';
$li .= $page->post_title;
$li .= '</a></li>';
echo $li;
}
}
?>
Many thanks!
Here is updated code,
<?php mytheme_list_pages('exclude=819&title_li=&sort_column=menu_order'); ?>
<?php
function mytheme_list_pages($param) {
$pages = get_pages($param);
foreach ( $pages as $page ) {
$li = '<li><a href="' . get_page_link( $page->ID ) . '" title="';
$li .= esc_attr($page->post_title);
$li .= '">';
$li .= $page->post_title;
$li .= '</a></li>';
echo $li;
}
}
?>
for more information http://codex.wordpress.org/Function_Reference/get_pages