Using polymorphic relationships of Laravel for SEO content

This tutorial applies to any applications that are built with Laravel framework and that need some sort of SEO and SEO management tool. You can also apply it as an extension to my previous tutorial on building a shop (where we built a review system).

SEO (Search Engine Optimization) is an important aspect of any website these days. While the tactics for SEO could be varying and there are multiple ways of optimizing a site for search engines, one way of telling the search engines about the content of your pages is to use page title, meta description and meta keywords tags. These three elements play an important in how the search engines view your pages and how the pages are displayed in the search results.

This past week I had an assignment at my job to build an SEO management panel for a large website. The SEO management panel will allow the admins of the site to set the title, description and keyword tags for site’s dynamic and static pages (there are well over 1000 pages).  Using Laravel’s polymorphic relationships I finished the assignment within two days. The tutorial below will explain some of the takeaways that I learned while implementing this task and the fundamentals that I used.

Before we start with the code, let’s first set some tone. Imagine that you have an e-Commerce website that has certain categories of products. Each category has its own page at a URL that uses a slug of category’s name (for example category “Long Sleeve Shirts” would be slug-ified to “long-sleeve-shirts”). Each product also has its own page using its name’s slug as well.

From a simplified shop model above you could see that there are at least 2 types of data in the system that will be visible to the users – categories and products. Of course you could have many many more – tags, brands, colors, manager’s picks, etc. Each of those data types has some sort page that displays the information about that data – category page would show all products under a certain category, product page would show the product and so on.

What if you wanted to implemented SEO for any or all of those data types? 

Solution 1 is to add SEO information as extra DB columns to each type of data. Maybe if you have only 1 or 2 types it is not a problem but when your application has more – your DB would grow considerably having columns like “title”, “description” and “keywords” for each data type.

Solution 2 is to use Laravel’s excellent Polymorphic relationships.

Don’t let the name scare you. Polymorphic relationships are a bit special but they are simpler than you might think. If you haven’t used them, they can greatly simplify the DB structure of an application in certain cases. Polymorphic relationships are extremely helpful when you have a common trait to two or more data types. You will understand the concept better as you read through this post. This is the type of a relationship I will be using for managing SEO content of an application.

Using Polymorphic relationships to store SEO data for Laravel application:

Polymorphic relationship is simply a method of convenience for accessing data in a single DB table that could relate to content from different DB tables. Instead of adding the same extra columns to all DB tables that need them (for example SEO data columns) you could have just one table that would have ID and TYPE of data from other tables stored. See the picture below that shows an actual DB structure if you were to use a polymorphic relationship to store SEO data for multiple types of data (multiple tables):

The lines with arrows point to the names and ids of the tables and that is actually what you will see in the DB in order for the relationship to work.

The SQL to create the SEO table is provided below:

CREATE TABLE `seo` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `title` varchar(255) NOT NULL,
  `description` varchar(255) NOT NULL,
  `keywords` varchar(255) NOT NULL,
  `seoble_id` int(11) unsigned NOT NULL,
  `seoble_type` varchar(255) NOT NULL,
  `created_at` datetime NOT NULL,
  `updated_at` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;

How can you use it?

First, you would need to create a model for your SEO data. Then you could use that model to all of the data types that you want to be able to relate to. The model for the SEO table is below (store it in app/models/Seo.php):

<?php

class Seo extends Eloquent {

    protected $table = 'seo';

    public function seoble()
    {
        return $this->morphTo();
    }

}

That’s it! In any other model that you want to use the SEO for, you would just specify $this->morphMany(‘Seo’,’seoble’) as the relationship returned for the seo (as an example I provide the model for Products stored in app/models/Product.php) :

class Product extends Eloquent
{
	...

	public function seo()
	{
	    return $this->morphMany('Seo', 'seoble');
	}

	...
}

Now, if you had the SEO data present in the SEO table, specifying an ID of some product in the DB and the “seoble_type” as “Product”, you could get the SEO data for the specific product and display it like this:

// retrieve the product from DB by ID
$product = Product::find($id);

// Get the SEO data for the product as an object
$seo = $product->seo->first();

// In the Blade view for the product display the SEO data:
<title>{{ isset($seo->title) ? $seo->title : 'Viewing Product'}}</title>
<meta name="keywords" content="{{ isset($seo->keywords) ? $seo->keywords : ''}}">
<meta name="description" content="{{ isset($seo->description) ? $seo->description : ''}}">

Moreover, if you had a model for the categories that would “morphMany(‘Seo’,’seoble’)” and a row for one of the categories available in the DB (in “categories” table), and if you had the ID of that category, then having a row in the “seo” table specifying that ID and the “seoble_type” as “Category”(the name of the model), you could retrieve the SEO data for that category exactly like you would for the product:

// retrieve the category from DB by ID
$category = Category::find($id);

// Get the SEO data for the category as an object
$seo = $category->seo->first();

// In the Blade view for the category display the SEO data:
<title>{{ isset($seo->title) ? $seo->title : 'Viewing Category'}}</title>
<meta name="keywords" content="{{ isset($seo->keywords) ? $seo->keywords : ''}}">
<meta name="description" content="{{ isset($seo->description) ? $seo->description : ''}}">

This is super convenient, isn’t it?

At this point, you could already input data through the DB admin (like PHP myadmin) for all products, categories and more and you could easily show them to the search engines in a way I just described.  Of course there is even a better way of inputting this data.

Over the weekend I will publish another post that will have a link to the source for an admin interface that helps you manage SEO data in the polymorphic relationship table, so stay tuned!

UPDATE: I have released the admin panel interface to manage SEO data, read the details at https://maxoffsky.com/code-blog/releasing-admin-panel-for-seo-polymorphic-relationships-using-laravel/

Enjoy using polymorphic relationships!

You may also like

More in Code Blog
Releasing new website for Laravel developers – Laravel-Tricks.com

I am happy to announce the immediate release of a new project that my friend (@stidges) and I have been...

Close