Making Codeigniter clean URLs cleaner

Posted on the May 10th, 2010 under Codeigniter,Programming by Sukumar

Usually when working with codeigniter you come across the use case where you need to remove the extra “index” appearing in the URL for purposes ranging from shorter URLs to SEO.

For example,

Current URL style: http://example.com/controller/method/category1/category2/page-name
Target URL style: http://example.com/category1/category2/page-name.html


As you can see, the difference in the target URL is the absence of the controller name and the method name and the presence of the extension “.html”. Now, lets see how to achieve this and why the extra extension is required.

Below is my version of .htaccess.

RewriteEngine on

RewriteRule ^([a-z0-9_-]+)\.html$ index.php/page/$1 [L]

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond $1 !^(index\.php|asset|robots\.txt)
RewriteRule ^(.*)$ index.php/$1 [L]

The line that is extra is 3 which redirects all the requests for “.html” files to the controller named “page”.

Now, lets look at the page controller which will handle these requests.

<?php if (!defined('BASEPATH')) exit('No direct script access allowed');

class Page extends Controller
    {

    function __construct()
    {
        parent::Controller();
    }

    function _remap()
    {
        $segment_count = $this->uri->total_segments();
        $segments = $this->uri->segment_array();

        if($segment_count == 0)
        {
            $this->data['title'] = 'UB Group Wines Division';
            $this->load->view('home', $this->data);
        }
        elseif($segment_count == 2) // Single page
        {
            $page_url = $segments[2];
            // Handle the page request
        }
        elseif($segment_count == 3) // Page with category
        {
            $category = $segments[2];
            $page_url = $segments[3];
            // Handle the category + page request
        }
    }
}

In this way you can have pages with smaller and cleaner URLs.

Tips:
1. You can use any extension you like. e.g; in case you have static HTML files to server, you can use the extension “.html” for static and “.htm” for non-static files.
2. You can have any number of URL stubs before the “.html” extension and you can access all these stubs in the controller.

Cons:
1. The URL needs an extra extension.
2. Only one controller per extension.

Do let me know what you think about this or if there is any way to improve on this.

Related posts:

  1. Codeigniter: Separating reads and writes for scaling MySQL Generally websites average a ratio of 9:1 or more for...

Tags: , , ,

7 Responses to 'Making Codeigniter clean URLs cleaner'

Subscribe to comments with RSS
  1. Ruben Müller said, on May 12th, 2010 at 4:08 am

    Why don’t you use the routes.php?
    http://codeigniter.com/user_guide/general/routing.html

  2. Bob said, on May 12th, 2010 at 8:31 am

    I’m wondering why you would want the extension (.html, .htm, .php, whatever). If you’re looking for shorter, cleaner URLs, why not:

    Current: http://example.com/controller/method/category1/category2/page-name
    Target : http://example.com/controller/method/category1/category2

    or to really chop it up:

    Target : http://example.com/category1/category2

    I suppose it makes a difference if your controller/method names are married to your site structure (i.e., http://example.com/products/view/cat1/cat2) or not (http://example.com/whichpage/displayproducts/cat1/cat2) but at least to the way I code, I’m not seeing the benefits of this method.

    Cheers,
    Bob

  3. Sukumar said, on May 13th, 2010 at 9:26 pm

    @Ruben

    Using routes is an option. But in order to get URLs like

    http://example.com/category1/category2/page-name

    without the controller name and the method name (‘index’ for example); the route would be (Please note that I haven’t tested this below route)

    $route['(:any)'] = "page/$1";
    

    Then you would be able to use any other controller since all the requests are routed to “page” controller.

    Do let me know if there is a better routing method I missed.

    @Bob

    The main reasons I didn’t want

    Target : http://example.com/controller/method/category1/category2

    is because my URLs would have looked like

    http://example.com/page/index/category1/category2

    AFAIK, google considers the URL segments to be more important the closer they are to the domain name.

    Yes,

    Target : http://example.com/category1/category2

    is quite possible and using routes at that. However, I think we wouldn’ t be able to use other controllers because of this (Unless we have some filter that checks for the existence of the controller and then the category). Using extensions helps to map a particular extension to a specific controller whithout affecting any other controllers.

    One of the main use cases I can think of is for a small blog similar to wordpress.

    Hope that makes sense :)

  4. Henry Weismann said, on May 25th, 2010 at 6:21 am

    How about:

    Current Url: http://example.com/controller-method/category1/category2
    OR
    Current Url: http://example.com/subfolder-controller-method/category1/category2

    is because my URLs would have looked like

    Target Url: http://example.com/index.php/controller/method/category1/category2
    OR
    Target Url: http://example.com/index.php/controller/method/index/category1/category2


    RewriteEngine on

    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond $1 !^(index\.php|asset|robots\.txt)
    RewriteRule ^([^/.]+)-([^/.]+)-([^/.]+)/(.*)$ index.php/$1/$2/$3/$4 [L]

    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond $1 !^(index\.php|asset|robots\.txt)
    RewriteRule ^([^/.]+)-([^/.]+)/(.*)$ index.php/$1/$2/$3 [L]

    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteCond $1 !^(index\.php|asset|robots\.txt)
    RewriteRule ^(.*)$ index.php/$1 [L]

    Using Routes:

    $route['^([^/.]+)-([^/.]+)/(.*)'] = "$1/$2/$3";
    $route['^([^/.]+)-([^/.]+)-([^/.]+)/(.*)'] = "$1/$2/$3/$4";

    I have no idea if that will work as I just wrote it now. Feel free to test it.

  5. Henry Weismann said, on May 25th, 2010 at 6:35 am

    Should read:

    Target Url: http://example.com/index.php/controller/method/category1/category2
    OR
    Target Url: http://example.com/index.php/subfolder/controller/method/index/category1/category2

  6. Sukumar said, on May 25th, 2010 at 6:55 am

    @Henry,

    Your code looks good, but my aim is to remove the controller and the method name from the URL.

    Target URL style: http://example.com/category1/category2/page-name

    Your method is useful to merge the forward slashes in the URL.
    Useful code nevertheless, thanks!

  7. rezronam said, on July 15th, 2010 at 8:59 pm

    Hi, It’s not working for me, I tried to put the .htaccess, index.php is still there. Sorry I’m new to CI.

Leave a Reply
XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>