« back

Integrating TinyMCE with plugins McImageManager and McFileManager into CakePHP

Posted Feb 26th 2010, 11:04 by PaulGardner

Are you a developer using CakePHP in the North East of England? If so, get in touch if you would be interested in being part of a group of developers who meet up once or twice a month to bounce ideas off one another.

A long overdue introduction to WYSIWYG editing

I have been developing bespoke CMS sites for many years now and for some unknown reason always steered clear of WYSIWYG editors.  That was until I had a play with Wildflower CMS, which I had seen mentioned by a few people in CakePHP's Google Group.

I used Wildflower CMS to develop a little website for Weardale Open Air Swimming Pool association (WOASPA), Durham's only heated outdoor swimming pool where I used to swim as a kid, and I was impressed by their inclusion of TinyMCE as it made the client's job so much easier to have word processor type functions available for them when editing pages and blog posts.

Wildflower CMS has not met my needs for future jobs and I had concerns about the lack of activity in their forum, but WOASPA are very happy with their site so it's worth a look for yourself to decide if it would fit your needs.

So with a new found respect for WYSIWYG editors I set about integrating TinyMCE into my next project and it's been very well recieved by recent clients

What comes next? Plugins of course!

Once I had TinyMCE integrated it was only logical that I started looking at available plugins, especially as my next few jobs relied heavily on imagery and required the ability to manage those images through the CMS. 

With MoxieCode (the developers of TinyMCE) currently being my flavour of the day and wanting to find a solution which seemlessly integrated with TinyMCE I bit the bullet and paid €82 for their McImageManager and McFileManager plugins and once again I was very happy with my choice.

I have mentioned my use of TinyMCE and these plugins in CakePHP's Google Group and have been asked to share my integration so I thought I would write it up and share it here, I hope if it's of some use.

Download and upload TinyMCE

Did I forget to mention that TinyMCE is free?  Now that's always welcome news.  MoxieCode have made TinyMCE free, but charge for their File and Image Manager plugins (I call them plugins, but they also work as standalone scripts). 

Go to their downloads page and grab the Main package.  There is a jQuery package there too, but I opted for the Main package, experiment at will yourself.

Unzip your downloaded package and upload it to /app/webroot/js/tiny_mce.

Integrating TinyMCE, Bakery to the rescue

My first port of call when trying to do something new in Cake is to visit the Bakery, normally via a Google search, and I chose to use a quick helper supplied by C.James Callaway (see comment 19).  So I was off to a flying start by saving the following helper to /app/views/helpers/tiny_mce.php.

<?php

/***********************************************************************
 *
 * Quick TinyMCE Helper for CakePHP
 * Author: C.James Callaway (http://www.cybergod.net) - 08/04/2008
 */

class TinyMceHelper extends HtmlHelper {
    var $helpers = array('Javascript');
    var $defaults = array(
      'theme'=>'default',
      'width'=>'99.9%',
      'plugins'=>'safari,table,advimage,imagemanager,advlink,filemanager,paste,inlinepopups',
      'dialog_type'=>'modal',
      'convert_urls'=>true,
      'relative_urls'=>false
    );

    function beforeRender() {
      $view = ClassRegistry::getObject('view');
      if (is_object($view)) {
        $view->addScript($this->Javascript->link('tiny_mce/tiny_mce'));
      }
    }

    function init($options = false) {
      if($options){
        $options = Set::merge($this->defaults, $options);
      }
      $code='tinyMCE.init('.json_encode($options).');';
      return $this->Javascript->codeBlock($code);
    }
}

Notice that I have various default settings specified in the $defaults var, these can be overridden when initiating the editor in your view, but you should include your most common settings here so you do not have to keep defining them in your views. 

It is not the scope of this article to explain all of TinyMCE's configuration settings, so for more information on how to configure the editor go to MoxieCode's Wiki or API.

Next was to amend my helpers array in /app/app_controller.php to include the TinyMce helper:

var $helpers = array('Html', 'Form', 'Time', 'Javascript', 'TinyMce');

As the helper's beforeRender() method includes the script, all I needed to add to the view is the 5 lines at the top of the following

<?php echo $tinyMce->init(array(
  'mode'=>'exact',
  'elements'=>'ArticleBody',
  'height'=>'500'
)); ?>

