Dynamic Menu Builder for Bootstrap 3: Item and Link

Share this article

In part 1, we prototyped the end product and wrote the main Menu class, which serves as the menu manager – a container to hold all sub-units (items and links). In this part, we’ll build the remainder of the classes and demonstrate the menu builder’s usage.

Item

Represents our menu items as independent objects.

Create a new file called item.php and paste in the following code:

item.php

class Item {
	
	protected $manager;
	protected $id;
	protected $pid;
	protected $meta;
	protected $attributes = array();
	
	public    $link;
	
	//...
  • $manager stores a reference to the menu manager (Menu object). This makes us able to use menu manager methods within Item context.
  • $id stores the item’s id.
  • $pid stores item’s parent id if it has one otherwise it’ll be set to null.
  • $meta an array for storing extra data with each item.
  • $attributes an array of HTML attributes.
  • $link stores an instance of class Link.

__construct(manager, title, url, attributes, pid)

Initializes the attributes.

public function __construct($manager, $title, $url, $attributes = array(), $pid = 0)
{
	$this->manager     = $manager;
	$this->id          = $this->id();
	$this->pid         = $pid;
	$this->title       = $title;
	$this->attributes  = $attributes;
	
	// Create an object of type Link
	$this->link        = new Link($title, $url);
}

add(title, options)

Class Item has an add() method as well (just like the menu manager). In fact this method doesn’t create items on its own. It gets the arguments, adds a pid key to $options and calls add() of the menu manager.

public function add($title, $options)
{
	if( !is_array($options) ) {
			$options = array('url' => $options);
		}
		
	$options['pid'] = $this->id;
				
	return $this->manager->add( $title, $options );
}

This gives us the power to create sub items in a more semantic way rather than explicitly defining a pid:

$menu = new Menu;
	
	$about = $menu->add('About', 'about');
	
	// We write it this way
	$about->add('What we do?', 'what-we-do');
	
	// instead of:
	// $menu->add('What we do?', array('url' => 'what-we-do', 'pid' => $about->get_id()));

id()

Generates a unique id for the Item. We use this identifier to refer to the item later.

protected function id()
{
	return $this->manager->length() + 1;
}

In fact id() calls length() of the menu manager and increments it by 1.

get_id()

We also need to create a getter method to return the id when needed:

public function get_id()
{
	return $this->id;
}

get_pid()

Items might have pid (parent’s id). pid value might be null or id of another item.

Items with pid set to null are the items at root level.

We need to create a getter to return Item’s pid as well:

public function get_pid()
{
	return $this->pid;
}

hasChildren()

Checks whether the item has any children or not.

public function hasChildren()
{
	return (count($this->manager->whereParent($this->id))) ? true : false;
}

It calls whereParent() via the manager.

children()

Fetches children of the item.

public function children()
{
	return $this->manager->whereParent($this->id);
}

attributes(key, value)

Gets or sets item’s attributes.

public function attributes()
{
	$args = func_get_args();

	if(is_array($args[0])) {
		$this->attributes = array_merge($this->attributes, $args[0]);
		return $this;
	}
	
	elseif(isset($args[0]) && isset($args[1])) {
		$this->attributes[$args[0]] = $args[1];
		return $this;
	} 
	
	elseif(isset($args[0])) {
		return isset($this->attributes[$args[0]]) ? $this->attributes[$args[0]] : null;
	}
	
	return $this->attributes;	
}

As you see attributes() returns different types of results according to the arguments given:

  • Sets attribute if both $key and $value given.
  • Sets array of attributes if $key is an array.
  • Gets attribute if only $key given.
  • Gets all attributes if no argument given.

meta($key, $value)

Meta stores extra data about the item. It can be any kind of data from placement order to required permissions.

public function meta()
{
	$args = func_get_args();

	if(is_array($args[0])) {
		$this->meta = array_merge($this->meta, $args[0]);
		return $this;
	}
	
	elseif(isset($args[0]) && isset($args[1])) {
		$this->meta[$args[0]] = $args[1];
		return $this;
	} 
	
	elseif(isset($args[0])) {
		return isset($this->meta[$args[0]]) ? $this->meta[$args[0]] : null;
	}
	
	return $this->meta;
}

meta() works exactly like attributes().

Now let’s move on to the Link class.

Class Link is a simple class consisting of several getter and setter methods.

Link has three attributes:

