Slugs

Adding search engine friendly URL’s (Slugs)

Posted on: August 5th, 2009 by taff No Comments

 

I was looking for a quick way to add search engine optimised URL's to my cakePHP application and was amazed at how fast it was setup.

These are the (extremely simple) steps that I took.
Add a slug field to my database table

ALTER TABLE `the_table_name` ADD `slug` VARCHAR(255) NOT NULL;

Update our table to add slugs, related to the title

For the sake of ease I simply added an extra line to my edit method. This doesn't check anything and will resave the slug whenever the title is changed...but it worked for testing 😉

if (!empty($this->data)) {
$this->data['Controller']['slug'] = Inflector::slug($this->data['Controller']['title_we_want_adapted']);
if ($this->Controller->save($this->data)) { $this->Session->setFlash(__('Saved', true));
} else {
$this->Session->setFlash(__('Not saved. Please try again.', true));
}
}

Note our use of the built in Inflector::slug class method. We should probably have converted to lowercase too.

The next step was to change links that previously pointed to
/path/to/app/controller/method/id
to now point to
/path/to/app/controller/method/the_slug_we_generated

What's left to do? Well if we click on our newly generated link, it probably won't find the row it needs because it will be doing something like:

SELECT * FROM `the_table_name` WHERE `id` = the_slug_we_generated;

I personally already had a beforeFilter() in my controller to prevent users accessing Lists that didn't belong to them so I updated it in the following way to ensure that both slugs and id would work (May come in handy if people have links bookmarked with the old method).

function beforeFilter() {
parent::beforeFilter();
//Are there any parameters for this action, i.e. is it an edit or view
if(isset($this->params['pass'][0])){
$id=$this->params['pass'][0];
//Is it numeric, in which case its an id already (we hope at least)
if(!is_numeric($id)){
//If its a slug, we need the related item.
$new_id=$this->currList=$this->Dolist->find('first',array("conditions"=>array('Dolist.slug'=>$id)));
$id=$new_id['Dolist']['id'];
//So we know it's using a slug
$this->usesSlug=$id;
}
$this->currList=$this->Dolist->find('first', array("conditions"=>array('Dolist.id'=>$id)));
//Check User stuff
if($this->currList['Dolist']['user_id']!=$this->Session->Read('Auth.User.id')){
$this->Session->setFlash("You're not authorised to ".$act." ID:".$this->params['pass'][0]." or it no longer exists");
$this->redirect(array('action'=>'index'));

}

}
}

I then updated my view method

function view($id = null) {
if (!$id) {
$this->Session->setFlash(__('Invalid Dolist.', true));
$this->redirect(array('action'=>'index'));
}
if($this->usesSlug!=0){
$id=$this->usesSlug;
}
//Carry on as normal....

For search engine optimisation we should probably set a redirect in the controller if it's an ID but thats up to you.

Don't you just love how easy things are to setup with cakePHP? 😉