Add Trailing Slash to CakePHP

This article is also available in the following languages:
By grabanski
How to add a trailing slash to URLs in CakePHP using .htaccess and app helper.
I wanted to add a trailing slash to URLs in CakePHP. Why?
  • There is speculation that it matters for SEO to have the trailing slash. For instance, Wordpress still has a trailing slash on URLs, which that community is obsessive with SEO practices so I look to them as a sort of de-facto standard.
  • I wanted CakePHP to do my bidding and learn in the process about URL handling
In my app_helper.php, I over wrote the url function to check to see if there already is a trailing slash, or there is a file extension and then added the trailing slash if not.

Helper Class:

<?php <?php
class AppHelper extends Helper {
    function 
url($url null$full false) {
        
$routerUrl Router::url($url$full);
        if (!
preg_match('/\\.(rss|html|js|css|jpeg|jpg|gif|png|xml?)$/'strtolower($routerUrl)) && substr($routerUrl, -1) != '/') {
            
$routerUrl .= '/';
        }
        return 
$routerUrl;
    }
}
?>?>
You may need to add more file extensions if you use them.

I also added 301 redirects to include the trailing slash on URL requests in my app level .htaccess
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_URI} !(\.[a-zA-Z0-9]{1,5}|/)$
#RewriteRule ^(.*)$ http://domain.com/$1/ [L,R=301]
RewriteRule ^(.*)$ http://domain.com/$1/ [L,R=301]
You will need to change domain.com to your domain.

Whether or not it matters to add the trailing slash is speculative, however if you want to this is how I made it work.

Comments

  • Posted 02/17/11 05:57:43 PM
    Good Solution, I'm wondering why you don't use the same regular expression for apache and the helper method. I think I could come up with a few URLs using $html->url() that would have to redirect via .htaccess. That seems a little counter-productive. I like the regexp you use in .htaccess better than the one you use in your helper class. Just my thoughts.
  • Posted 09/03/10 04:14:54 PM
    Dunno what the others' experiences were, but this worked like a charm for me.
  • Posted 12/18/09 01:15:06 PM
    I added the helper code to /app/views/helpers/app_helper.php and I added your .htaccess to the end of /app/.htaccess and it doesn't work.
  • Posted 03/18/09 11:32:03 PM
    Just a correction to my thoughts:

    I said that Router::url deliberately remove the trailing slash what is true for a $url parameter being an array. Besides that Router::url() WILL NOT remove the trailing slash for full path URL. Therefore, a overloaded redirect method that uses full path URL will work adding trailing slash to redirect URL. I.e.:

    function redirect( $url, $status = NULL, $exit = true ) {
    $routerUrl = Router::url($url,true);
    if (!preg_match('/\\.(rss|html|js|css|jpeg|jpg|gif|png|xml?)$/', strtolower($routerUrl)) && substr($routerUrl, -1) != '/') {
    $routerUrl .= '/';
    }
    parent::redirect($routerUrl,$status,$exit);
    }

    However, as described in my last post, it will make no difference if you have a rewrite rule adding trailing slashes for you at .htaccess. Besides that a redirect method solve all redirect problem but leaves open the user opportunity to type URL without trailing slash at the very first time and a controller making use of any Router::url will need to care alone about trailing since Router::url is not overloaded to care about trailing slashes. The rewrite solution closes these three opportunities and avoid redirect overload necessity.

    Regards,
    Benito.
  • Posted 03/18/09 11:13:44 PM
    @Mathew,

    I was looking a way to overload redirect method as you suggested. I agreed with that redirect will not care about trailing slash and this is not what I want. However, the redirect method use the Router::url that deliberately remove slashes at the and of URLs.

    Although, I saw now way to override this Router::url() behavior, I've figured out that redirect will use HTTP header "Location:" which makes browsers to request a new address to server. This way, the mod_rewrite rules proposed here will take care of trailing slash and no redirect or Router::url() overloading will be necessary.

    However, for me the rules propose here won't work since I can't use domain name hard coded in .htaccess file. Now I am trying to figure out a way to add slash at the end of an URL without need to use hard coded domain name. Suggestions are welcome.

    Best Regards,
    Benito.
  • Posted 03/18/09 10:04:51 PM
    Hi,

    Thanks. The part of rewrite rules does not work for me since I can put the domain name in there. I am still looking for a server redirect solution.

    Although I agreed with Matthew's comment about parent::url method I don't know if the parent::url() will handle well the modified URL. My suggestion is, instead of put it after modify the URL, use parent::url to actually get the URL. I mean, instead of use Router::url() to get the $returnUrl, use parent::url to do it. Some will argue that AppHelper::url (original method) has only a call to Router::url and because it doesn't matter call one or another. I agree that this is true today. But if someday the Cake team modify AppHelper class (the url method of this class) the overloaded method will no longer have the same functionality as before. Using parent::url() instead of Router::url() will avoid any changes to parent class being missed by overloaded method.

    Regards,
    Benito.
  • Posted 06/18/08 10:27:44 PM
    This is interesting, and I have some suggestions.

    1) I think you should call the parent url() method after you've made changes to the URL.

    2) You should probably add the some method overloading for the redirect() method.

    I don't know how much this matters to some people, but if you're obsessive about SEO, I suppose this is one of those must-do solutions =)

Comments are closed for articles over a year old