How to advance our CMS in CakePHP


At the end of part one, we had a working CMS.  Well, at least it was saving files and they could be displayed to the public.  In today’s article, we are going to further advance our CMS.  We will cover the following items:

  1. fckEditor
  2. Revisions

Adding fckEditor should be the easiest process to the whole CMS.  Download the latest version of fckEditor ( and extract it to app/webroot/js.  Now we need to update our pages_controller to load the JavaScript array helper when we are adding or editing a file.  Simply update the $helpers array to include Javascript:

var $helpers = array(‘Html’, ‘Form’, ‘Javascript’);

Now, we need to update our app/views/pages/add.ctp and edit.ctp.  Include the following lines at the top of the file:

[code]<?php echo $javascript->link(‘fckeditor/fckeditor’, false); ?>
<?php echo $javascript->codeBlock(‘
window.onload = function() {
 var oFCKeditor = new FCKeditor( “PageBody” ) ;
 oFCKeditor.BasePath = “/CMS/js/fckeditor/” ;
 oFCKeditor.ReplaceTextarea() ;
‘, array(‘safe’ => false, ‘inline’ => false)); ?>

This will now make it a lot easier for our clients, who are most likely non-HTML savy, to add useful content to their web site.

Finally, let’s add a really useful feature – revision history.  We want to accomplish two things here.  One, each time a file is saved, we want to save the previous version and delete all revisions when a page is deleted.  Two, we want to allow our client to view their revision history and restore to a previous version.

Let’s begin.  We’ll start by creating a revision table.  Now, we could simply update our pages table, but I like to separate these two tables.  By putting them together, our pages index will be a lot bigger than it needs to be.

[code]CREATE TABLE  `pages_revisions` (
  `id` int(10) unsigned NOT NULL auto_increment,
  `page_id` int(10) unsigned NOT NULL,
  `title` varchar(255) NOT NULL,
  `body` text NOT NULL,
  `created` datetime default NULL,
  `modified` datetime default NULL,
  PRIMARY KEY  (`id`)

We are going to want to create a model for this table, so let’s use the bakery again.

[code]Start > Run
Type: “cmd” and press enter
Type: “cd \xampplite\htdocs\CMS” and press enter
Type: “cake\console\cake bake” and press enter
Type: “M” and press enter
Press enter to use default database config
Type: “2” and press enter for the PagesRevision model
Type: “n” and press enter
Type: “y” and press enter
Type: “y” and press enter
Type: “n” and press enter
Type: “y” and press enter
Type: “n” and press enter
Type: “Q” and press enter

We have now successfully created our PagesRevision model and associated it to our page model.  To make this process simple and minimize the amout of work, we are going to simply update the beforeSave and afterDelete statements.  In the beforeSave, we will save a copy of the current Page to our PagesRevision model and in our afterDelete statement, we will clean up our PagesRevision and remove all revisions for that page.  Here is our two updated functions in our app/models/page.php:

[code] function beforeSave() {
  // only create revision if id is > 0
  if (!empty($this->data[‘Page’][‘id’])) {
   // import our PagesRevision model
   App::import(‘model’, ‘PagesRevision’);
   // instantiate it
   $this->PagesRevision = new PagesRevision();
  return true;

 function afterDelete() {
  // import our PagesRevision model
  App::import(‘model’, ‘PagesRevision’);
  // instantiate it
  $this->PagesRevision = new PagesRevision();

And here is our updated app/models/pages_revision.php:

[code] function saveRevision($data) {
  // get our current page
  $this->Page->recursive = -1;
  $page = $this->Page->find(‘first’, array(‘conditions’ => array(‘id’ => $data[‘Page’][‘id’])));
  $revision = array(‘PagesRevision’ => array(‘page_id’ => $page[‘Page’][‘id’], ‘title’ => $page[‘Page’][‘title’], ‘body’ =>


 function deleteRevision($page_id) {
  $this->deleteAll(array(‘page_id’ => $page_id), false, false);
[/code]Now every time we save or delete, our code will automatically create a previous copy of the page or it will delete all revisions along with our current page we deleted.

I will leave part two up to you and that is creating a list of revisions and allowing a user to revert back to that version.  To finish let’s summarize what we’ve learned in this two part series:

  • How to use routes
  • How to use the Bakery
  • How to use the callback functions
  • How to include fckEditor

About the author

By Jamie

My Books