I have a main navigation and all parents have children.
Eg:
Page A: About Us
child1
child2
Page B : Our services
Child 3
Child 4
I need to include a horizontal sub-menu on a page. But my problem is, if currently we are on page A, all the child items of page A only to be displayed on page.
If we are on Page A, it should looks like:
Page A
Child 1
Child 2
Like this, when we go to Page B, the child of page B only to be displayed.
<?php
$args = array(
'theme_location' => '',
'menu' => '13', //nav menu id, which has about-us as a menu.
'container' => 'div',
'container_class' => '',
'container_id' => '',
'menu_class' => 'menu',
'menu_id' => '',
'echo' => true,
'fallback_cb' => 'wp_page_menu',
'before' => '',
'after' => '',
'link_before' => '',
'link_after' => '',
'items_wrap' => '<ul id="%1$s" class="%2$s">%3$s</ul>',
'depth' => 0,
'walker' => ''
);
$menu_items = wp_nav_menu($args);//wp_get_nav_menu_items(13);
I tried writing above code, which resulted in all the parent items with their children.
Can someone help me on this?
In short, I want to get all the children(sub-menu) of About us menu entry.(i.e. I want child1 & child2 as a list with <a> tags)
Please write this code in theme's functions.php
<?php
// add hook
add_filter( 'wp_nav_menu_objects', 'my_wp_nav_menu_objects_sub_menu', 10, 2 );
// filter_hook function to react on sub_menu flag
function my_wp_nav_menu_objects_sub_menu( $sorted_menu_items, $args ) {
if ( isset( $args->sub_menu ) ) {
$root_id = 0;
// find the current menu item
foreach ( $sorted_menu_items as $menu_item ) {
if ( $menu_item->current ) {
// set the root id based on whether the current menu item has a parent or not
$root_id = ( $menu_item->menu_item_parent ) ? $menu_item->menu_item_parent : $menu_item->ID;
break;
}
}
// find the top level parent
if ( ! isset( $args->direct_parent ) ) {
$prev_root_id = $root_id;
while ( $prev_root_id != 0 ) {
foreach ( $sorted_menu_items as $menu_item ) {
if ( $menu_item->ID == $prev_root_id ) {
$prev_root_id = $menu_item->menu_item_parent;
// don't set the root_id to 0 if we've reached the top of the menu
if ( $prev_root_id != 0 ) $root_id = $menu_item->menu_item_parent;
break;
}
}
}
}
$menu_item_parents = array();
foreach ( $sorted_menu_items as $key => $item ) {
// init menu_item_parents
if ( $item->ID == $root_id ) $menu_item_parents[] = $item->ID;
if ( in_array( $item->menu_item_parent, $menu_item_parents ) ) {
// part of sub-tree: keep!
$menu_item_parents[] = $item->ID;
} else if ( ! ( isset( $args->show_parent ) && in_array( $item->ID, $menu_item_parents ) ) ) {
// not part of sub-tree: away with it!
unset( $sorted_menu_items[$key] );
}
}
return $sorted_menu_items;
} else {
return $sorted_menu_items;
}
}
Then you can display it in your theme using wp_nav_menu (just like you normally would), but also passing in a sub_menu flag to activate the custom sub_menu function:
<?php
wp_nav_menu( array(
'theme_location' => 'primary',
'sub_menu' => true
) );
?>
When on a page you first get all the pages, then you can get the current page ID, get the children in an array and loop through this array like this:
<?php
// First get all the pages in your site
$wp_query = new WP_Query();
$all_pages = $wp_query->query(array('post_type' => 'page'));
// Then get your current page ID and children (out of all the pages)
$current_page_id = get_the_id();
$current_page_children = get_page_children($current_page_id, $all_pages);
// Loop through the array of children pages
foreach ($current_page_children as $child_page) {
// Echo whatever you want from the pages
}
?>
EDIT: This has nothing to do with the structured menus you make in the backend, it has to do with making a page child of another page directly in the page edit section.
This is doing it all
<?php
global $wp_query;
if( empty($wp_query->post->post_parent) ) {
$parent = $wp_query->post->ID;
} else {
$parent = $wp_query->post->post_parent;
} ?>
<?php if(wp_list_pages("title_li=&child_of=$parent&echo=0" )): ?>
<div>
<ul>
<?php wp_list_pages("title_li=&child_of=$parent" ); ?>
</ul>
</div>
<?php endif; ?>
Thanks for all the solutions !
I wrote a function to help with this, since most examples I found include the page children, but not the parent itself. Just add this function to your functions.php file:
<?php
// Display sub menu
function the_sub_menu()
{
global $post;
// Open list
echo '<ul class="sub_menu">';
// Sub page
if($post->post_parent) {
// Load parent
$parent = get_post($post->post_parent);
// Add parent to list
echo '<li>' . $parent->post_title . '</li>';
// Add children to list
wp_list_pages('title_li=&child_of=' . $post->post_parent);
// Parent page
} else {
// Add parent to list
echo '<li class="current_page_item">' . $post->post_title . '</li>';
// Add children to list
wp_list_pages('title_li=&child_of=' . $post->ID);
}
// Close list
echo '</ul>';
}
Then, to use it on a page, simply call it like this:
<?php get_header() ?>
<?php while (have_posts()): the_post() ?>
<!-- Include the sub menu! -->
<?php the_sub_menu() ?>
<article>
<?php the_content() ?>
</article>
<?php endwhile ?>
<?php get_footer() ?>
First thing you need to do is to make your 'child1' 'child2' pages as child pages of 'About Us' page.
Click here to find out more on creating sub pages.
Once you have the pages structured, you can use this function, (link to docs)
<?php wp_list_pages( $args );
$args = array(
'depth' => 0,
'show_date' => '',
'date_format' => get_option('date_format'),
'child_of' => N, //N here should be replaced by your About-us page ID.
'exclude' => '',
'include' => '',
'title_li' => __('About Us'), //here you can mention any title you like for the list that's echoed by this function
'echo' => 1,
'authors' => '',
'sort_column' => 'menu_order, post_title',
'link_before' => '',
'link_after' => '',
'walker' => '',
'post_type' => 'page',
'post_status' => 'publish'
); ?>
Same goes for your 'Our services' page, Hope this resolves your problem. Do let us know if you face any problem & welcome to stackoverflow!
A fast and "dirty" solution.
I have created the following file .../wp-content/plugins/gabriel-submenu.php
With this content:
<?php
/**
* #package Gabriel_SubMenu
* #version 0.1
*/
/*
Plugin Name: Gabriel SubMenu
Plugin URI: http://www.nuage.ch
Description: My plugin to display a submenu
Author: Gabriel Klein
Version: 0.1
Author URI: http://www.nuage.ch
*/
function gab_submenu_content($a) {
$d = array(
'theme_location' => 'main_menu',
'child_of' => $a['id'],
'echo' => false,
'sort_column' => 'menu_order'
);
return wp_nav_menu( $d );
}
add_shortcode('gabsubmenu','gab_submenu_content' );
?>
Then in my posts I have:
[gabsubmenu id=93]
Where id is the id of the parent page.
Custom Menu and its Submenus
function thewebpixel_header_menu(){ ?>
<i class="fa fa-bars"></i>
<ul class="sf-menu fixed" id="menu">
<?php
$args = array(
'order' => 'ASC',
'orderby' => 'menu_order',
'post_type' => 'nav_menu_item',
'post_status' => 'publish',
'output' => ARRAY_A,
'output_key' => 'menu_order',
'nopaging' => true,
'update_post_term_cache' => false );
$items = wp_get_nav_menu_items( 'main', $args );
$parents = array();
foreach($items as $item )
$parents[] = $item->menu_item_parent;
function check_has_child($parents, $menu_id){
if(in_array($menu_id, $parents))
return "YES";
else
return "NO";
}
$flag = 0;
$count = 0;
foreach($items as $item ) { ?>
<?php if( !$item->menu_item_parent ){
if($count != 0 && $count != 5 && $flag == 2){
echo '</ul></div></div></li>';
$count=0;
$flag=0;
}
if(check_has_child($parents, $item->ID ) == "YES")
{
$liclass = '';
$aclass = 'class="sf-with-ul"';
}else{
$liclass = 'dropdown';
$aclass = '';
}
?>
<li class="<?php echo $liclass; ?>"><a <?php echo $aclass; ?> href="<?php echo $item->url;?>"><span><?php echo
$item->title;?></span></a>
<?php } ?>
<?php if( $item->menu_item_parent){ if($flag != 2)$flag = 1; ?>
<?php if($flag == 1) {
$flag = 2;
echo '<div class="sf-mega">';
}
if($count == 0 ){
echo '<div class="sf-mega-section"><ul>';
}
$count++;
?>
<li><a href="<?php echo $item->url; ?>">
<i class="fa fa-angle-right"></i>
<?php echo $item->title; ?>
</a>
</li>
<?php
if($count == 5){
echo '</ul></div>';
$count=0;
}
} ?>
<?php if( !$item->menu_item_parent && check_has_child($parents, $item->ID ) == "NO" ){ ?></li> <?php } ?>
<?php } ?>
</ul>
<?php } ?>
Find more information and examples at https://developer.wordpress.org/reference/functions/wp_get_nav_menu_items/ .
Related
I want to create a custom HTML sitemap using wp_nav_menu() because this function has the exact structure I want to display. It works, but the only problem I have is with some parent pages that are only used to display child pages. They have '#' as a link. So I want to display the title of these parent pages without the link.
This is the code I have so far. Maybe I'm completely wrong.
<?php
$webpages = wp_nav_menu( array(
'items_wrap' => '%3$s',
'menu' => 'Menu principal',
'container' => 'div',
'container_class' => 'pages-container',
'post_status' => 'publish'
) );
if ( $webpages ) {
$permalink = get_permalink();
foreach ( $webpages as $page ) :
setup_postdata( $page ); ?>
<li> <?php
if ($permalink === '#') {
echo strip_tags($permalink,'a');
}
else {
//'' . the_title(); '';
$permalink;
}
?> </li>
<?php
endforeach;
wp_reset_postdata();
}
?>
Any help or advise is greatly appreciated!
Thanks!
I need help with combining these two codes:
this:
<?php wp_nav_menu(
array(
'theme_location' => 'primary',
'container_class' => 'collapse navbar-collapse',
'container_id' => 'navbarNavDropdown',
'menu_class' => 'navbar-nav',
'fallback_cb' => '',
'menu_id' => 'main-menu',
'walker' => new rorentrep_WP_Bootstrap_Navwalker(),
)
);
?>
and this (from https://www.minddevelopmentanddesign.com/blog/showing-current-pages-parents-sub-menu-items-custom-nav-menu-wordpress/):
<?php
$section_id = empty( $post->ancestors ) ? $post->ID : end( $post->ancestors );
$locations = get_nav_menu_locations();
$menu = wp_get_nav_menu_object( $locations[ 'primary' ] ); // 'primary' is our nav menu's name
$menu_items = wp_get_nav_menu_items( $menu->term_id, array( 'post_parent' => $section_id ) );
if( !empty( $menu_items ) ) {
echo '<ul class="section-submenu">';
foreach( $menu_items as $menu_item ) {
echo '<li>' . $menu_item->title . '</li>';
}
echo '</ul>';
}
?>
More precisely, I want the links that the second code echoes to appear as the first code.
The structure of my pages are like this:
Business
- Sub page a
- Sub page b
- Sub page c
Private
- Sub page x
- Sub page y
- Sub page z
Whenever I visit a child's page of Business I want the menu to only list Sub page a-c, and when I visit a child's page of Private I want the menu to only list Sub page x-z.
As multiple pages can be added, I do not want to target specific page id's.
The main reason for this is for the output code to wrap and nest like wp_nav_menu using walker bootstrap nav (adding current-classes to nav-items).
In your walker class, you can set the behavior for each level. Then check the depth in the element method: start_el
class Footer extends \Walker_Nav_Menu
{
function start_el(&$output, $item, $depth = 0, $args = array(), $id = 0)
{
if ($depth == 0) {
$output .= '
<li class="list-inline-item">
<a href="' . $item->url . '" title="' . $item->title . '">
' . $item->title . '
</a>
</li>';
}
}
function start_lvl( &$output, $depth = 0, $args = array() ) {
$output.= '';
}
function end_lvl( &$output, $depth = 0, $args = array() ) {
$output.= '';
}
}
I have the following navigational structure in WordPress:
Page
Sub Page
Child Page
Child Page
Child Page
Page
Sub Page
Child Page
Child Page
Child Page
Page
Sub Page
Child Page
Child Page
Child Page
On each Sub Page and Child Page, I want to display the following in the sidebar:
Sub Page
Child Page
Child Page
Child Page
The closest I've come to this is the following code from here:
<ul>
<?php
global $post;
$current_page_parent = ( $post->post_parent ? $post->post_parent : $post->ID );
wp_list_pages( array(
'title_li' => '',
'child_of' => $current_page_parent,
'depth' => '1' )
);
?>
</ul>
However, on Sub Pages it only shows a list of all Sub Pages (without Child Pages) and on Child Pages, it displays a list of Child Pages of that section but the parent Sub Page title is missing.
How do I modify to achieve what I'm looking for?
Thanks!
Yes, you are right this is not showing parent page on child or sub for that you may use following code.
<?php if ( $post->post_parent ) {
$children = wp_list_pages( array(
'title_li' => '',
'child_of' => $post->post_parent,
'echo' => 0
) );
$title = get_the_title( $post->post_parent ); } else {
$children = wp_list_pages( array(
'title_li' => '',
'child_of' => $post->ID,
'echo' => 0
) );
$title = get_the_title( $post->ID );} if ( $children ) : ?>
<h2><?php echo $title; ?></h2>
<ul>
<?php echo $children; ?>
</ul>
Mukesh Ram's code is working, just missing the final ENDIF
<?php if ( $post->post_parent ) {
$children = wp_list_pages( array(
'title_li' => '',
'child_of' => $post->post_parent,
'echo' => 0
) );
$title = get_the_title( $post->post_parent ); } else {
$children = wp_list_pages( array(
'title_li' => '',
'child_of' => $post->ID,
'echo' => 0
) );
$title = get_the_title( $post->ID );} if ( $children ) : ?>
<h2><?php echo $title; ?></h2>
<ul>
<?php echo $children; ?>
</ul>
<?php endif; ?>
I'm currently using this code (per the codex) to show children on parent pages, and children of the parent pages on their children:
<?php if($post->post_parent)
$children = wp_list_pages("title_li=&child_of=".$post->post_parent."&echo=0");
else
$children = wp_list_pages("title_li=&child_of=".$post->ID."&echo=0");
if ($children) { ?>
<ul>
<?php echo $children; ?>
</ul>
<?php } ?>
I would like to add that if on a secondary child page (child's child) to then show it's parent and parent's siblings.
Thank you for your help! :D
<?php
if($post->post_parent)
{
//get the parent post
$parent = get_post($post->post_parent);
//check to see if we have a grandparent
if($parent->post_parent)
{
$page_list = wp_list_pages( array( 'child_of' => $parent->post_parent, 'echo' => false, 'depth' => 1 ) );
}
else
{
$page_list = wp_list_pages( array( 'child_of' => $post->post_parent, 'echo' => false, 'depth' => 1 ) );
}
}
else
$page_list = wp_list_pages( array( 'child_of' => $post->ID, 'echo' => false, 'depth' => 1 ) );
if ($page_list) {
?>
<ul>
<?php echo $page_list; ?>
</ul>
<?php } ?>
This will check if the post has a parent and then if that post has a parent. The $page_list should be a list of pages of the parent and its siblings. the 'depth' => 1 tells WordPress to only get one level of pages. This will stop it from getting the children of those pages
I am working on a Wordpress-Design and i want to creat a Custom Menu.
$items = wp_get_nav_menu_items('Menu', array(
'order' => 'ASC',
'orderby' => 'menu_order',
'post_type' => 'nav_menu_item',
'post_status' => 'publish',
'output' => ARRAY_A,
'output_key' => 'menu_order',
'nopaging' => true,
'update_post_term_cache' => false));
echo '<pre>'; print_r($items); echo '</pre>';
foreach($items as $item){
echo '<div class="menu_entry">'.$item->title.'</div>';
}
The problem is, i need the "current-page"-Class, which is WordPress creating - in the Standard Menu.
Any Ideas how to add this class?
Solution time:
WordPress's function that adds these classes is _wp_menu_item_classes_by_context(). This is called already when you use wp_nav_menu but not wp_get_nav_menu_items. Fortunately, the latter provides a filter so we can do it ourselves:
add_filter( 'wp_get_nav_menu_items', 'prefix_nav_menu_classes', 10, 3 );
function prefix_nav_menu_classes($items, $menu, $args) {
_wp_menu_item_classes_by_context($items);
return $items;
}
You can do a compare on the current page / cat etc ID against the menu items object_id which is the ID of the page / category etc its linked to.
Something like (untested);
global $post;
$thePostID = $post->ID;
foreach($items as $item){
if($thePostID === $item->object_id) {
echo '<div class="menu_entry">'.$item->title.'</div>';
}else{
echo '<div class="menu_entry">'.$item->title.'</div>';
}
}
Using the function get_queried_object_id(). This works fine in all the pages, including the Blog page.
See an example:
if ( $menu_items = wp_get_nav_menu_items( 'menu' ) ) {
foreach ( $menu_items as $menu_item ) {
$current = ( $menu_item->object_id == get_queried_object_id() ) ? 'current' : '';
echo '<li class="' . $current . '">' . $menu_item->title . '</li>';
}
}