<h1>Add Article</h1>
<?php $session->flash('flash'); ?>
<?php
echo $form->create('Article');
  echo $form->input('Article.title');
  echo $form->input('Article.summary');
  echo $form->input('Article.body');
echo $form->end('Submit');
?>

Here, I have passed in three settings which will override any defaults in the helper.  The mode and elements settings define that the editor should only initiate on the field ArticleBody. If I had not included these TinyMCE would have initiated for all textareas and I did not want summary to have an editor.  The height setting defines the height of the editor.

This should be all you need to get TinyMCE working using the default theme. Simples!

Editing the Theme

To edit which buttons are available and whether they appear at the top or bottom of the editor you need to edit the config file found at /app/webroot/js/tiny_mce/themes/default/editor_template.js

I have only played with the ed.settings and t.settings arrays found at the top of the init function

init : function(ed, url) {
  var t = this, s, v, o;

  t.editor = ed;
  t.url = url;
  t.onResolveName = new tinymce.util.Dispatcher(this);

  // Default settings
  ed.settings.skin = "o2k7";
  ed.settings.skin_variant = "silver";

  t.settings = s = extend({
    theme_default_path : true,
    theme_default_toolbar_location : "top",
    theme_default_toolbar_align : "center",
    theme_default_buttons1 : "undo,redo,|,bold,italic,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,bullist,numlist,blockquote,charmap,|,link,unlink,anchor,image,insertfile",
    theme_default_buttons2 : "formatselect,|,tablecontrols,|,cleanup,code",
    theme_default_buttons3 : "",
    theme_default_blockformats : "p,h2,h3,h4",
    theme_default_row_height : 23,
    theme_default_resize_horizontal : 1,
    theme_default_resizing_use_cookie : 1,
    readonly : ed.settings.readonly
  }, ed.settings);
...

The ed.settings arrray defines that I want to use the o2k7 skin with the silver variant which comes packaged with TinyMCE and the t.settings array defines the toolbars position, alignment, buttons, etc. More information on themes is available within the MoxieCode Wiki and API.

Installing the Plugins

If you do not want the Image and File Manager plugins, or if you are going to try installing one of the free Image Manager solutions, then there is no need to read on.  Still with me? Well it's great to have you, let's continue!

Now you can't download and trial these plugins, you have to purchase them before you can download them, but both plugins have online demo's available for you to try before you buy.  The best way to demo them is to go to the TinyMCE full featured example and click on the last two icons (Insert file/image).

So go to their pages .. have a play and purchase your licenses.  Once you have done so, download the packages, unzip and upload to /app/webroot/js/tiny_mce/plugins/[image|file]manager.

You then need to make sure you include the plugins when you initiate the editor.  If you go back to my helper code you can see if have the following pluins defined

...
'plugins'=>'safari,table,advimage,imagemanager,advlink,filemanager,paste,inlinepopups',
...

A quick overview of my plugin choices:

  • safari: corrects some issues in the Safari browser
  • table: allows for control of tables
  • advimage: includes advanced image options
  • imagemanager: includes the newly image manager plugin
  • advlink: makes the browse button when adding a link open the file manager plugin
  • filemanager: includes the file manager plugin
  • paste: improves TinyMCEs ability to deal with cut and pasted code
  • inlinepopups: makes TintMCE windows model boxes rather than seperate windows

Plugin Configuration

Next we need to configure our plugins to define the folders where we are going to be saving images/files and how the plugins are going to authorise user access.

We need to edit /app/webroot/js/tiny_mce/plugins/[image|file]manager/config.php and edit the following settings

...
// Preview options
$mcImageManagerConfig['preview.wwwroot'] = '/home/username/public_html';
$mcImageManagerConfig['preview.urlprefix'] = "http://www.website.co.uk";
...
// General filesystem options
$mcImageManagerConfig['filesystem.path'] = '../../../../uploads';
$mcImageManagerConfig['filesystem.rootpath'] = '../../../../uploads';
...
// Authenication
$mcImageManagerConfig['authenticator'] = "ExternalAuthenticator";
...
// ExternalAuthenticator config
$mcImageManagerConfig['ExternalAuthenticator.external_auth_url'] = "/users/mcAuth";
$mcImageManagerConfig['ExternalAuthenticator.secret_key'] = "ASecretKeyOfYourChoice";
...

I have paraphrased a lot of the file, missing out all of the unchanged settings.  The above comes from the filemanager/config.php but it's exactly the same settings that we need to define in imagemanager/config.php just the array is called $mcFileManagerConfig.

The preview options define where the plugin should look to find previews.  The general filesystem options define relative paths from the script to /app/webroot/uploads.  You must create this folder and give the server write access to it (I do this via SSH using chmod -R apache:apache /home/username/public_html/app/webroot/uploads).

The last 3 settings deal with how the plugin authenticates whether a user has access to the folder they are trying to access.  Setting authenticator to ExternalAuthenticator means we are defining where the plugin requsts auth information from.  ExternalAuthenticator.external_auth_url defines the controller/action we are going to authenticate at, in this case /users/mcAuth, and ExternalAuthenticator.secret_key is a key passed from the plugin to the authenticating method.

Authenticating Requests and Customising User Settings

I am assuming your app is using the Auth component, if not this section may require some alteration. 

We have already specified that the plugins are going to make a request to /users/mcAuth for each request so we now need to create that method along with it's view and layout.  So open your users controller and add the following

function mcAuth() {
  $secretKey = "ASecretKeyOfYourChoice";
  if (!$this->Session->check('Auth.User.id')) die("You are not logged in.");
  $user_id = $this->Session->read('Auth.User.id');
  $doc_root = '/home/username/public_html/';
  $config = array(
    'filesystem.path' => $doc_root.'uploads/users/'.$user_id,
    'filesystem.rootpath' => $doc_root.'uploads/users/'.$user_id
  );
  $this->set('config', $config);
  $key = md5(implode('', array_values($config)) . $secretKey);
  $this->set('key', $key);
  $this->layout = 'mc_remote';
}

You'll notice the first line defines a secretKey variable, this needs to exactly match the value you specified in your plugin config. I then check to see if the user is logged in, if not a issue a die() command.  If so I fetch the users id, define the root and set use that when redefining the filesystem.path and filesystem.rootpath values which override the values we gave in the plugin's config.php file.  This means that a users images and files will be stored in their own directory (they can create sub directories in the plugins) and only they can get access to them.

Finally we encrypt the config setting with the secret key and pass the config array and key to the view before setting an alternate layout.

The View and Layout

These are very simple.

/app/views/users/mc_auth.ctp

<form method="post" action="<?php echo htmlentities($_GET['return_url']); ?>">
<input type="hidden" name="key" value="<?php echo htmlentities($key); ?>" />
<?php
	foreach ($config as $key => $value) {
		echo '<input type="hidden" name="' . htmlentities(str_replace('.', '__', $key)) . '" value="' . htmlentities($value) . '" />';
	}
?>
</form>

This creates a form containing the secret key and our customised user settings.

/app/views/layouts/mc_remote.ctp

<html>
<body onload="document.forms[0].submit();">
  <?php echo $content_for_layout; ?>
</body>
</html>

And the layout automatically submits the form.

Conclusion

And that's that ... no doubt there will be some issues in my code somewhere, feel free to notify me by commenting below. 

I will also create a few other blog posts about initiating standalone instances of the plugins, integrating Syntax Highlighter into TinyMCE (used to highlight the code in this article) and some work I have been doing with phpThumb which extracts images from the HTML TinyMCE produces and creates any sized thumbnails you require.

Happy baking, and see you in the Google Group.

Tags: mcfilemanager mcimagemanager image upload file upload tinymce cakephp

2 Comments

  1. Mar 31st 2011, 20:26 by tomfumb

    Thanks for providing the info - I'm currently integrating MCFileManager with a CakePHP site and this has helped a lot. However it would be good if you could explain why you are hashing config values - I understand this overrides the MCFile/ImageManager's config.php settings (so you can get the values from Config::read()) but I found little documentation online for this approach.

  2. Apr 15th 2011, 14:03 by PaulGardner

    Glad you found this information useful and really sorry for the delayed reply.

    It was some time back that I set this up, but you have to encrypt (MD5) the values with the $mcFileManagerConfig['ExternalAuthenticator.secret_key'] you specify in the config settings. If the values are not decrypt-able with the key they will not be accepted.

Leave a comment

Why not leave a comment for the author and others to read?

Get In Touch

Keep In Touch

Twitter Updates

    follow us on Twitter