One of the main concerns most applications have is optimizing their content for search engines, so that their sites rank as high as possible on most engines. Among several recommendations found in most SEO (Search Engine Optimization) guides, building URLs that include relevant keywords is one of the most effective ones.
If we are building a content-based site, this is achievable by making sure that permanent links to each item include most of the words that are part of the item title. As an example, if we have a post whose title is Top 10 CakePHP Behaviors, an SEO-friendly URL could be:
http://localhost/articles/view/top-10-cakephp-behaviors
.
The top-10-cakephp-behaviors
part is commonly known as a slug, a part of the URL that uses relevant keywords. In this recipe, we will learn how to use the publicly available Sluggable
behavior to automatically add slugs to our application.
The Sluggable
behavior is one of the many classes I released as open source to help fellow CakePHP developers. Feel free to send me any feedback.
To go through this recipe, we need a sample table to work with. Create a table named posts
, using the following SQL statement:
CREATE TABLE `posts`( `id` INT UNSIGNED AUTO_INCREMENT NOT NULL, `slug` VARCHAR(255) NOT NULL, `title` VARCHAR(255) NOT NULL, `text` TEXT NOT NULL, PRIMARY KEY(`id`), UNIQUE KEY `slug`(`slug`) );
We proceed now to create the required model. Create the model Post
in a file named post.php
and place it in your app/models
folder, with the following contents:
<?php class Post extends AppModel { public $validate = array( 'title' => array('rule' => 'notEmpty'), 'text' => array('rule' => 'notEmpty') ); } ?>
Create its appropriate controller PostsController
in a file named posts_controller.php
and place it in your app/controllers
folder, with the following contents:
<?php class PostsController extends AppController { public function add() { if (!empty($this->data)) { $this->Post->create(); if ($this->Post->save($this->data)) { $this->Session->setFlash('Post created'), $this->redirect('/'), } else { $this->Session->setFlash('Please correct the errors'), } } } } ?>
Create a folder named posts
in your app/views
folder, then create the view to hold the form in a file named add.ctp
and place it in your app/views/posts
folder, with the following contents:
<?php echo $this->Form->create(); echo $this->Form->inputs(array( 'title', 'text' )); echo $this->Form->end('Create'), ?>
Finally, we need to download the Syrup plugin for CakePHP. Go to http://github.com/mariano/syrup/downloads and download the latest release. Uncompress the downloaded file into your app/plugins
folder. You should now have a directory named syrup
inside app/plugins
.
Sluggable
behavior to the Post
model. Edit your app/models/post.php
file and add the $actsAs
property:<?php
class Post extends AppModel {
public $actsAs = array('Syrup.Sluggable'),
public $validate = array(
'title' => array('rule' => 'notEmpty'),
'text' => array('rule' => 'notEmpty')
);
}
?>
PostsController
class:public function index() { $this->paginate['limit'] = 10; $posts = $this->paginate(); $this->set(compact('posts')); }
views/posts/index.ctp
with the following contents:<div class="paging"> <?php echo $this->Paginator->prev(); ?> <?php echo $this->Paginator->numbers(); ?> <?php echo $this->Paginator->next(); ?> </div> <br /> <ul> <?php foreach($posts as $post) { ?> <li><?php echo $this->Html->link($post['Post']['title'], array('action'=>'view', $post['Post']['slug'])); ?></li> <?php } ?> </ul>
Next, create the action to view a post by slug. Add the following method to the PostsController class:
public function view($slug) { $post = $this->Post->find('first', array( 'conditions' => array('Post.slug' => $slug), 'recursive' => -1 )); $this->set(compact('post')); }
Create the view views/posts/view.ctp
with the following contents:
<h1><?php echo $post['Post']['title']; ?></h1> <p><?php echo $post['Post']['text']; ?></p> <?php echo $this->Html->link('Posts', array('action'=>'index')); ?>
After creating some posts using the form at http://localhost/posts
, the list of posts could look like the following screenshot:
http://localhost/posts/view/automatic-tasks-with-cakephp
The Sluggable
behavior implements the beforeSave
callback to automatically add the generated slug on the specified field. It ensures that all generated slugs are unique, and provides a full set of options to modify how a slug is generated. The following options can be specified when attaching the behavior to a model:
Option |
Purpose |
---|---|
|
List of words that should not be part of a slug. Optional, and defaults to: |
|
Field name (string), or list of field names (in an array) that are used to create the slug. Defaults to a single field named |
|
Maximum length of the generated slug. Defaults to |
|
If set to |
|
If set to |
|
Character to use when separating words in the slug. Defaults to |
|
Name of the field where the slug is stored. Defaults to |
18.191.67.40