Slug Generator

Last updated: 04/17/2026 · Written by Agent0

Slug Generator

StackCTL includes a generate_slug() global helper that converts any string into a URL-safe slug and automatically guarantees uniqueness by checking the database. It's available everywhere in the application — no imports needed.


How It Works

When called, the helper:

  1. Converts the input string to lowercase
  2. Replaces non-alphanumeric characters with hyphens
  3. Trims leading and trailing hyphens
  4. Caps the slug at 100 characters
  5. Queries the specified table to check for a duplicate slug
  6. If the slug is already taken, appends an incrementing suffix (-1, -2, etc.) until a unique one is found

It uses the shared database connection from the App container — no PDO instance needs to be passed manually.


Basic Usage

$slug = generate_slug('Hello World', 'articles');
// → 'hello-world'

// If 'hello-world' already exists in the articles table:
// → 'hello-world-1'

// If 'hello-world-1' also exists:
// → 'hello-world-2'

Signature

generate_slug(string $value, string $table, string $column = 'slug'): string
  • $value — The string to slugify (e.g. an article title or category name)
  • $table — The table to check for uniqueness
  • $column — The column to check against. Defaults to 'slug'

Example: Generating a Slug on Create

Call generate_slug() in your controller's save() method when creating a new record. Include the result in the data array passed to insert().

public function save()
{
    $id = !empty($_POST['id']) ? (int)$_POST['id'] : null;

    $data = [
        'title'      => trim($_POST['title']),
        'content'    => $_POST['content'],
        'created_by' => auth('id'),
    ];

    if ($id) {
        // Updating — don't regenerate the slug
        Query::table('articles')->where('id', $id)->update($data);
        flash('success', 'Article updated.');
    } else {
        // Creating — generate a unique slug from the title
        $data['slug'] = generate_slug($_POST['title'], 'articles');
        Query::table('articles')->insert($data);
        flash('success', 'Article created.');
    }

    redirect('/articles');
}

Important: Only generate a slug on create, not on update. Regenerating a slug on update would break any existing links or bookmarks pointing to the original URL.


Custom Column Name

If your table uses a different column name than slug, pass it as the third argument:

$slug = generate_slug($name, 'categories', 'url_key');
// Checks the 'url_key' column in the 'categories' table

Edge Cases

  • If the input string is empty or produces no valid characters, the slug falls back to 'n-a'
  • Slugs are capped at 100 characters before the uniqueness suffix is added
  • The helper is safe to call with any user-supplied input — special characters, Unicode, and symbols are all handled
Was this helpful?