Reputation: 934
Is it possible to make a custom structure for the Wordpress main navigation? I want to integrate Semantic-UI with my website but Semantic-UI uses divs and links for the menu structure but Wordpress uses lists. I found a way to remove the UL tags but now I'm stuck with the LI tags.
I would like to make my menu look something like this: Home
<a class="item">
<i class="mail icon"></i> Messages
</a>
<a class="item">
<i class="user icon"></i> Friends
</a>
<div class="right menu">
<div class="item">
<div class="ui icon input">
<input type="text" placeholder="Search...">
<i class="search link icon"></i>
</div>
</div>
<a class="ui item">
Logout
</a>
</div>
</div>
URL: http://semantic-ui.com/collections/menu.html It is the eleventh menu.
Upvotes: 1
Views: 1271
Reputation: 2544
If you want your Wordpress menu with sub menus in Semantic UI structure, you can use the following code.
Put the code to your template file, where the menu should be displayed.
You just need to adjust your Menu ID (if you hover the "delete menu" link in wordpress, it will be displayed in the URL).
You can also adapt the code for other Semantic UI menus.
<?php
$menuID = 'your menu ID';
$primaryNav = wp_get_nav_menu_items($menuID);
<div class="ui secondary vertical menu">
<?php
$count = 0;
$submenu = false;
foreach( $primaryNav as $item ) {
$link = $item->url;
$title = $item->title;
// item does not have a parent
if ( !$item->menu_item_parent ) {
$parent_id = $item->ID; ?>
<?php } ?>
<?php // item is parent of next element ?>
<?php if ( $parent_id == $item->menu_item_parent ) { ?>
<?php if ( !$submenu ) {
$submenu = true; ?>
<div class="ui dropdown item"><i class="dropdown icon"></i><?php echo get_the_title($parent_id); ?><div class="menu">
<?php } ?>
<a href="<?php echo $link; ?>" class="item"><?php echo $title; ?></a>
<?php if ( $primaryNav[ $count + 1 ]->menu_item_parent != $parent_id && $submenu ) { ?>
</div> <!-- menu --> </div> <!-- item -->
<?php $submenu = false;
} ?>
<?php }
else { // item is not parent of next element ?>
<?php if ( !$primaryNav[ $count + 1 ]->menu_item_parent ) { ?>
<a href="<?php echo $link; ?>" class="item"><?php echo $title; ?></a>
<?php } ?>
<?php } ?>
<?php $count++;
} ?>
</div> <!-- menu -->
?>
Upvotes: 1
Reputation: 351
I made an improvement to Adrian Z.'s answer.
It depends on these classes. I used composer
to load them into the code.
At the end of functions.php
, I placed:
/**
* @property \Onimla\SemanticUI\Menu $menu
* @property \Onimla\SemanticUI\Container $container
* @property array $items
* @property WP_Post $wp_menu_items
*/
class Semantic_UI_Menu
{
/**
* Sub menus
* @var array
*/
public $sub = array();
/**
* @see https://stackoverflow.com/a/25242681/437459
* @param string $menu_name
*/
public function __construct($menu_name, $horizontal = true)
{
require_once substr(__DIR__, 0, strrpos(__DIR__, DIRECTORY_SEPARATOR)) . DIRECTORY_SEPARATOR . 'vendor/autoload.php';
$locations = get_nav_menu_locations();
if ($locations && isset($locations[$menu_name])) {
$menu_object = wp_get_nav_menu_object($locations[$menu_name]);
$menu_items = wp_get_nav_menu_items($menu_object->term_id);
$this->wp_menu_items = array_combine(array_column(json_decode(json_encode($menu_items), true), 'ID'), $menu_items);
$this->items = array();
foreach (new ArrayIterator($this->wp_menu_items) as $menu_item) {
/* @var $menu_item WP_Post */
$is_home = $menu_item->post_name == 'home' and $menu_item->post_title = 'Home';
/* Instâncias =============================================================== */
$item = new \Onimla\SemanticUI\Menu\Item($menu_item->title, $menu_item->url, $menu_item->attr_title);
/* Atributos ================================================================ */
if (strlen($menu_item->target) > 0) {
$item->target($menu_item->target);
}
if ($menu_item->url == get_permalink()) {
$item->setActive();
}
/* Árvore =================================================================== */
$this->home_item($menu_item, $item);
/* Exibição ================================================================= */
$this->submenu($menu_item, $item, $horizontal);
}
/* Instâncias =============================================================== */
$this->container = new \Onimla\SemanticUI\Container($this->items);
$this->menu = new \Onimla\SemanticUI\Menu;
/* Atributos ================================================================ */
#$this->menu->pointing();
$this->menu->large();
/* Árvore =================================================================== */
$this->menu->container = $this->container;
} else {
$this->menu = new \Onimla\SemanticUI\Message\Error\WithWarningSign("Menu \"{$menu_name}\" não encontrado.");
}
}
public function __toString()
{
return "{$this->menu}";
}
/**
* @param WP_Post $menu_item
* @param \Onimla\SemanticUI\Menu\Item $sui_item
*/
protected function home_item($menu_item, &$sui_item)
{
if ($menu_item->url == esc_url(home_url('/'))) {
$sui_item->text($menu_item->title == 'Home' ? __('Home', 'josb2017') : $menu_item->title);
$sui_item->prepend(new \Onimla\SemanticUI\Icon\Home);
if (is_home()) {
$sui_item->setActive();
}
}
}
/**
*
* @param WP_Post $menu_item
* @param \Onimla\SemanticUI\Menu\Item $sui_item
* @return \Onimla\SemanticUI\Content\Item|\Onimla\SemanticUI\Menu\Item\Dropdown
*/
protected function submenu($menu_item, &$sui_item, $horizontal = true)
{
$parent_id = (int) $menu_item->menu_item_parent;
if ($parent_id == '0') {
$this->items[$menu_item->ID] = $sui_item;
return $sui_item;
}
if (key_exists($parent_id, $this->sub)) {
$this->sub[$parent_id]->append($sui_item);
return $this->sub[$parent_id];
} else {
unset($this->items[$parent_id]);
/* @var $parent WP_Post */
$parent = $this->wp_menu_items[$parent_id];
/* Instâncias =============================================================== */
$dropdown = new \Onimla\SemanticUI\Menu\Item\Dropdown($parent->title);
$group = new \Onimla\SemanticUI\Menu\Item\Group();
/* Atributos ================================================================ */
if (strlen($parent->attr_title) > 0) {
$dropdown->title($parent->attr_title);
}
/* Árvore =================================================================== */
$dropdown->append($sui_item);
$group->setHeader($parent->title);
$group->append($sui_item);
/* Exibição ================================================================= */
$result = $horizontal ? $dropdown : $group;
$this->items[$parent_id] = $result;
$this->sub[$parent_id] = $result;
unset($this->items[$menu_item->ID]);
return $result;
}
return false;
}
}
/**
* @param string $menu_name
*/
function wp_get_nav_sui_menu($menu_name, $horizontal = true)
{
$sui_menu = new Semantic_UI_Menu($menu_name, $horizontal);
return $sui_menu->menu;
}
function wp_nav_sui_menu($menu_name, $horizontal = true)
{
echo wp_get_nav_sui_menu($menu_name, $horizontal);
}
The code was tested using two levels. I didn't have time to code more levels.
Also, you have to run JavaScript to activate dropdowns:
$('.ui.dropdown.item').dropdown({on: 'hover'});
Upvotes: 1
Reputation: 934
I have updated your suggestion and it looks like this:
/** Custom Semantic-UI menu */
function wp_nav_semantic_menu($show){
$menu_name = 'semantic-menu';
$locations = get_nav_menu_locations();
if ( $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 = '<div id="menu-' . $menu_name . '" class="ui secondary pointing menu">';
foreach ( (array) $menu_items as $key => $menu_item ) {
$title = $menu_item->title;
$url = $menu_item->url;
$menu_list .= '<a class="item" href="'. $url .'">';
$menu_list .= $title;
$menu_list .= '</a>';
}
$menu_list .= '</div>';
}else{
$menu_list = '<div class="ui red message">Menu "'. $menu_name .'" not defined.</div>';
}
if($show){
echo $menu_list;
}
}
This works just fine but there are a few things that I would like to add to this. If you look at the default wp_nav_menu() output it looks like this:
<li
id="menu-item-10"
class=" menu-item
menu-item-type-post_type
menu-item-object-page
menu-item-10">
<a
href="http://127.0.0.1/htdocs/?page_id=9">
Page
</a>
</li>
Is there a variable that I can add to my id and class within my custom function to add all those page information classes?
Upvotes: 2
Reputation: 8877
Yes. You need to use wp_get_nav_menu_items function to grab the menu object, and you can then loop through and build the menu however you wish.
The example taken from the documentation:
// Get the nav menu based on $menu_name (same as 'theme_location' or 'menu' arg to wp_nav_menu)
// This code based on wp_nav_menu's code to get Menu ID from menu slug
$menu_name = 'custom_menu_slug';
if ( ( $locations = get_registered_nav_menus() ) && in_array( $menu_name, $locations ) ) {
$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 . '">';
foreach ( (array) $menu_items as $key => $menu_item ) {
$title = $menu_item->title;
$url = $menu_item->url;
$menu_list .= '<li><a href="' . $url . '">' . $title . '</a></li>';
}
$menu_list .= '</ul>';
} else {
$menu_list = '<ul><li>Menu "' . $menu_name . '" not defined.</li></ul>';
}
// $menu_list now ready to output
Upvotes: 1