How to make SEO friendly urls

How to make SEO friendly urls

It's now quite common to swap the old url format containing file extensions and non explicit query strings by SEO friendly ones, only made of keywords and slashes, hence their name.

There are several techniques to do so, and I certainly do not have the pretention to say that this one is the best of all, but it is the one I use in personal projects as it works nicely, and it is robust and dynamic.

It makes use of an .htaccess file to rewrite the urls, of a php function to parse the given parameters, and a content manager to serve the appropriate content according to them.

Before we start I'd like to make a personal thanks to Josh Moont for his precious help.

Thank You for Downloading

I'm glad that you found my work useful. If you did, it might help some other people too. So why not helping me spread the word with a tweet? You could also buy me a coffee to thank me for my code and explanations if you prefer ;).
I hope you'll enjoy your download. Regards. Jeremy.

How to setup

Step 1: The .htaccess file

As we've said in the introduction, the first element that stands in the process of rewriting is the .htaccess file. If you do not already have one on the root of your website, just create a file with no name and the extension .htaccess there. Open that file, and copy the following code in it:
  1. RewriteEngine On
  5. ErrorDocument 206 /Error/206
  6. ErrorDocument 301 /Error/301
  7. ErrorDocument 400 /Error/400
  8. ErrorDocument 401 /Error/401
  9. ErrorDocument 403 /Error/403
  10. ErrorDocument 404 /Error/404
  11. ErrorDocument 500 /Error/500
  12. ErrorDocument 503 /Error/503
  14. ## Page rewrite ##
  16. RewriteCond %{REQUEST_FILENAME} !-f
  17. RewriteCond %{REQUEST_FILENAME} !-d
  18. RewriteRule ^(.*)$ index.php?path=$1 [NC,QSA]
Ok so what does that actually mean? Simple. On line 1, we specify that we want to turn on an Apache functionality called Mod_Rewrite. Mod_rewrite is an Apache-based rewrite engine for dynamically rewriting URLs. It's built into Apache servers natively, though not enabled by default, that's why we turn it on here. The lines 3 to 12 are actually beyond the scope of this tutorial but I left them there anyway as they are still useful. In fact they allow you to create a custom error page and to redirect to that page when a specific error happens on your server, the 404 error for example. It's nicer for the user to face a custom error page than the default ones. Let's get back to our rewrite now. On line 16 and 17, we have 2 lines that tell the server NOT to rewrite the urls leading to files that exist on the server, such as images for example, or js files, stylesheets on so on. So in fact, all those files will be accessed in the old fashioned way, and the rewrite will only be focused on pages, which saves a lot of time as you'll understand later on. And Finally, on the last line, that expression specifies that every url, that is not a file, will be sent to the file index.php for analysis under the name "path". NC means it's not case sensitive, and QSA that the redirect still keeps the $_GET variables so in your urls, you can use slashes and also old fashioned query strings. (which is not the point really, but it still works...) This step marks the end of the .htaccess role in our rewrite. To summarize, it doesn't deal with files, and redirects any other url to the index.php under the name "path".

Step 2: Dealing with the parameters

Now that the urls are redirected from the .htaccess, we are going to use slashes in our urls and not query strings anymore. Because this format of url is not understood by the server in the first place, we need a mechanism to parse the given parameters into a form that is going to be useful for the server. In order to do so, we'll use the function get_url_params showed below:
  1. function get_url_params(){
  3. //Get the query string made of slashes
  4. $slashes=explode("/",trim(htmlentities(array_shift($_GET),ENT_QUOTES),"/"));
  6. //Extract the asked page from those parameters
  7. switch(count($slashes)){
  8. case 0:
  9. $params['page'] = "home";
  10. break;
  11. case 1:
  12. $params['page'] = array_shift($slashes);
  13. break;
  14. case ((count($slashes) % 2)==1):
  15. //odd
  16. $params['page'] = array_shift($slashes);
  17. break;
  18. default:
  19. //even
  20. $params['page'] = array_shift($slashes);
  21. $params['myparam'] = array_shift($slashes);
  22. break;
  23. }
  25. //Process the parameters by pairs
  26. $cpt=1;$param="";
  27. if(!empty($slashes)){foreach($slashes as $get){
  28. switch($cpt){
  29. case 1: $param=htmlentities($get,ENT_QUOTES);$cpt=2; break;
  30. case 2: $params[$param] = htmlentities($get,ENT_QUOTES);$cpt=1; break;
  31. }}}
  33. //Process the $_GET parameters if any
  34. if(!empty($_GET)){foreach($_GET as $name=>$get){
  35. $params[$name] = htmlentities($get,ENT_QUOTES);
  36. }}
  38. return $params;
  39. }
