Permalinks tutorial

Permalinks tutorial

6 102145
Permalinks tutorial

Permalinks tutorial

What are permalinks? Actually, they are just various links to entries of your website. Long ago, nearly all hyperlinks were permalinks, just because all content was static (static html pages). Later, with the development and popularization of programming languages, dynamic links began to appear. As example: dynamic listings of members, blogs, photos, etc. We ourselves can determine the permalinks scheme, in order to make them more friendly. As always, Rewrite engine (mod_rewrite module) is used to convert urls with different GET params into more human-readable urls.

In the beginning, I recommend that you check if ‘mod_rewrite’ is installed on your Apache server (phpinfo)

Live Demo


download in package


Now you can download the package to follow my explanations.

Step 1 – .htaccess

Firstly, create an empty .htaccess file and paste next code:

<IfModule mod_rewrite.c>
RewriteEngine on
# 1-level
RewriteRule ^home/{0,1}$  index.php?module=home [QSA,L]
RewriteRule ^faces/{0,1}$  index.php?module=faces [QSA,L]
RewriteRule ^clubs/{0,1}$  index.php?module=clubs [QSA,L]
RewriteRule ^photos/{0,1}$  index.php?module=photos [QSA,L]
RewriteRule ^videos/{0,1}$  index.php?module=videos [QSA,L]
RewriteRule ^blog/{0,1}$  index.php?module=blog [QSA,L]
# 2-level
RewriteRule ^home/([^/.]+)/{0,1}$  index.php?module=home&key=$1 [QSA,L]
RewriteRule ^faces/([0-9]+)/{0,1}$  index.php?module=faces&value=$1 [QSA,L]
# 3-level
RewriteRule ^clubs/([^/.]+)/([0-9]+)/{0,1}$  index.php?module=clubs&key=$1&value=$2 [QSA,L]
RewriteRule ^photos/([0-9]+)/([0-9]+)/{0,1}$  index.php?module=photos&value1=$1&value2=$2 [QSA,L]
# all other cases
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule .+ - [L]
RewriteRule ^([^/]+)/{0,1}$ index.php?module=other&key=$1 [QSA,L]

Then, save this file, and upload to the root folder of your project (website). As usual, this is ‘www’ or ‘httpdocs’ folder. Now, let’s back to our rules:

All rules are wrapped with ‘IfModule mod_rewrite’ construction. This is some kind of check if ‘mod_rewrite’ is installed or not. After, I added different permalink rules to different section of our ‘website’ (see – demo page). There are several main sections: home, faces, clubs, photos, videos and blog. Also, there are 2-level and 3-level constructions (links).

In the beginning of every rule you can see ^ anchor. It means – ‘Start-of-line anchor’. Anchor ‘$’ – ‘End-of-line anchor’.

Next flags are used:
‘QSA’ (query string append) – this flag forces the rewrite engine to append a query string part of the substitution string to the existing string, instead of replacing it. Use this when you want to add more data to the query string via a rewrite rule.
‘L’ (last rule) – stop the rewriting process here and don’t apply any more rewrite rules. This corresponds to the Perl last command or the break command in C. Use this flag to prevent the currently rewritten URL from being rewritten further by following rules.

Pay attention, that we can use regular expressions in our rules, like [0-9]+) or ([^/]+). The first expressions is ‘any digit (any length)’, the second is ‘any symbol (any length)’.

Note, that in order to pass params into GET variables, we have to wrap necessary sections in round brackets. The first section will be accessible through ‘$1’ key, second – ‘$2’, and so on.

Step 2 – HTML

in order to give our demo finished look, I prepared a template of our page