  • text link text
  • url link URL
  • attributes link attributes

link.php

class Link {
	
	public $text;
	public $url;
	public $attributes;

	//....

__construct(text, url, attributes)

When we create an object of type Link, the constructor method binds the arguments to the attributes listed above:

public function __construct($text, $url, $attributes = array())
{
	$this->text = $text;
	
	$this->url = $url;
	
	$this->attributes = $attributes;
}

string get_url()

Returns link url.

public function get_url()
{
	return $this->url;
}

string get_text()

Returns the link text

public function get_text()
{
	return $this->text;
}

You’ll encounter situations when you need to append or prepend some content to the anchor text like a caret sign for drop-downs or a graphical icon. To achieve this, we will create two simple functions that do just the thing for us.

append(content)

append adds content to the link text:

public function append($content)
{
	$this->text .= $content;
	
	return $this;
}

prepend(content)

prepend prepends content to the link:

public function prepend($content)
{
	$this->text = $content . $this->text;
	
	return $this;
}

attributes(key, value)

Like Items It would be fantastic if we could define HTML attributes for anchors.

public function attributes($key = null, $value = null)
{
	$args = func_get_args();

	if(is_array($args[0])) {
		$this->attributes = array_merge($this->attributes, $args[0]);
		return $this;
	}
	
	elseif(isset($args[0]) && isset($args[1])) {
		$this->attributes[$args[0]] = $args[1];
		return $this;
	} 
	
	elseif(isset($args[0])) {
		return isset($this->attributes[$args[0]]) ? $this->attributes[$args[0]] : null;
	}
	
	return $this->attributes;
}

I think this method is familiar to you since we’ve created it earlier.

With this, our Menu Builder is complete!

Usage

We usually create one PHP file per class definition, so, to use our menu builder we need to include each file at the beginning of our script.

Rather than including all the three files, I’m going to take advantage of class autoloading feature in PHP: __autoload(string $class). This feature helps us avoid writing a long list of includes at the beginning of each script.

__autoload() is automatically called in case you are trying to use a class or interface which hasn’t been defined yet.

__autoload receives the class name as argument.

This is how we’re going to use it:

function __autoload($class) {
	require_once(strtolower($class) . '.php');
}

Name this file autoload.php and include it in your script.

Please note that this is probably less than ideal. In a real project, your autoloading needs would be taken care of by Composer or the framework’s autoloader. You can see this on the Github link we provided – the project is fully developed there, and fine tuned for use with Laravel, among others.

Next, let’s create a menu to test our menu builder out:

<?php
require_once('autoload.php');

$menu = new Menu;

$about = $menu->add('About', 'about');

// since this item has sub items we append a caret icon to the hyperlink text
$about->link->append(' <span class="caret"></span>');

// we can attach HTML attributes to the hyper-link as well
$about->link->attributes(['class' => 'link-item', 'target' => '_blank']);

// Adding an attribute to the item wrapper itself
$about->attributes('data-model', 'info');

$about->add('Who we are?', array('url' => 'who-we-are',  'class' => 'navbar-item whoweare'));
$about->add('What we do?', array('url' => 'what-we-do',  'class' => 'navbar-item whatwedo'));

$about->add('Goals', array('url' => 'goals', 'display' => false));

$menu->add('Portfolio', 'portfolio');
$menu->add('Contact',   'contact');

// we're only going to hide items with `display` set to **false**

$menu->filter( function($item){
	if( $item->meta('display') === false) {
		return false;
	}
	return true;
});

// Now we can render the menu as various HTML entities:

echo $menu->asUl( attribute('class' => 'ausomw-ul') );

//OR

echo $menu->asOl( attribute('class' => 'ausomw-ol') );

// OR

echo $menu->asDiv( attribute('class' => 'ausomw-div') );

?>

Done!

Bootstrap 3 Navbar

The final step is to use our menu builder to create dynamic Bootstrap Navbars.

First of all, we need to create a function that populates our items in a Bootstrap friendly format because the existing render method doesn’t do this for us.

I name this function bootstrapItems() (I couldn’t really think of a better name, feel free to name it whatever you please).

You can put this function in any file you like as long as it is loaded at application startup. Alternatively you can extend the class Menu and add this method to the class. In this example, I place it in autoloader.php (as a helper function) to make sure it is always available to me.

function bootstrapItems($items) {
	
	// Starting from items at root level
	if( !is_array($items) ) {
		$items = $items->roots();
	}
	
	foreach( $items as $item ) {
	?>
		<li <?php if($item->hasChildren()): ?> class="dropdown" <?php endif ?>>
		<a href="<?php echo $item->link->get_url() ?>" <?php if($item->hasChildren()): ?> class="dropdown-toggle" data-toggle="dropdown" <?php endif ?>>
		 <?php echo $item->link->get_text() ?> <?php if($item->hasChildren()): ?> <b class="caret"></b> <?php endif ?></a>
		<?php if($item->hasChildren()): ?>
		<ul class="dropdown-menu">
		<?php bootstrapItems( $item->children() ) ?>
		</ul> 
		<?php endif ?>
		</li>
	<?php
	}
}

Since it’s just for educational purpose I didn’t use a template engine here as It’s beyond the scope of this tutorial. You can use the template engine of your choice to separate logic from presentation and make your code more readable.

Let’s see what BootstrapItems does behind the scenes.

First of all, it checks whether the given argument is an array or not. If it’s not, it fetches the items at root level and iterates over them. On each iteration it checks also if the current element has any children and if the element does have children, it will call itself passing the element’s children as a parameter. This process is repeated until it renders all the items to the deepest level.

Okay, now that we are able to generate the items in a Bootstrap friendly format, let’s register some items:

<?php
require_once('autoload.php');
// $menu #1
$main = new Menu;

$main->add('<span class="glyphicon glyphicon-home"></span>', '');
$about = $main->add('about', 'about');
   $about->add('Who we are?', 'who-we-are?');
   $about->add('What we do?', 'what-we-do?');
$main->add('Services', 'services');
$main->add('Portfolio', 'portfolio');
$main->add('Contact', 'contact');

// menu #2
$user = new Menu;

$user->add('login', 'login');
$profile = $user->add('Profile', 'profile');
  $profile->add('Account', 'account')
          ->link->prepend('<span class="glyphicon glyphicon-user"></span> ');
  