Again I remind that there are several methods to do so, but this is the way I like to do. Explanation: First of all, on line 4, we get the "path" sent by the .htaccess file, for analysis, meaning that we split it according to the slashes and we count how many different parts it gives. Here's the principle (there are 4 different possible cases). If we do not have any parameter, the path is empty, we'll therefore display the home page.(lines 8-10) If we only have ONE parameter, it will be the page to display.(line 11-13) If we have an ODD number of parameters, the first one will be the page, and then we'll match up the other parameters by key=>values pairs.(lines14-17) And finally, if we have an EVEN number, the first one will be the page, the second one the subpage, and afther that, again we'll match up the parameters by key=>values pairs.(lines 18-22) Now that we've extracted the page to display from the parameters, we match them up by pairs (lines 25-31). As we've said in the introduction, this method is quite robust as it works with $_GET parameters too. So if there are any specified in the url, we match them up by pairs here, so they will be available later on (lines 33-36). For example, the url /resource/param1/value1/param2=value2, mixing slashes and query strings, will return $params = array("page"=>"resource","param1"=>"value1","param2"=>"value2"); To summarize this step, first we get the path from the .htaccess, we work out the page we want to display from it, and we match the other parameters by key=>values pairs. The parameters are now ready to be used by the content manager.

Step 3: The Content Manager

Once we've nicely reordered the parameters, we need to display the page targeted by the given url. To do so, I like to use a content controller, in order to have an MVC structure. My controller is structured as shown:
  1. require_once("Path_to/Globals.php");
  2. $params = Globals::get_url_params();
  3. $module = $params['page'];
  4. if (!empty($module)) {
  5. switch ($module) {
  6. case "home":
  7. $page = "Path_to/home.php";
  8. break;
  10. case "resources":
  11. $page = "Path_to/resources.php";
  12. break;
  14. case "Error":
  15. $page = "Path_to/error.php";
  16. break;
  17. .
  18. .
  19. .
  20. default:
  21. $page = "Path_to/home.php";
  22. break;
  23. }
  24. } else {
  25. $page = "Path_to/home.php";
  26. }
  29. require_once("Path_to/header.php");
  30. require_once($page);
  31. require_once("Path_to/footer.php");
The get_url_params() function has been put into a separate class called Globals, that's why include that file on line 2. We can then call that function to get the parameters (line 3), and especially the page we want (line 4). We then have a switch case statement that figures out what file needs to be included according to the wanted page. This is how we match the parameters given in the url with the corresponding files. When you want to add a new page to your site, you just have to add a case in this content manager. In lines 34,35 and 36, the manager will finally include the pages for display. I like to use a separate header and footer, containing the code common to every page, it is easier to maintain. There we go, 3 easy steps to make your own friendly url system from scratch! No excuses for those endless and meaningless query strings any more now!

5 Responses to How to make SEO friendly urls

  1. Thanks I wil ltry this at my Tibia aCcount website thanks so much I hope it works with no problems. Its just htat I dont know where to put the php codes.

  2. Great tutorial.

  3. Thanks for the tutorial, you explained it very clearly!

  4. Thanks a lot. I'm mainly using WordPress so I won't need it but once I start making custom websites I'd definitely use this.

    • tesdt

Leave a Reply

Your email address will not be published. Required fields are marked *

Other Useful Resources

How to turn any jQuery plugin into a WordPress one illustration

WordPress and jQuery are both very famous for their plugins. In the case of jQuery, plugins allow developers to extend the library's capacities in order to create beautiful effects. In WordPress, they allow anyone to benefit from the work of others, as they come under the form of a module that you can easily activate from within the administration interface, and start using right away.

Creating one of those modules is not that difficult, but if you are not familiar with their syntax, it could end up being a headache. There are many jQuery plugins that have been transferred into a WordPress one already, but what can you do when it is not the case? How do you do when you have found the perfect jQuery plugin for your latest site, but it is not yet available as a WordPress plugin?

In this tutorial, we'll see how you can easily create a WordPress plugin from a jQuery one. We'll review what a jQuery, or a WordPress plugin is actually made of, so we'll find the elements they both have in common. From there, we'll show how it leads us to perform some simple operations to allow us to benefit from our jQuery plugins in a WordPress template.

Read more
Introducing the Twitter Watch illustration

The Watch is a list of curated quality links about web development. I've been maintaining it for a year now so I thought I would share the results with everyone as this will probably be useful to somebody else. I select the links from Twitter mostly based on their usefulness. They contain interesting reads, points of views, helpful scripts, articles, resources... Well plenty of things worth bookmarking when you are interested in web development.

Read more
How to Create Native Admin Tables in WordPress illustration

WordPress list tables are a very common element of the WordPress admin interface. They are used by nearly all default admin list pages, and also often implemented by developers while writing plugins. However, creating one of those tables is not really an intuitive thing to do when you haven't done it before, and I've seen cases where people where trying to replicate one, with techniques such as using the WordPress CSS classes on personal markup, or even replicating the CSS from scratch.

In this article, we'll see how WordPress provides native functionality that can be used to generate some native admin tables. We'll have a look at a typical WordPress table and its different components, showing how it is possible to implement them the right way.

Read more
RT @pauljadam: Made a New WCAG 2.0 AA #A11y Testing Checklist in Numbers sheet. I'm open to collaborating/updating from feedback. https://t05 Jan / 11:34