Building Dynamic Breadcrumbs In Laravel
Tags: laravel, php, breadcrumbs
Published: 2017-11-29 19:15:49

---
title: Building Dynamic Breadcrumbs In Laravel
published: true
description: Building Dynamic Breadcrumbs In Laravel
tags: laravel,php,breadcrumbs
---

![](https://cdn.scotch.io/40410/Yk7veZxQRSaunKy4aLB8_Untitled%201.png.jpg)


##  The Importance of Breadcrumbs
   In the past, web developers were more concerned with the functions (back-end) and information web applications could deliver and didn't pay as much attention to the visual appearance (front-end) of web pages. This wasn't entirely their fault, there weren't fitting technology to develop complex web page designs at that time. The few ones that could do a bit of magic were a hassle to use. 

   Today, it's a whole different story; the UI/UX design stage in web development is just as important as the pre-planning of the backend logic that keeps everything running. There lie a wide spectrum of acceptable design practices that can help a web application earn the "user-friendly" tag, but there are even more design flaws that everyone should watch out for.

   People hate getting unsolicited pop-up boxes in their faces; I do too, but pop-ups aren't the only things that can grind the user's gears. The inability to locate one's self and navigate easily on a website is as bad as getting lost in a big mall; the same feeling of overwhelmingness. 

   While that could be a serious problem, it doesn't have to be! Breadcrumbs can be the easiest solution to giving users the smooth web navigation experience they deserve.

>Breadcrumbs provide a navigation system to help users know their current location in relation to other web pages on a website. The name breadcrumbs is derived from the well-known fairy tale [Hansel and Grettel](https://en.wikipedia.org/wiki/Hansel_and_Gretel) because it does pretty much the same thing; leaves a trail behind to prevent users from getting lost hence promoting user experience. Breadcrumbs on a website will also reduce the number of actions a user has to trigger to reach a page of choice. 

 Setting up breadcrumbs in Laravel is quite simple. There is a package that takes care of most of the logic, and we will be looking at how to use this package and get the best features out of it.

The source code for this tutorial is available [here](https://github.com/Jordanirabor/Laravel-Breadcrumbs) on GitHub.


## Setting up the Laravel application
   This entire tutorial is targeted at Laravel developers.

   We will be pulling in the [Laravel Breadcrumbs](https://github.com/davejamesmiller/laravel-breadcrumbs) package via Composer and writing code to render breadcrumb navigation services dynamically, depending on what page the user is viewing.

The resulting code for this article is available [here](https://github.com/Jordanirabor/Laravel-Breadcrumbs) on GitHub.

   For the sake of this article, we will be installing a fresh instance of a Laravel application.

```BASH
laravel new breadcrumbs
```

OR
```BASH
composer create-project --prefer-dist laravel/laravel breadcrumbs
```

   Next, we pull in the [Laravel Breadcrumbs](https://github.com/davejamesmiller/laravel-breadcrumbs) package by typing the command below in the terminal.

```BASH

composer require davejamesmiller/laravel-breadcrumbs

```

### Creating the HTTP routing

   Let's create some `HTTP` routes ( and name them as well ) in the` routes/web.php` file — we will be referring to these routes by name in later parts of this article.

   These are the routes needed for this example:

*routes/web.php*
```PHP

Route::get('/',  ['as' => 'home', 'uses' => 'MainController@home']);

Route::get('/continent/{name}',  ['as' => 'continent', 'uses' => 'MainController@continent']);

Route::get('/country/{name}',  ['as' => 'country', 'uses' => 'MainController@country']);

Route::get('/city/{name}',  ['as' => 'city', 'uses' => 'MainController@city']);

```

To demonstate the power of Laravel Breadcrumbs, we will build a small application where we register continent, country and citiy models. We will also say that a continent `hasMany` countries and a country `hasMany` cities.

To create these models, we write these commands to the terminal:

```BASH
php artisan make:model Continent
php artisan make:model Country
php artisan make:model City
```
Let's also create the migration files for each of these models:

```BASH
php artisan make:migration continents
php artisan make:migration countries
php artisan make:migration cities
```

Next, let's define the relationship methods in each one of the model classes:

*app/Continent.php*
```PHP
namespace App;
use App\Country;

use Illuminate\Database\Eloquent\Model;

class Continent extends Model
{
    public function country(){
    	return $this->hasMany(Country::class);
    }
}
```

*app/Country.php*
```PHP
namespace App;

use App\City;
use App\Continent;

use Illuminate\Database\Eloquent\Model;

class Country extends Model
{

    protected $guarded = [];
    public function city(){
    	return $this->hasMany(City::class);
    }

    public function continent(){
    	return $this->belongsTo(Continent::class);
    }
}
```

*app/City.php*
```PHP
namespace App;


use App\Country;

use Illuminate\Database\Eloquent\Model;

class City extends Model
{

	protected $guarded = [];
    public function country(){
    	return $this->belongsTo(Country::class);
    }
}
```
> Notice that ` guarded` is set to an empty array, this is because we intend to do some form of mass assignment when seeding the database. Whenever you make a change like this to a model file, always remember to revert the change before the application gets to production stage.

Now let's create a controller that will handle all the `HTTP` requests the application receives. We will call the controller `MainController` and will declare different actions (`methods`) to `compact` instances of models with the returning view, each view will display its own breadcrumb(s).

To create this controller, we write this command to the terminal:

```BASH
php artisan make:controller MainController
```
Now let's write the actions (`methods`) that will return views after handling the `HTTP` requests.

*app/Http/Controllers/MainControllers.php*
```PHP
namespace App\Http\Controllers;
use App\Continent;
use App\Country;
use App\City;
use Illuminate\Http\Request;

class MainController extends Controller
{
    public function home(){
    	return view('home');
    }

     public function continent($name){
           $continent = Continent::where('name', $name)->first();
    	return view('continent', compact('continent'));
    }

     public function country($name){
           $country = Country::where('name', $name)->first();
    	return view('country', compact('country'));
    }

     public function city($name){
           $city = City::where('name', $name)->first();
    	return view('city', compact('city'));
    }
}
```

We have included the relationships between models so we can explore the capabilities of the [Laravel Breadcrumbs](https://github.com/davejamesmiller/laravel-breadcrumbs) package when it comes to dynamic linking and relational properties.

Now let's create some views to match the models we just created. In the `resources/views` directory, we'll add four new files, we'll name them: 

```
home.blade.php
continent.blade.php
country.blade.php
city.blade.php
```
Their names are quite intuitive; the first will hold the frontend code for the homepage, the second will hold the frontend code for the continent page, the third will hold the frontend code for the country page and the last will hold the frontend code for the city page.

Great, now let's put some code in these new views:

*resources/views/home.blade.php*
```HTML
<!DOCTYPE html>
<html>
<head>

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">

 </head>
 <body>
 
{{ Breadcrumbs::render('home') }}

</body>
</html>
```

*resources/views/continent.blade.php*
```HTML
<!DOCTYPE html>
<html>
<head>

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">

 </head>
 <body>
 
{{ Breadcrumbs::render('continent', $continent) }}

</body>
</html>
```

*resources/views/country.blade.php*
```HTML
<!DOCTYPE html>
<html>
<head>

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">

 </head>
 <body>
 
{{ Breadcrumbs::render('country', $country->continent, $country) }}

</body>
</html>
```

*resources/views/city.blade.php*
```HTML
<!DOCTYPE html>
<html>
<head>

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">

 </head>
 <body>
 
{{ Breadcrumbs::render('city', $city->country->continent, $city->country, $city) }}

</body>
</html>
```

   The `Continent` and `Country` models exhibit a `One To Many` relationship. Many cities belong to one country and many countries belong to one continent. A continent is the grandparent of a city while a country is the parent of a city. We won't be diving into the logic that binds Laravel relationships in this article but if you wish to learn about it, you can find good knowledge [here](https://scotch.io/courses/laravel-eloquent-relationships/getting-started).
   
Lastly, Let's modify the migration files a bit so they define the proper structure for the tables in the database.

*database/migrations/2017_11_02_092826_continents.php*
```PHP
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class Continents extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('continents', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        //
    }
}
```

*database/migrations/2017_11_02_092835_countries.php*
```PHP
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class Countries extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('countries', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('continent_id');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        //
    }
}
```

*database/migrations/2017_11_02_092845_cities.php*
```PHP
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class Cities extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('cities', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('country_id');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        //
    }
}
```
We can run the migrations with this command on the terminal:

```BASH
php artisan migrate
```

Let's insert some data into the database so we can test this application. To do this, we'd create three `factory` files [ one for each model ] and update the `run` method of the [ already existing ] `DatabaseSeeder.php` file in the `database/seeds` directory.

To create the factory files, we'd write these commands to the terminal:

```BASH
php artisan make:factory ContinentFactory --model=Continent
php artisan make:factory CountryFactory --model=Country
php artisan make:factory CityFactory --model=City
```

The commands above will create these files respectively:

*database/factories/ContinentFactory.php*
```PHP

use Faker\Generator as Faker;

$factory->define(App\Continent::class, function (Faker $faker) {
    return [
        //
    ];
});
```

*database/factories/CountryFactory.php*
```PHP

use Faker\Generator as Faker;

$factory->define(App\Country::class, function (Faker $faker) {
    return [
        //
    ];
});
```

*database/factories/CityFactory.php*
```PHP

use Faker\Generator as Faker;

$factory->define(App\City::class, function (Faker $faker) {
    return [
    	//
    ];
});
```
Lastly, let's update the `DatabaseSeeder.php` file that ships with every fresh instance of a Laravel application. We'll use this file to insert three rows into the database, we'll insert `Africa` [ of the continent model], `South Africa` [ of the country model ] and `Johannesburg`[ of the city model ], we'll also specify their relationships :

```PHP

use Illuminate\Database\Seeder;

class DatabaseSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {

      factory(App\City::class)->create([
      	'name' => 'Johannesburg',
      	'country_id' => function(){
		
      		return factory(App\Country::class)->create([
      			'name' => 'South Africa',
      			'continent_id' => function(){
				
      				return factory(App\Continent::class)->create([
      					'name' => 'Africa' ])->id;
      			}
      			])->id;
      	}
      	]);
    }
}
```
We can seed the database with this command to the terminal:

```BASH
php artisan db:seed --class=DatabaseSeeder
```

## Setting up the breadcrumbs file

We need to create a `breadcrumbs.php` file in the routes directory. This file will be referenced whenever a breadcrumb is rendered because it instructs Laravel on how to process the breadcrumb information. Without this file, Laravel will squawk an error in our faces whenever it encounters a call to a breadcrumb function in the views.

   The first breadcrumb function we will be defining in our newly created `breadcrumbs.php` file is the one for our homepage. The 'home' breadcrumb will be loaded whenever the route named 'home' is visited.

*routes/breadcrumbs.php*
```PHP
Breadcrumbs::register('home', function ($breadcrumbs) {
     $breadcrumbs->push('Home', route('home'));
});

```
## Rendering a static breadcrumb
   In the above code, we see that the `Breadcrumbs` class is used to call a static method. The register method registers a new breadcrumb with the name home and calls a closure. Then the closure takes a $breadcrumbs parameter and pushes a new breadcrumb instance alongside its URL. 

 ```PHP
 $breadcrumbs->push('Home', route('home'));
 ```

   The 'Home' in the `push` method is hard-coded and what will appear when the breadcrumb is rendered on the home view or any other view that requires the `Home` breadcrumb to display a complete navigation chain.

   The `route('home')` returns the URL of 'home' and will be the link `Home` leads to when it is rendered on any view.

   Finally, in the home view code, this is how we render the breadcrumb.
   
*resources/views/home.blade.php*
```HTML
{{ Breadcrumbs::render('home') }}
```
   The `render` method receives the name of the breadcrumb to display on the home view. In more complex navigation chains that include some form of database relationship, the `render` function will accept as many instances of `Models` as arguments, as are required to render the complete breadcrumb navigation chain. 

   We will talk more about this next.

## Rendering a dynamic breadcrumb

   What happens when we have a web application where we do not know the exact attributes of the pages users will be visiting? For example, we have a website that displays information about continents, countries, and cities. We can't always hard-code the name of any continent, country or city to the `routes/breadcrumbs.php` file because we never know which one a user will be viewing.

  To make it possible for dynamic breadcrumb rendering in real time, we can write the `routes/breadcrumbs.php` file to efficiently work with the dynamic `Models` in our application and create the breadcrumb navigation chain as users explore deeper layers in our web application.

   As we said before, the continent `Model` `hasMany` countries and the country `Model` `hasMany` cities. Knowing this, we should be able to get a breadcrumb display that looks like this if we visit Johannesburg of South Africa where South Africa belongs to Africa. 

![](https://cdn.scotch.io/40410/FinwqBwHSYyWCCIwKflV_breadcrumb.png)

To generate the chain of breadcrumb navigation using `Model` relationships as we see above, we start by writing the code for registering the `continent` breadcrumb:

*routes/breadcrumbs.php*
```PHP
Breadcrumbs::register('continent', function ($breadcrumbs, $continent) {
    $breadcrumbs->parent('home');
    $breadcrumbs->push($continent->name, route('continent', ['name' => $continent->name]));
});
```

   We register a `continent` breadcrumb and pass a `closure`. The closure accepts a new parameter, the `$continent` (which will be supplied by the calling view in real time). Next, the `home` breadcrumb is assigned as the parent and lastly, the name and URL of the `$continent` breadcrumb is pushed.

   To render the breadcrumb in the continent view code, we write this snippet:

*resources/views/continent.blade.php*
```HTML
{{ Breadcrumbs::render('continent', $continent) }}
```
   The `render` method receives the name of the breadcrumb as the first argument. It also receives a `$continent` argument that will help in resolving the instance of the `continent` `Model` to its basic properties such as name and URL.
   
  On my local machine, visiting `http://127.0.0.1:8000/continent/africa` will result in the `Africa` continent page with this breadcrumb display.
   
   ![](https://cdn.scotch.io/40410/dJFNYZqgRX6qFIBeC2DE_bread.png)



## Rendering a complete navigation chain

   We have looked at the code to render individual breadcrumbs, now let's look at the code and logic to render a complete breadcrumb chain. For the sake of this article, we will be rendering a city page that is related to a country page, then a continent page and lastly, a home page.
   
   This is the final code [for this article, it can get way bigger depending of what you aim to achieve ] for the `routes/breadcrumbs.php` file:
   
   *routes/breadcrumbs.php*
   ```PHP
Breadcrumbs::register('home', function ($breadcrumbs) {
     $breadcrumbs->push('Home', route('home'));
});

Breadcrumbs::register('continent', function ($breadcrumbs, $continent) {
    $breadcrumbs->parent('home');
    $breadcrumbs->push($continent->name, route('continent', ['name' => $continent->name]));
});

Breadcrumbs::register('country', function ($breadcrumbs, $continent, $country) {
    $breadcrumbs->parent('continent', $continent);
    $breadcrumbs->push($country->name, route('country', ['name' => $country->name]));
});

Breadcrumbs::register('city', function ($breadcrumbs, $continent, $country, $city) {
    $breadcrumbs->parent('country', $continent, $country);
    $breadcrumbs->push($city->name, route('city', ['name' => $city->name]));
});
   
   ```
   
   We have added two more breadcrumbs — `country` and `city` — We need these additional breadcrumbs so that all the breadcrumbs can effectively communicate with one another when a view calls for a navigation chain that involves more than one breadcrumb.
   
   The methods for registering and pushing the `country` and `city` breadcrumbs are the same as the ones for the `continent` breadcrumb so we will not be looking at it in detail.
   
   To render the breadcrumb in the view code for the city page, we simply insert this snippet of code in the desired location:
   
   *resources/views/city.blade.php*
   ```HTML
   {{ Breadcrumbs::render('city', $city->country->continent, $city->country, $city) }}
   ```
 
  The `render` method here receives the name of the breadcrumb as the first argument. Next, it receives a `$city->country->continent` argument which will evaluate to an instance of a `continent` `Model`, also it receives a `$city->country` argument which is the country the city `belongsTo` and lastly a `$city` instance. 
	  
That is it. We have completely generated our fully functional and dynamic breadcrumb navigation in only a few lines of code.

## Conclusion

In a world where the 'users' of internet services seek for the easiest to use products, it is only be right for developers to add breadcrumbs to websites. This article has taught that, with just a few lines of code, we can create a fully functional navigation service. There are lots more that can be done with the [Laravel Breadcrumb](https://github.com/davejamesmiller/laravel-breadcrumbs) package [ for example, we can affect the style and layout to our taste ], feel free to explore it to its fullest power. 

The source code for this tutorial is available [here](https://github.com/Jordanirabor/Laravel-Breadcrumbs) on GitHub.