  $profile->add('Settings', 'settings')
          ->link->prepend('<span class="glyphicon glyphicon-cog"></span> ');
	
?>

And here’s our boilerplate code:

<nav class="navbar navbar-default" role="navigation">
  <div class="container-fluid">
    <!-- Brand and toggle get grouped for better mobile display -->
    <div class="navbar-header">
      <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      <a class="navbar-brand" href="#">Sitepoint</a>
    </div>

    <!-- Collect the nav links, forms, and other content for toggling -->
    <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
      <ul class="nav navbar-nav">
        <?php echo bootstrapItems($main); ?>
      </ul>
      <form class="navbar-form navbar-left" role="search">
        <div class="form-group">
          <input type="text" class="form-control" placeholder="Search">
        </div>
        <button type="submit" class="btn btn-default">Submit</button>
      </form>
      <ul class="nav navbar-nav navbar-right">
         	<?php echo bootstrapItems($user); ?>
      </ul>
    </div><!-- /.navbar-collapse -->
  </div><!-- /.container-fluid -->
</nav>

Because we have two different menus, we call BootstrapItems two times in our Bootstrap template.

Don’t forget to have jquery and bootstrap CSS and JS files loaded in your page before testing out the result!

Conclusion

We implemented a Menu manager, Items and Links in three class definitions for the sake of flexbility. We also stored a reference to the manager along with each item. This reference allowed us to access the manager from within Item context.

You can use this menu builder in any form you like as long as you use the right methods.

If you’re using Laravel 4, you can get laravel-menu which is implemented based on the methods described in this tutorial while providing more features, otherwise, see the full code of our built Menu Builder: fleximenu.

Happy coding!

Frequently Asked Questions on Dynamic Menu Builder with Bootstrap 3

How can I customize the color and style of my Bootstrap 3 dynamic menu?

Customizing the color and style of your Bootstrap 3 dynamic menu can be done through CSS. You can either modify the existing Bootstrap CSS or create a new CSS file and link it to your HTML file. In your CSS, you can target the specific classes used in your menu and apply the desired styles. For example, to change the background color of the navbar, you can use the following code:

.navbar {
background-color: #your-color;
}
Remember to replace ‘#your-color’ with the actual color code you want to use.

How can I add dropdown menus to my Bootstrap 3 dynamic menu?

Adding dropdown menus to your Bootstrap 3 dynamic menu involves adding a few more lines of code to your HTML. Bootstrap has a built-in class called ‘dropdown’ that you can use. Here’s an example of how you can add a dropdown menu:

<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
</ul>
</li>
In this example, ‘Dropdown’ is the name that will appear on the menu, and ‘Action’, ‘Another action’, and ‘Something else here’ are the options in the dropdown menu.

How can I make my Bootstrap 3 dynamic menu responsive?

Bootstrap 3 comes with built-in responsiveness, so your dynamic menu should automatically adjust to different screen sizes. However, you can further customize its responsive behavior using the ‘navbar-collapse’ class. This class collapses the navbar into a single button at a certain screen width (defined by you in your CSS). Here’s an example:

<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
</div>
<div class="collapse navbar-collapse">
<!-- your menu items here -->
</div>
In this example, the ‘navbar-toggle’ button will appear when the screen width is less than the threshold you defined in your CSS. When clicked, it will expand to show the menu items.

How can I add icons to my Bootstrap 3 dynamic menu?

Adding icons to your Bootstrap 3 dynamic menu can be done using icon libraries such as Font Awesome or Glyphicons. Once you’ve included the library in your project, you can add icons to your menu items like this:

<li><a href="#"><i class="fa fa-home"></i> Home</a></li>
In this example, ‘fa fa-home’ is the class for the home icon in Font Awesome. Replace it with the appropriate class for the icon you want to use.

How can I align menu items to the right in my Bootstrap 3 dynamic menu?

Aligning menu items to the right in your Bootstrap 3 dynamic menu can be done using the ‘navbar-right’ class. Simply add this class to the ‘ul’ element that contains your menu items, like this:

<ul class="nav navbar-nav navbar-right">
<!-- your menu items here -->
</ul>
In this example, all menu items within this ‘ul’ will be aligned to the right.

How can I add a search bar to my Bootstrap 3 dynamic menu?

Adding a search bar to your Bootstrap 3 dynamic menu involves adding a ‘form’ element with the ‘navbar-form’ class. Here’s an example:

<form class="navbar-form navbar-left" role="search">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
In this example, the search bar will appear on the left side of the navbar. Replace ‘navbar-left’ with ‘navbar-right’ if you want it on the right side.

How can I add a brand logo to my Bootstrap 3 dynamic menu?

Adding a brand logo to your Bootstrap 3 dynamic menu can be done using the ‘navbar-brand’ class. Here’s an example:

<a class="navbar-brand" href="#">
<img src="path-to-your-logo.png" alt="Your Brand">
</a>
In this example, replace ‘path-to-your-logo.png’ with the actual path to your logo image.

How can I make my Bootstrap 3 dynamic menu sticky?

Making your Bootstrap 3 dynamic menu sticky can be done using the ‘navbar-fixed-top’ class. Simply add this class to your ‘nav’ element, like this:

<nav class="navbar navbar-default navbar-fixed-top">
<!-- your menu items here -->
</nav>
In this example, the navbar will stick to the top of the page as you scroll down.

How can I add submenus to my Bootstrap 3 dynamic menu?

Adding submenus to your Bootstrap 3 dynamic menu involves adding another ‘ul’ element within a ‘li’ element. Here’s an example:

<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">Dropdown <b class="caret"></b></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li class="dropdown-submenu">
<a href="#">Submenu</a>
<ul class="dropdown-menu">
<li><a href="#">Sub-action</a></li>
</ul>
</li>
</ul>
</li>
In this example, ‘Submenu’ is a submenu of ‘Dropdown’, and ‘Sub-action’ is an option in the submenu.

How can I add active states to my Bootstrap 3 dynamic menu items?

Adding active states to your Bootstrap 3 dynamic menu items can be done using the ‘active’ class. Simply add this class to the ‘li’ element of the current page, like this:

<li class="active"><a href="#">Home</a></li>
In this example, the ‘Home’ menu item will be highlighted as the current page.

Reza LavarianReza Lavarian
View Author

A web developer with a solid background in front-end and back-end development, which is what he's been doing for over ten years. He follows two major principles in his everyday work: beauty and simplicity. He believes everyone should learn something new every day.

bootstrapbootstrap 3Bootstrap-resourcesfleximenuframeworklaravelmenumenu builderOOPHPPHP
Share this article
Read Next
Get the freshest news and resources for developers, designers and digital creators in your inbox each week