Add Trailing Slash to CakePHP

By Marc Grabanski (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:

Download code <?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
Download code 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 709

CakePHP Team Comments Author Comments
 

Comment

1 Cool

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 =)
Posted Jun 18, 2008 by Matthew Harris
 

Comment

2 Thanks

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 Mar 18, 2009 by Josenivaldo Benito Junior
 

Comment

3 Overload redirect method

@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 Mar 18, 2009 by Josenivaldo Benito Junior
 

Comment

4 small correction to my last comment

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 Mar 18, 2009 by Josenivaldo Benito Junior