October 16, 2026 - 04:45
SEO-Friendly URL Structures with PHP Image
PHP

SEO-Friendly URL Structures with PHP

0 Comments

A readable URL can explain a page's subject, but it does not guarantee search rankings. Do not rename working, indexed addresses simply to make them look cleaner. Designing slugs for a new PHP application and migrating an established site's URLs are different tasks.

A small Apache rewrite example

This example assumes Apache 2.4, enabled mod_rewrite, and the necessary AllowOverride permission. It belongs in a web-root .htaccess file; adapt it for a subdirectory or an existing router. Do not put LoadModule in .htaccess. Module loading is a server-configuration responsibility.

APACHE
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^blog/([a-z0-9]+(?:-[a-z0-9]+)*)/?$ blog.php?slug=$1 [END]

A request for /blog/php-arrays is handled internally as blog.php?slug=php-arrays. This is not an external redirect: the browser address stays unchanged. Because the target includes a query string and QSA is absent, the incoming query string is not appended. A supplied ?slug=another-post therefore cannot override the path-selected value through this rule. Tracking parameters are dropped too; decide explicitly how to support them if needed.

Validate the request in PHP as well

A rewrite rule does not secure database access. The handler can also be requested directly, so validate its input. This example assumes a PDO connection from trusted application configuration and a posts(slug, title, status) schema; adapt the table to your application.

PHP
<?php
// $pdo: the application's PDO connection using utf8mb4.
$slug = $_GET['slug'] ?? '';
if (!is_string($slug) || strlen($slug) > 160
    || !preg_match('/\A[a-z0-9]+(?:-[a-z0-9]+)*\z/', $slug)) {
    http_response_code(404);
    exit('Page not found.');
}
$stmt = $pdo->prepare(
    'SELECT title FROM posts WHERE slug = :slug AND status = :status LIMIT 1'
);
$stmt->execute(['slug' => $slug, 'status' => 'published']);
$post = $stmt->fetch(PDO::FETCH_ASSOC);
if ($post === false) {
    http_response_code(404);
    exit('Page not found.');
}
echo htmlspecialchars($post['title'], ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');

For a multilingual system, include the language in the lookup and design uniqueness around the language/slug pair. Draft and scheduled content must follow the application's publication rules. A clean-looking URL does not enforce those rules.

Generate a slug without breaking Turkish characters

Use an explicit character map instead of a replacement pattern that maps letters incorrectly. This function is for new records, not for regenerating established URLs. It is not a general transliteration solution for every writing system.

PHP
<?php
function makeSlug(string $title): string {
    $text = strtr($title, [
        'Ç' => 'C', 'Ğ' => 'G', 'İ' => 'I',
        'Ö' => 'O', 'Ş' => 'S', 'Ü' => 'U',
        'ç' => 'c', 'ğ' => 'g', 'ı' => 'i',
        'ö' => 'o', 'ş' => 's', 'ü' => 'u',
    ]);
    $slug = trim((string) preg_replace('/[^a-z0-9]+/', '-', strtolower($text)), '-');
    if ($slug === '' || strlen($slug) > 160) {
        throw new InvalidArgumentException('Slug is empty or too long.');
    }
    return $slug;
}
echo makeSlug('İçerik Yönetimi: Çığ, Şube ve Ölçü');
// icerik-yonetimi-cig-sube-ve-olcu

Identical titles can produce identical slugs. An application-level existence check alone does not prevent a concurrent insert race; use an appropriate unique index and conflict handling. Resolve conflicts for new records through a defined suffix or identifier policy.

Test address behaviour before publishing

Check that a valid slug selects the correct post and an unknown one returns an actual 404 status. An array input such as slug[]=x should produce the error page, not a database exception. Choose one preferred trailing-slash form. If you genuinely migrate a URL, redirect the old address to its corresponding replacement with 301 rather than sending every old page to the home page. Build canonical URLs from a trusted configured origin, not an unchecked request Host header.

References: Apache RewriteRule flags and PHP strtr.

Related Articles

Comments (0)

No comments yet. Be the first to comment!

Leave a Comment