Laravel Slug Helper Generate Unique slug for Laravel

Categories - Laravel PHP Framework Tags - PHP Laravel   Maniruzzaman Akash   1 year ago   1268   3 minutes   6

Simple Way: Beginner friendly

In Laravel, you can use the Str::slug() helper method to generate a unique slug for a given string. Here’s an example of how you might use it:

use Illuminate\Support\Str;

$title = 'My Blog Post';
$slug = Str::slug($title, '-');

echo $slug; // Outputs: "my-blog-post"

The Str::slug() method takes two arguments: the string to convert into a slug, and the character to use as the delimiter. By default, it uses a hyphen (-) as the delimiter.

To make the slug unique, you can check if a slug with the same value already exists in the database, and if it does, append a number to the end of the slug to make it unique. For example:

use Illuminate\Support\Str;

$title = 'My Blog Post';
$slug = Str::slug($title, '-');

$i = 1;
while (Post::where('slug', $slug)->exists()) {
    $slug = Str::slug($title, '-') . '-' . $i++;
}

echo $slug; // Outputs: "my-blog-post" (if the slug is unique), or "my-blog-post-2" (if the slug already exists in the database)

This will ensure that the generated slug is always unique, by appending a number to the end of the slug if it already exists in the database.

Advanced Way: Best practice way

Hi, let’s make a unique slug helper method to create really nice unique slug in Laravel

Steps:

  1. Create a folder called Helpers inside app directory.
  2. Create a file SlugHelper.php inside Helpers directory.
  3. Paste the below codes inside SlugHelper
<?php

namespace App\Helpers;

class SlugHelper
{
    /**
     * Generate a Unique Slug.
     *
     * @param string $title
     * @param object $model
     * @param string $field
     * @param string $separator
     *
     * @return string
     * @throws \Exception
     */
    public static function generate($model, $title, $field, $separator = "-"): string
    {
        $id = 0;

        $slug =  preg_replace('/\s+/', $separator, (trim(strtolower($title))));
        $slug =  preg_replace('/\?+/', $separator, (trim(strtolower($slug))));
        $slug =  preg_replace('/\#+/', $separator, (trim(strtolower($slug))));
        $slug =  preg_replace('/\/+/', $separator, (trim(strtolower($slug))));

        // $slug = preg_replace('!['.preg_quote($separator).']+!u', $separator, $title);

        // Remove all characters that are not the separator, letters, numbers, or whitespace.
        // $slug = preg_replace('![^'.preg_quote($separator).'\pL\pN\s]+!u', '', mb_strtolower($slug));

        // Replace all separator characters and whitespace by a single separator
        $slug = preg_replace('![' . preg_quote($separator) . '\s]+!u', $separator, $slug);

        // Get any that could possibly be related.
        // This cuts the queries down by doing it once.
        $allSlugs = static::getRelatedSlugs($slug, $id, $model, $field);

        // If we haven't used it before then we are all good.
        if (!$allSlugs->contains("$field", $slug)) {
            return $slug;
        }

        // Just append numbers like a savage until we find not used.
        for ($i = 1; $i <= 10; $i++) {
            $newSlug = $slug . $separator . $i;
            if (!$allSlugs->contains("$field", $newSlug)) {
                return $newSlug;
            }
        }

        throw new \Exception('Can not create a unique slug');
    }

    private static function getRelatedSlugs($slug, $id, $model, $field)
    {
        if (empty($id)) {
            $id = 0;
        }

        return $model::select("$field")->where("$field", 'like', $slug . '%')
            ->where('id', '<>', $id)
            ->get();
    }
}

Output example

php artisan tinker

// If Web Designing slug not exist in database, response would be like this
>>> App\Helpers\SlugHelper::generate(App\Models\Category::class, 'Web Designing', 'slug')
=> "web-designing"

// If Web Designing slug exist in database, response would be like this
>>> App\Helpers\SlugHelper::generate(App\Models\Category::class, 'Web Designing', 'slug')
=> "web-designing-1"

>>> App\Helpers\SlugHelper::generate(App\Models\Category::class, 'Web Designing', 'slug')
=> "web-designing-2"

Tags: Laravel Slug Helper Generate Unique slug for Laravel, new slug laravel, laravel awesome slug, laravel slug

Previous
PHP If-else-elseif and Switch-case
Next
PHP String Functions - All necessary String functions in PHP to manage strings better.