<!DOCTYPE html>
<html lang="en" >
    <meta charset="utf-8" />
    <meta name="author" content="Script Tutorials" />
    <title>Permalinks tutorial | Script Tutorials</title>
    <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
    <meta content="width=device-width, initial-scale=1" name="viewport" />
    <!-- define base url -->
    <base href="{url}" />
    <!-- add styles -->
    <link href="css/main.css" rel="stylesheet" type="text/css" />
    <link href="css/responsive.css" rel="stylesheet" type="text/css" />
    <div id="header">
        <!-- logo -->
        <a href="#" id="logo"><img src="images/logo.png"></a>
        <!-- extra top links -->
        <div id="links">
            <a href="about-us/">About us</a>
            <a href="help/">Help</a>
            <a href="contact-us/">Contact Us</a>
        <!-- navigation menu -->
        <div id="navmenu">
            <nav id="menu">
                <input type="checkbox" id="menu_check">
                <label for="menu_check" onclick>&nbsp;</label>
                    <li {mact1}><a href="home/">Home</a>
                            <li><a href="home/facebook/"><span class="icon elem1"></span>Facebook</a></li>
                            <li><a href="home/google/"><span class="icon elem2"></span>Google</a></li>
                            <li><a href="home/rss/"><span class="icon elem3"></span>RSS</a></li>
                            <li><a href="home/skype/"><span class="icon elem4"></span>Skype</a></li>
                            <li><a href="home/stumbleupon/"><span class="icon elem5"></span>Stumbleupon</a></li>
                    <li {mact2}><a href="faces/">Faces</a>
                            <li><a href="faces/1/"><span class="icon elem0"></span>Faces 1</a></li>
                            <li><a href="faces/2/"><span class="icon elem0"></span>Faces 2</a></li>
                            <li><a href="faces/3/"><span class="icon elem0"></span>Faces 3</a></li>
                            <li><a href="faces/4/"><span class="icon elem0"></span>Faces 4</a></li>
                            <li><a href="faces/5/"><span class="icon elem0"></span>Faces 5</a></li>
                    <li {mact3}><a href="clubs/">Clubs</a>
                            <li><a href="clubs/step/1/"><span class="icon elem0"></span>Clubs 1</a></li>
                            <li><a href="clubs/step/2/"><span class="icon elem0"></span>Clubs 2</a></li>
                            <li><a href="clubs/step/3/"><span class="icon elem0"></span>Clubs 3</a></li>
                            <li><a href="clubs/step/4/"><span class="icon elem0"></span>Clubs 4</a></li>
                            <li><a href="clubs/step/5/"><span class="icon elem0"></span>Clubs 5</a></li>
                    <li {mact4}><a href="photos/">Photos</a>
                            <li><a href="photos/10/10/"><span class="icon elem0"></span>Photos 10</a></li>
                            <li><a href="photos/20/10/"><span class="icon elem0"></span>Photos 20</a></li>
                            <li><a href="photos/30/10/"><span class="icon elem0"></span>Photos 30</a></li>
                            <li><a href="photos/40/10/"><span class="icon elem0"></span>Photos 40</a></li>
                            <li><a href="photos/50/10/"><span class="icon elem0"></span>Photos 50</a></li>
                    <li {mact5}><a href="videos/">Videos</a></li>
                    <li {mact6}><a href="blog/">Blog</a></li>
            <!-- search form -->
            <div id="search">
                <form role="search" method="get">
                    <input type="text" placeholder="search..." name="s" value="" autocomplete="off" />
    <!-- main content section -->
    <div class="main">
        <!-- left column -->
        <div class="left">
            <!-- block element -->
            <div class="block">
                <h3 class="head">{title}</h3>
                <h3 class="foot">Footer</h3>
        <!-- right column -->
        <div class="right">
            <div class="block">
                <h3 class="head">{title}</h3>
                    Some extra content. Some extra content. Some extra content. Some extra content.
                <h3 class="foot">Footer</h3>
    <div class="footer">
        Permalinks tutorial (<a href="">Back to original tutorial</a>)

There are only several template keys in use: {url} (to set a base url), {mact1} – {mact6} (menu active element status), {title} and {explanation} (to place title and some explanation).

Step 3 – PHP


Finally, the code of our main homepage:

// active menu elements, titles and explanations (depending on params)
$sMac1 = $sMac2 = $sMac3 = $sMac4 = $sMac5 = $sMac6 = '';
$sTitle = $sText = 'Home';
if ($_GET) {
    switch($_GET['module']) {
        case 'home':
            $sMac1 = 'class="active"';
            $sText = 'RewriteRule ^home/{0,1}$  index.php?module=home [QSA,L]';
            if (isset($_GET['key']) && $_GET['key']) {
                $sTitle .= ' - ' . $_GET['key'];
                $sText = 'RewriteRule ^home/([^/.]+)/{0,1}$  index.php?module=home&key=$1 [QSA,L]';
        case 'faces':
            $sMac2 = 'class="active"';
            $sTitle = 'Faces';
            $sText = 'RewriteRule ^faces/{0,1}$  index.php?module=faces [QSA,L]';
            if (isset($_GET['value'])) {
                $sTitle .= ' - ' . (int)$_GET['value'] . ' page';
                $sText = 'RewriteRule ^faces/([0-9]+)/{0,1}$  index.php?module=faces&value=$1 [QSA,L]';
        case 'clubs':
            $sMac3 = 'class="active"';
            $sTitle = 'Clubs';
            $sText = 'RewriteRule ^clubs/{0,1}$  index.php?module=clubs [QSA,L]';
            if (isset($_GET['key']) && isset($_GET['value'])) {
                $sTitle .= ' - ' . (int)$_GET['value'] . ' ' . $_GET['key'];
                $sText = 'RewriteRule ^clubs/([^/.]+)/([0-9]+)/{0,1}$  index.php?module=clubs&key=$1&value=$2 [QSA,L]';
        case 'photos':
            $sMac4 = 'class="active"';
            $sTitle = 'Photos';
            $sText = 'RewriteRule ^photos/{0,1}$  index.php?module=photos [QSA,L]';
            if (isset($_GET['value1']) && isset($_GET['value2'])) {
                $sTitle .= ' - ' . (int)$_GET['value1'] . ' : ' . (int)$_GET['value2'];
                $sText = 'RewriteRule ^photos/([0-9]+)/([0-9]+)/{0,1}$  index.php?module=photos&value1=$1&value2=$2 [QSA,L]';
        case 'videos':
            $sMac5 = 'class="active"';
            $sTitle = 'Videos';
            $sText = 'RewriteRule ^videos/{0,1}$  index.php?module=videos [QSA,L]';
        case 'blog':
            $sMac6 = 'class="active"';
            $sTitle = 'Blog';
            $sText = 'RewriteRule ^blog/{0,1}$  index.php?module=blog [QSA,L]';
        case 'other':
            if (isset($_GET['key'])) {
                $sTitle = 'Other - ' . $_GET['key'] . ' (or, error 404, not found)';
                $sText = 'RewriteRule ^([^/]+)/{0,1}$ index.php?module=other&key=$1 [QSA,L]';
} else {
    $sMac1 = 'class="active"';
// Display main page
$aKeys = array(
    '{url}' => '',
    '{mact1}' => $sMac1,
    '{mact2}' => $sMac2,
    '{mact3}' => $sMac3,
    '{mact4}' => $sMac4,
    '{mact5}' => $sMac5,
    '{mact6}' => $sMac6,
    '{title}' => $sTitle,
    '{explanation}' => $sText,
echo strtr(file_get_contents('templates/index.html'), $aKeys);

As you see, depending on params – this code generates different titles and explanation texts for our template. Also it passes the base ‘website’ url.

Live Demo


That’s all for today. I hope, that from now on you are able to apply your knowledge in practice in order to build friendly permalinks for your own projects. Good luck and welcome back



  1. Thank you very much for sharing your knowledge with the community, are helpful
    This very well.
    A hug and psyche as well.

  2. Thank you. This is the first tutorial which clearly explained to me how rewrite rules work. Earlier I tried to read other tutorials and they were not very helpful. Still I think “all other cases” section needs to be explained in more details. Blind copypasting the code doesn’t help to understand.

  3. The code is fine but can’t we code it in easy way , i mean lets store the permalink of any page in DB (i am talking of dynamic website) and map it when some Post id or something match ???

    • Hi Shahid,
      It doesn’t matter how you generate the code (HTML). Our tutorial tells you how to handle with links (using the .htaccess file)

Leave a Reply