Unique Identifiers in Dynamic URL Structures with Laravel

Unique Identifiers in Dynamic URL Structures with Laravel

Published on 14.03.2024

Have you ever clicked on a link only to find it’s broken? It’s frustrating, isn’t it? This often happens when a website’s page title changes, which can lead to a change in the URL. If you’ve got a website and you want to avoid this headache for your users (and for your SEO), we’ve got a nifty solution for you using Laravel, one of the popular PHP frameworks.

Why Semantic URLs Matter

Semantic URLs are the ones that are readable and meaningful to both humans and search engines. For example, instead of having a URL that ends with a bunch of numbers and symbols, you have one that actually tells you what the page is about, like /tips-for-growing-tomatoes. They’re great for navigation and can give your SEO a boost.

The Challenge of Changing URLs

Now, the issue arises when you want to update the title of an article, a product name, or a category. The URL changes, and suddenly all the links that used to point to it lead to the dreaded 404 error page. We definitely don’t want that.

Introducing Unique Identifiers

To solve this, we can use a unique identifier in our URL structure. This means you can change the title as much as you want, but the unique identifier stays the same, preserving the link. Here’s an example of what this looks like:

https://inthemakings.com/en/article/how-to-code_123abc

The part after the underscore is the unique identifier that stays constant.

How to Set Up Unique Identifiers in Laravel

Let’s roll up our sleeves and dive into the code. Initially, our article route might look simple:

Route::group(['prefix' => '/{language}'], function () {
    Route::get('/article/{slug}', 'ArticlesController@get_view');
});

But we’re going to add a twist to include the unique identifier:

Route::get('/article/{slug}_{hashid}', 'ArticlesController@get_view');
Route::get('/article/{slug}', 'ArticlesController@get_redirectToUrlWithHashid');

The first route is our new path, while the second one ensures that any old URLs will redirect to the updated one.

The Magic of Hashids

To create these unique identifiers, we’ll use a library called Hashids. It turns numbers into short, unique strings. It’s like giving each article its own secret code that never changes. And there’s a Laravel package that makes integrating Hashids a breeze.

Just run:

composer require vinkla/hashids
php artisan vendor:publish

Don’t forget to set up your config in config/hashids.php with a salt, length, and alphabet that you decide on. Remember, once you’ve started using Hashids, changing these settings will change all your IDs, so set it and forget it!

Updating the Article Model

We’ll add a couple of methods to our Article model to work with Hashids:

class Article extends Model
{
    public function getHashidAttribute() {
        return Hashids::connection('articles')->encode($this->id);
    }

    public function scopeWhereHashid($query, $hashid) {
        $decoded = Hashids::connection('articles')->decode($hashid)[0] ?? null;
        return $query->where('id', '=', $decoded);
    }
}

The Controller Methods

In the controller, we’ll use our new whereHashid scope to find the right article, and if the slug doesn’t match, we’ll redirect to the updated URL with a 301 status code, which tells search engines that the page has moved permanently.

class ArticlesController extends Controller
{
    public function get_view($language, $slug, $hashid) {
        $article = Article::whereHashid($hashid)->firstOrFail();

        if ($article->slug !== $slug) {
            return redirect()->route('articles.view', [
                'language' => $language,
                'slug' => $article->slug,
                'hashid' => $article->hashid,
            ], 301);
        }
    }

    public function get_redirectToUrlWithHashid($language, $slug) {
        $article = Article::where('slug', $slug)->firstOrFail();
        return redirect()->route('articles.view', [
            'language' => $language,
            'slug' => $article->slug,
            'hashid' => $article->hashid,
        ], 301);
    }
}

And there you have it! With this setup, you can freely update your article titles without worrying about breaking links. Your users will thank you, and your SEO won’t take a hit from dead links. It’s a win-win!