I read wordpress code documents about how to iterate menu items, and then I wrote this code in index.php:
<?php
$menu_name = 'top_menu';
$array_menu = wp_get_nav_menu_items($menu_name);
foreach ((array)$array_menu as $mol) ;
{
echo $mol;
}
?>
But it doesn't work. And is returning nothing. Casting to array didn't help so.
I need to echo items menu title one by one. without any html list tags.
$navItem is an object, so you can not just echo it, try to echo its properties like this:
foreach ($array_menu as $navItem ) {
echo '<li>'.$navItem->title.'</li>';
}
This might help:
<?php
function get_menu_items_by_registered_slug($menu_slug) {
$menu_items = array();
if ( ( $locations = get_nav_menu_locations() ) && isset( $locations[ $menu_slug ] ) ) {
$menu = get_term( $locations[ $menu_slug ] );
$menu_items = wp_get_nav_menu_items($menu->term_id);
}
return $menu_items;
}
$show_menus = [];
$menus = get_menu_items_by_registered_slug('primary');
foreach( $menus as $menu ) {
$show_menus[] = $menu->title;
}
echo '<pre>';
print_r($show_menus);
?>
Related
I am trying to create a list of all links in primary navigation on my WordPress site. I am trying to output the link as URL: in a script tag using a foreach loop.
I am stuck trying to list of of the navitems links using $navItem->url in my foreach loop. It doesn't return anything / false.
Instead of $locations[$menuLocations] I have tried simply just write primary menu name as well: $locations['primary'] but no luck so far.
function get_nav_menu_items_by_location( $location, $args = [] ) {
$html = '<script type="application/ld+json" alt="hejtest">';
// Get all locations
$menuLocations = get_nav_menu_locations();
// Get object id by location
$object = wp_get_nav_menu_object( $locations[$menuLocations] );
// Get menu items by menu name
$menu_items = wp_get_nav_menu_items($object);
foreach ( $menu_items as $navItem ) {
$html .= '"url":"' . $navItem->url . '"';
}
$html .= "</script>";
echo $html;
}
add_action('wp_head', 'get_nav_menu_items_by_location');
Well... I did a refactor of your code and it's works ;)
Try with this way:
function get_nav_items() {
$menu_slug_to_retrieve = 'main'; // This can be main, primary, what ever...
$locations = get_nav_menu_locations();
$menu = wp_get_nav_menu_object( $locations[ $menu_slug_to_retrieve ] );
$menu_items = wp_get_nav_menu_items( $menu->term_id );
$menu_items_json = array(); // Prepare the array to convert to json
// Loop it
if ( $menu_items ) {
foreach ( $menu_items as $item ) {
$menu_items_json[] = array( 'url' => $item->url );
}
$html = sprintf(
'<script type="application/ld+json" id="custom-json">%s</script>',
json_encode( $menu_items_json )
);
echo $html;
}
}
add_action( 'wp_head', 'get_nav_items' );
Regards!
I got a ACF Reaper field with a couple of rows I am trying to show. However, I only want the show row if it has a checkbox checked (Checkbox is a subfield within the repeater). I am trying to accomplish that by using if in_array as described in ACF documentation under "Conditional logic":
if( in_array( "bestyrelsevalg", get_sub_field( 'bestyrelse' ) ) )
I am outputting the result in a WordPress shortcode. For now, my code kinda works, except it shows all results within the repeater field (also those that are unchecked). What am I missing ??
My code:
function investor_bestyrelse_shortcode() {
$rows = get_field('budgetter_og_nyhedsbreve');
if( $rows ) {
echo '<ul class="slides">';
foreach( $rows as $row ) {
if( in_array( "bestyrelsevalg", get_sub_field( 'bestyrelse' ) ) ) {
$image = $row['upload_dokument'];
echo '<li>';
echo get_field( 'upload_dokument' );
echo '</li>';
}
}
echo '</ul>';
}
}
add_shortcode( 'investor_bestyrelse', 'investor_bestyrelse_shortcode' );
Managed to solve issue and with the help from #maggiathor's answer. For some reason echo was causing issue. I had to use return insted:
function investor_bestyrelse_shortcode() {
$rows = get_field('budgetter_og_nyhedsbreve');
if( $rows ) {
$content = '<ul class="dokumenter">';
foreach( $rows as $row ) {
if( !in_array( "bestyrelsevalg", $row['bestyrelse'] ) ) {
$pdf = $row['upload_dokument'];
$content = $content . '<li>' . $pdf . '</li>';
}
}
}
$content = $content . '</ul>';
return $content;
}
add_shortcode( 'investor_bestyrelse', 'investor_bestyrelse_shortcode' );
You cannot use get_sub_field() within the foreach loop, either you need to use a have_rows-while-loop or access it from the associative array:
function investor_bestyrelse_shortcode() {
$rows = get_field('budgetter_og_nyhedsbreve');
if( $rows ) {
echo '<ul class="slides">';
foreach( $rows as $row ) {
if( in_array( "bestyrelsevalg", $row['bestyrelse'] ) ) {
$image = $row['upload_dokument'];
echo '<li>';
echo $row['upload_dokument'];
echo '</li>';
}
}
echo '</ul>';
}
}
add_shortcode( 'investor_bestyrelse', 'investor_bestyrelse_shortcode' );
I have a 3 level navigation:
Home
> submenu1
>> sub3
> submenu
>> sub4
>> sub5 // current page
About
> about2
>> sub6
> about3
>> sub7
I am trying to get each navigation level separately,
With the example nav above, being on the sub5 page, I would need
Current 1st level nav: Home
Current parallel 2nd level nav: submenu1, submenu (who are both under Home)
Current parallel 3rd level nav: sub4, sub5 (who are menu under submenu)
I will need to modify the elements and styles of the menu and will need to work with menu items in php, such as:
$menu_name = 'topnav';
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);
foreach ( (array) $menu_items as $key => $menu_item ) {
$title = $menu_item->title;
$url = $menu_item->url;
[...]
Please help getting the navigation layers separately to show up as explained above.
I got the 1st and 3rd level working, but can't get the current parallel 2nd level nav to show up correctly.
Thanks.
Current Code: 2nd nav works:
<?php
$menu_name = 'topnav';
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 );
// Convert Objects to Arrays, Enables us to use Array Filter
$json = json_encode($menu_items);
$menu_items = json_decode($json, true);
// Current Page
$child = get_the_id();
$current_level = array_filter( $menu_items, function($v, $k) use ($child) {
return $v['object_id'] == $child;
}, ARRAY_FILTER_USE_BOTH );
$current_level_keys = array_keys($current_level);
$parent = $current_level[$current_level_keys[0]]['menu_item_parent'];
if( !empty( $parent ) )
{
$current_level_items = array_filter( $menu_items, function($v, $k) use ($parent) {
return $v['menu_item_parent'] == $parent;
}, ARRAY_FILTER_USE_BOTH );
} else {
$current_level_items = $current_level[$current_level_keys[0]];
}
//echo '1:';
//echo '<pre>';
//print_r($current_level_items);
//echo '</pre>';
//foreach ($current_level_items as $k => $v) {
// echo '<li>'.$v['title'].'</li>';
//}
$parent_level = array_filter( $menu_items, function($v, $k) use ($parent) {
return $v['ID'] == $parent;
}, ARRAY_FILTER_USE_BOTH );
$parent_level_keys = array_keys($parent_level);
$grand_parent = $parent_level[$parent_level_keys[0]]['menu_item_parent'];
if( !empty( $grand_parent ) )
{
$parent_level_items = array_filter( $menu_items, function($v, $k) use ($grand_parent) {
return $v['menu_item_parent'] == $grand_parent;
}, ARRAY_FILTER_USE_BOTH );
} else {
$parent_level_items = $parent_level[$parent_level_keys[0]];
}
//echo '2:';
//echo '<pre>';
//print_r($parent_level_items);
//echo '</pre>';
//foreach ($parent_level_items as $k => $v) {
//echo '<li>'.$v['title'].'</li>';
//}
$grand_parent_level = array_filter( $menu_items, function($v, $k) use ($grand_parent) {
return $v['ID'] == $grand_parent;
}, ARRAY_FILTER_USE_BOTH );
$grand_parent_level_keys = array_keys($grand_parent_level);
$great_grand_parent = $grand_parent_level[$grand_parent_level_keys[0]];
if( !empty( $parent ) ) {
if( !empty( $great_grand_parent ) ) {
echo '<li class="custom-page-title">'.$great_grand_parent['title'].'</li>';
if (is_array($parent_level_items)) {
foreach ($parent_level_items as $k => $v) {
echo '<li>'.$v['title'].'</li>';
}
}
} else {
echo '<li class="custom-page-title">'.$parent_level_items['title'].'</li>';
if (is_array($current_level_items)) {
foreach ($current_level_items as $k => $v) {
echo '<li>'.$v['title'].'</li>';
}
}
}
}
//echo '3:';
//echo '<pre>';
//print_r($great_grand_parent);
//echo '</pre>';
}
?>
However if there are duplicate (3rd level) pages in the menu, this script only takes the first parent... Could it be the last or the real parent (from url path maybe?)
Duplicate page in menu issue:
Home
> submenu1
>> sub3
> submenu
>> sub4
>> sub5 // current page
About
> about2
>> sub6
> about3
>> sub7
>> sub5 // duplicate page
When visiting the duplicate page (sub5), the parent returned is the first one (Home > submenu), when it should be (About > about3)
Please help getting this fixed...
Edit:
To address the duplicate situation you have to add a line of code. You can add one of the below lines based on the parent chain you want to select. I am also adding these lines in the actual code to show you where they go.
// Get First Parent Chain
$current_level = array_values(array_slice($current_level, 0, 1));
// Get Last Parent Chain
$current_level = array_values(array_slice($current_level, -1, 1));
Original Answer: ( Also updated with the above lines )
This code will give you all levels items, it is written for only three levels as per your requirements but you can use the logic and reiterate the code to as many levels as needed, or better yet write up something recursive.
$menu_name = 'topnav';
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 );
// Convert Objects to Arrays, Enables us to use Array Filter
$json = json_encode($menu_items);
$menu_items = json_decode($json, true);
// Current Page
$child = get_the_id();
$current_level = array_filter( $menu_items, function($v, $k) use ($child) {
return $v['object_id'] == $child;
}, ARRAY_FILTER_USE_BOTH );
// Get First Parent Chain ( Uncomment below line if you want to use this )
//$current_level = array_values(array_slice($current_level, 0, 1));
// Get Last Parent Chain ( Uncomment below line if you want to use this )
//$current_level = array_values(array_slice($current_level, -1, 1));
$current_level_keys = array_keys($current_level);
$parent = $current_level[$current_level_keys[0]]['menu_item_parent'];
if( !empty( $parent ) )
{
$current_level_items = array_filter( $menu_items, function($v, $k) use ($parent) {
return $v['menu_item_parent'] == $parent;
}, ARRAY_FILTER_USE_BOTH );
} else {
$current_level_items = $current_level[$current_level_keys[0]];
}
echo '<pre>';
print_r($current_level_items);
echo '</pre>';
$parent_level = array_filter( $menu_items, function($v, $k) use ($parent) {
return $v['ID'] == $parent;
}, ARRAY_FILTER_USE_BOTH );
$parent_level_keys = array_keys($parent_level);
$grand_parent = $parent_level[$parent_level_keys[0]]['menu_item_parent'];
if( !empty( $grand_parent ) )
{
$parent_level_items = array_filter( $menu_items, function($v, $k) use ($grand_parent) {
return $v['menu_item_parent'] == $grand_parent;
}, ARRAY_FILTER_USE_BOTH );
} else {
$parent_level_items = $parent_level[$parent_level_keys[0]];
}
echo '<pre>';
print_r($parent_level_items);
echo '</pre>';
$grand_parent_level = array_filter( $menu_items, function($v, $k) use ($grand_parent) {
return $v['ID'] == $grand_parent;
}, ARRAY_FILTER_USE_BOTH );
$grand_parent_level_keys = array_keys($grand_parent_level);
$great_grand_parent = $grand_parent_level[$grand_parent_level_keys[0]];
echo '<pre>';
print_r($great_grand_parent);
echo '</pre>';
}
I have tried to write it as self explanatory, but if you have any questions i will be happy to help.
I would like to know how to retrieve as variable the name of the current page.
For exemple, My menu is like :
Item 1
Item 2 => sub-item 1
Item 1 & 2 are custom links. sub-item1 is my page.
When I'm on this page, I want to retrieve "Item 2" name (to build my custom breadcumbs)
Thanks
BREADCRUMBS:
Here is a breadcrumbs function that work with the hierarchy of your menu. Add this to your theme's 'functions.php'.
function my_menu_breadcrumb($theme_location, $separator = ' > ') {
$locations = get_nav_menu_locations();
if ( isset( $locations[ $theme_location ] ) ) {
$menu = wp_get_nav_menu_object( $locations[ $theme_location ] );
$menu_items = wp_get_nav_menu_items($menu->term_id);
_wp_menu_item_classes_by_context( $menu_items );
$breadcrumbs = array();
foreach ( $menu_items as $menu_item ) {
if ($menu_item->current) {
$breadcrumbs[] = "<span title=\"{$menu_item->title}\">{$menu_item->title}</span>";
}
else if ($menu_item->current_item_ancestor) {
$breadcrumbs[] = "{$menu_item->title}";
}
}
echo implode($separator, $breadcrumbs);
}
}
You can then call as <?php my_menu_breadcrumb('header-menu'); ?> where 'header-menu' is the menu location name. In the loop, $menu_item->title will return page title and $menu_item->url it's URL.
PARENT MENU TITLE:
Here is the function to get parent menu item title(s) of current page - add this to your theme's 'functions.php'.
function my_menu_parent($theme_location) {
$locations = get_nav_menu_locations();
if ( isset( $locations[ $theme_location ] ) ) {
$menu = wp_get_nav_menu_object( $locations[ $theme_location ] );
$menu_items = wp_get_nav_menu_items($menu->term_id);
_wp_menu_item_classes_by_context( $menu_items );
$breadcrumbs = array();
foreach ( $menu_items as $menu_item ) {
if ($menu_item->current_item_ancestor) {
$breadcrumbs[] = $menu_item->title;
}
}
return $breadcrumbs;
}
}
You can then call as below where 'header-menu' is the menu location name.
$parentitems = my_menu_parent( 'header-menu' );
foreach ( $parentitems as $parentitem ) {
echo $parentitem."<br>";
}
You can user this
$pagename = get_query_var('pagename');
if ( !$pagename && $id > 0 ) {
// If a static page is set as the front page, $pagename will not be set. Retrieve it from the queried object
$post = $wp_query->get_queried_object();
$pagename = $post->post_name;
}
There are plenty of tutorials and code snippets online describing how to show the active page’s children (or if on one of those children, the active page’s siblings) as a sub-menu in WordPress. Usually something like this:
<?php
$ref_post = empty($post->post_parent) ? $post->ID : $post->post_parent;
$children = wp_list_pages('title_li=&child_of='.$ref_post.'&echo=0');
if ($children) {
echo "<ul>$children</ul>";
}
?>
for ref:-https://www.minddevelopmentanddesign.com/blog/showing-current-pages-parents-sub-menu-items-custom-nav-menu-wordpress/
I am having some trouble with my WordPress navigation functionality. I have the following function that pulls menu items from the admin:
function cr_get_menu_items($menu_location)
{
$locations = get_nav_menu_locations();
$menu = get_term($locations[$menu_location], 'nav_menu');
return wp_get_nav_menu_items($menu->term_id);
}
In my navigation template, I use this function to pull in only parent items like this:
<?php $nav = cr_get_menu_items('navigation_menu') ?>
<?php foreach ($nav as $link):
if ($link->menu_item_parent == 0) : ?>
<a class="main-nav" href="<?= $link->url ?>"><?= $link->title ?></a>
<?php endif; endforeach; ?>
I tried to make a sub navigation that shows children items like this:
<?php $nav = cr_get_menu_items('navigation_menu') ?>
<?php foreach ($nav as $link):
if ($link->menu_item_parent !== 0) : ?>
<?= $link->title ?>
<?php endif; endforeach; ?>
This pulls in ALL children menu items. The way the navigation I am building should work is: you click on a parent menu item and the sub navigation displays all child menu items for that parent. The hide/display functionality is all JS.
Is there a way to alter the function I have to pull in only children for a specific parent menu item? Any help/guidance is appreciated.
Is there a way to alter the function I have to pull in only children
for a specific parent menu item?
For that purpose, yes, there is.
Try the following function (replace the existing cr_get_menu_items() function):
function cr_get_menu_items($menu_location, $parent = -1)
{
$locations = get_nav_menu_locations();
$menu = get_term($locations[$menu_location], 'nav_menu');
$items = wp_get_nav_menu_items($menu->term_id);
if ( is_numeric( $parent ) && $parent >= 0 ) {
$_id = (int) $parent;
foreach ( $items as $i => $item ) {
if ( $_id !== (int) $item->menu_item_parent ) {
unset( $items[ $i ] );
}
}
}
return $items;
}
Usage examples:
$nav = cr_get_menu_items( 'navigation_menu' ); // Get all menu items.
$nav = cr_get_menu_items( 'navigation_menu', 0 ); // Get menu items whose parent ID is 0
UPDATE
After I re-read your question, this is the function that you likely need:
// $items is the menu items array that you retrieved using `cr_get_menu_items()`,
// or other functions which return valid `nav_menu` items.
function cr_get_submenu_items( array $items, $parent ) {
$parent = (int) $parent;
$list = [];
foreach ( $items as $item ) {
if ( $parent === (int) $item->menu_item_parent ) {
$list[] = $item;
}
}
return $list;
}
UPDATE #2
Here's how you would/could use cr_get_menu_items() along with cr_get_submenu_items():
<?php $nav = cr_get_menu_items('navigation_menu') ?>
<!-- Display parent items. -->
<?php $nav = cr_get_menu_items('navigation_menu') ?>
<?php foreach ($nav as $link):
if ($link->menu_item_parent == 0) : ?>
<a class="main-nav" href="<?= $link->url ?>"><?= $link->title ?></a>
<?php endif; endforeach; ?>
<!-- Display children items. (in its own wrapper `div`/`ul`/etc.) -->
<?php $_ids = []; ?>
<?php foreach ($nav as $link):
$parent = (int) $link->menu_item_parent;
if ( 0 !== $parent && ! in_array( $parent, $_ids ) ) : ?>
<!-- This `div` is just an example wrapper. -->
<div class="menu-<?= $parent ?>-subnav">
<?php foreach ( cr_get_submenu_items( $nav, $parent ) as $clink ): ?>
<?= $clink->title ?>
<?php endforeach; ?>
<?php $_ids[] = $link->menu_item_parent; ?>
</div>
<?php endif; endforeach; ?>