SEO-Friendly URLs: Design and Routing in PHP and Laravel

In this article10 sections
SEO-friendly URLs are short, readable addresses that describe the page, use words people understand, separate those words with hyphens and stay stable over time. Google's own guidance on URL structure recommends simple, descriptive URLs rather than long strings of identifiers, and warns that unnecessary parameters can create huge numbers of duplicate addresses for the same content. Good URLs do not make a page rank on their own, but they help users decide what to click, make links easier to share and trust, and keep crawling efficient. Most importantly, a well-designed URL scheme rarely needs to change, and every change carries the risk of broken links and lost signals.
This guide covers the design principles, then shows how to implement slugs, hierarchy and safe slug changes in PHP and Laravel.
Key takeaways
- Use descriptive words, lowercase letters and hyphens between words.
- Group related content in directories that reflect the site's structure.
- Keep parameters for genuine variations, and avoid session IDs in URLs.
- Design URLs to last, and redirect old slugs permanently when they must change.
- Generate every URL from one helper so links, canonicals and sitemaps agree.
What Google recommends for SEO-friendly URLs
Google's article on URL structure best practices sets out a few clear principles.
- Use simple, descriptive words that make sense to people:
/services/magento-developmentrather than/index.php?id=7&cat=3. - Use hyphens to separate words. Google recommends hyphens over underscores, which may be read as joining words together.
- Use the audience's language, with UTF-8 encoding for non-ASCII characters where appropriate.
- Avoid unnecessary parameters that create many URLs for the same content.
- Keep URLs consistent, since mixed case and trailing slashes create duplicates.
Google also notes elsewhere that keywords in URLs have only a small effect on ranking. The benefit is mostly for people: a readable URL in a search result or a shared message tells them what to expect.
Readable URLs also help your own team. Analytics reports, Search Console data and server logs are far easier to interpret when the path itself says which page and section a row refers to.
Designing a URL structure
A URL scheme is easiest to get right before launch. Start from the site's information architecture and give each content type a predictable pattern.
| Content type | Pattern | Example |
|---|---|---|
| Service | /services/{slug} | /services/magento-store-migration |
| Service in a market | /services/{service}/{location} | /services/magento-development/uk |
| Article | /blog/{slug} | /blog/xml-sitemaps-guide |
| Category | /blog/category/{slug} | /blog/category/technical-seo |
| Product | /store/{slug} | /store/magento-2-gst-checkout |
| Location | /locations/{slug} | /locations/lucknow |
- Keep hierarchy shallow. Two or three levels are usually enough; deep paths become fragile when categories change.
- Avoid dates in article URLs unless the content is genuinely time-bound news; dates make evergreen content look old.
- Leave out file extensions such as .php or .html; they expose implementation details you may later change.
- Do not put categories in product URLs if products belong to several categories; it creates duplicates.
Grouping similar content in directories also helps Google understand which parts of the site change often, which Google mentions as useful for large sites.
Write the URL patterns down in the project documentation before development starts, alongside the content types and their fields. Designers, developers and content editors then work from the same plan, and nobody invents a new pattern for a one-off page that later becomes a whole section.
Generating slugs in PHP
A slug is the readable part of the URL derived from a title. Generate it once, store it, and treat it as a stable identifier rather than recalculating it from the title on every request.
// Laravel: unique slug from a title, stored on create.
use Illuminate\Support\Str;
public static function uniqueSlug(string $title, ?int $ignoreId = null): string
{
$base = Str::slug($title); // "SEO-Friendly URLs!" becomes "seo-friendly-urls"
$slug = $base;
$n = 2;
while (static::where('slug', $slug)->when($ignoreId, fn ($q) => $q->where('id', '!=', $ignoreId))->exists()) {
$slug = $base . '-' . $n++;
}
return $slug;
}
- Trim stop words carefully. Removing "a", "the" and "and" can shorten slugs, but keep words that change the meaning.
- Limit length to something readable; around three to six words is plenty for most pages.
- Let editors override the slug before publishing, with validation for allowed characters.
- Add a unique index on the slug column, so duplicates cannot slip in under load.
- Do not change the slug automatically when an editor updates the title of a published page; changing the URL should be a deliberate decision.
Routing with slugs in Laravel
Laravel's route model binding can resolve records by slug directly. The Laravel routing documentation shows how to bind a column other than the primary key.
// routes/web.php
Route::get('/blog/{post:slug}', [PostController::class, 'show'])->name('posts.show');
Route::get('/services/{service:slug}/{location:slug}', [ServiceLocationController::class, 'show']);
// Generating links always goes through the route name.
$url = route('posts.show', $post); // https://example.com/blog/seo-friendly-urls
Generate every internal link, canonical tag, sitemap entry and structured data URL from named routes or a single URL helper. When links are built by string concatenation in many templates, inconsistencies such as trailing slashes or different hosts creep in. Our guide to canonical URLs and duplicate content explains why that consistency matters.
Changing slugs safely
Sometimes a slug must change: a product is renamed, a typo slipped through or a page now covers a different topic. Every old URL may have links, bookmarks and search visibility. Handle the change in code so editors cannot break it by accident.
- When a published record's slug changes, store the old path.
- Create a permanent 301 redirect from the old path to the new one.
- Update internal links to the new URL so they do not rely on the redirect.
- Prevent the old slug being reused for different content while the redirect exists.
- Collapse chains: if a slug changes twice, redirect the oldest path straight to the newest.
// After saving a model whose slug changed.
if ($model->wasChanged('slug') && $model->getOriginal('slug')) {
Redirect::updateOrCreate(
['source_path' => '/blog/' . $model->getOriginal('slug')],
['target' => '/blog/' . $model->slug, 'code' => 301]
);
Redirect::where('target', '/blog/' . $model->getOriginal('slug'))
->update(['target' => '/blog/' . $model->slug]); // no chains
}
Content management systems should make this automatic. Editors change titles often, and they should never have to remember to add a redirect by hand.
Our guide to HTTP status codes and SEO explains why permanent redirects matter for passing signals to the new address.
Parameters, filters and session IDs
Query parameters are fine for genuine variations such as search terms, filters and pagination. Problems start when combinations multiply or when parameters carry state that does not change the content.
- Sort and view parameters should canonicalise to the default view.
- Tracking parameters must never be added to internal links; use them only on links from emails and adverts.
- Session IDs belong in cookies, not URLs, because every visitor would generate unique addresses.
- Consistent parameter order avoids
?a=1&b=2and?b=2&a=1being treated as different URLs. - Filter pages worth ranking can be given clean paths, such as
/shoes/running, instead of parameters.
Non-English URLs and multilingual sites
For sites in other languages, URLs in the reader's language are more meaningful than transliterated English. Google supports UTF-8 characters in paths, which browsers display readably and encode when sending requests. Keep one language per URL, use a clear language or region prefix such as /ar/ or /de/, and connect equivalents with hreflang annotations.
Avoid automatically redirecting visitors to a language based on their location, which can stop crawlers reaching other versions. Offer a visible language switcher instead.
Decide early whether translated pages use translated slugs or keep the English ones. Translated slugs read better for local visitors, but they need a mapping between languages so hreflang annotations and language switchers can find the matching page. Either approach works if it is applied consistently.
Moving from query-string URLs
Many older PHP applications use URLs such as /index.php?page=product&id=184. Moving to readable paths is worthwhile when the site is being rebuilt anyway, but it must be done as a careful migration rather than a cosmetic change.
- Export every old URL that receives traffic, links or appears in the sitemap.
- Map each one to its new path, using the record ID to find the matching slug.
- Implement the redirects in code, so
?id=184resolves to the product's current slug even if it changes later. - Switch internal links, canonicals and sitemaps to the new paths on the same day.
- Monitor Search Console for redirect errors and pages that drop out of the index in the following weeks.
Expect some movement in search results while Google processes the new addresses; it usually settles within weeks when every old URL redirects in a single hop. Keep the redirect logic for at least a year. Old URLs survive in bookmarks, emails, printed materials and other websites for much longer than most teams expect. Our guide to migrating without losing SEO covers the wider process for stores.
Testing URL behaviour
- Assert that upper-case, trailing-slash and duplicate-host variants redirect once to the canonical form.
- Assert that renamed slugs return a 301 to the new address, and that redirect chains collapse.
- Crawl the site and list URLs with parameters, unusual characters, spaces or excessive length.
- Check that every URL in the sitemap matches the canonical tag on its own page.
Internal linking and URL design work together. Our guide to internal linking for online stores shows how a clear structure helps search engines find important pages.
Frequently asked questions
Do keywords in URLs improve rankings?
Only slightly. Descriptive URLs mainly help people understand and trust a link before they click.
Hyphens or underscores?
Hyphens. Google recommends them for separating words in URLs.
Should I change old URLs to make them prettier?
Usually not. Changing working URLs risks broken links and temporary ranking loss. Change them only when there is a strong reason, with redirects.
Should URLs end with a slash?
Either works. Choose one style and redirect the other consistently.
Planning a new site or untangling an old URL structure? Our SEO services include URL audits, and our developers can design and migrate the structure.
Want an expert to look at your store?
Tell us what you are working on. A senior e-commerce consultant will reply within one working day with honest, practical advice. No obligation and no sales script.
- Reply within one working day
- Advice even if we are not the right fit
- Your details are never shared