Integrating FCKeditor Into CakePHP

January 28th, 2009 | Tags: , ,

There are two different methods of FCKeditor integration to choose from with CakePHP: PHP and JavaScript. I will cover both of them here but I think my personal choice would be using the JavaScript method and replacing the textarea. That way there is a fall back for people with JavaScript turned off. For this example I will be using my previous post about creating a CMS using Cake and adding the famous rich text editor to the add and edit content pages.

The first thing you want to do is download the latest version of FCKeditor. At the time of this writing the current stable version is 2.6.3. You could try the beta version or the nightly build if you feel adventurous but personally I like sticking with stable versions.

PHP Integration Method

After you have finished downloading FCKeditor extract the archive and upload the fckeditor folder to your webroot, /app/webroot/fckeditor. I know most people might say to put this in /app/vendors but I have a reason. Instead of using App::import to import the /fckeditor/fckeditor.php file I took the contents of that file and created a helper with it. I would have imported the distributed class into the helper to make it more portable, but I wanted to rewrite the CreateHtml function to make it a little more CakePHP friendly.

Here is the Fck Helper.

/app/views/helpers/fck.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
<?php
class FckHelper extends AppHelper {
    var $InstanceName;
    var $InstanceId;
    var $BasePath;
    var $Width;
    var $Height;
    var $ToolbarSet;
    var $Config;
    var $Value;
    var $Error;

    function __construct() {
        $this->BasePath     = '/fckeditor/';
        $this->Width        = '100%';
        $this->Height       = '400';
        $this->ToolbarSet   = 'Default';
        $this->Config       = array();
    }

    function IsCompatible() {
        if ( isset( $_SERVER ) ) {
            $sAgent = $_SERVER['HTTP_USER_AGENT'] ;
        } else {
            global $HTTP_SERVER_VARS ;
            if ( isset( $HTTP_SERVER_VARS ) ) {
                $sAgent = $HTTP_SERVER_VARS['HTTP_USER_AGENT'] ;
            } else {
                global $HTTP_USER_AGENT ;
                $sAgent = $HTTP_USER_AGENT ;
            }
        }
        if ( strpos($sAgent, 'MSIE') !== false && strpos($sAgent, 'mac') === false && strpos($sAgent, 'Opera') === false ) {
            $iVersion = (float)substr($sAgent, strpos($sAgent, 'MSIE') + 5, 3) ;
            return ($iVersion >= 5.5) ;
        } else if ( strpos($sAgent, 'Gecko/') !== false ) {
            $iVersion = (int)substr($sAgent, strpos($sAgent, 'Gecko/') + 6, 8) ;
            return ($iVersion >= 20030210) ;
        } else if ( strpos($sAgent, 'Opera/') !== false ) {
            $fVersion = (float)substr($sAgent, strpos($sAgent, 'Opera/') + 6, 4) ;
            return ($fVersion >= 9.5) ;
        } else if ( preg_match( "|AppleWebKit/(\d+)|i", $sAgent, $matches ) ) {
            $iVersion = $matches[1] ;
            return ( $matches[1] >= 522 ) ;
        } else return false ;
    }

    function Create($instance) {
        $instance = explode('/', $instance);
        $this->InstanceName = 'data['.$instance[0].']['.$instance[1].']';
        $this->InstanceId   = $instance[0].Inflector::camelize($instance[1]);
        $HtmlValue = htmlspecialchars( $this->Value ) ;
        $Html = '' ;
        if ( $this->IsCompatible() ) {
            if ( isset( $_GET['fcksource'] ) && $_GET['fcksource'] == "true" )
                $File = 'fckeditor.original.html' ;
            else
                $File = 'fckeditor.html' ;
            $Link = "{$this->BasePath}editor/{$File}?InstanceName={$this->InstanceName}";
            if ( $this->ToolbarSet != '' )
                $Link .= "&amp;Toolbar={$this->ToolbarSet}" ;
            $Html .= "<input type=\"hidden\" id=\"{$this->InstanceId}\" name=\"{$this->InstanceName}\" value=\"{$HtmlValue}\" style=\"display:none\" />";
            $Html .= "<input type=\"hidden\" id=\"{$this->InstanceId}___Config\" value=\"" . $this->GetConfigFieldString() . "\" style=\"display:none\" />";
            $Html .= "<iframe id=\"{$this->InstanceId}___Frame\" src=\"{$Link}\" width=\"{$this->Width}\" height=\"{$this->Height}\" frameborder=\"0\" scrolling=\"no\"></iframe>";
        } else {
            if ( strpos( $this->Width, '%' ) === false )
                $WidthCSS = $this->Width . 'px';
            else
                $WidthCSS = $this->Width;
            if ( strpos( $this->Height, '%' ) === false )
                $HeightCSS = $this->Height . 'px' ;
            else
                $HeightCSS = $this->Height ;
            $Html .= "<textarea name=\"{$this->InstanceName}\" id=\"{$this->InstanceId}\" rows=\"4\" cols=\"40\" style=\"width: {$WidthCSS}; height: {$HeightCSS}\">{$HtmlValue}</textarea>" ;
        }
        if ( !empty( $this->Error ) ) {
            $Html .= '<div class="error-message">'.$this->Error.'</div>';
        }
        return $Html ;
    }

    function GetConfigFieldString() {
        $sParams = '' ;
        $bFirst = true ;
        foreach ( $this->Config as $sKey => $sValue ) {
            if ( $bFirst == false )
                $sParams .= '&amp;' ;
            else
                $bFirst = false ;
            if ( $sValue === true )
                $sParams .= $this->EncodeConfig( $sKey ) . '=true' ;
            else if ( $sValue === false )
                $sParams .= $this->EncodeConfig( $sKey ) . '=false' ;
            else
                $sParams .= $this->EncodeConfig( $sKey ) . '=' . $this->EncodeConfig( $sValue ) ;
        }
        return $sParams ;
    }

    function EncodeConfig( $valueToEncode ) {
        $chars = array(
            '&' => '%26',
            '=' => '%3D',
            '"' => '%22' ) ;
        return strtr( $valueToEncode,  $chars ) ;
    }
}
?>

After you have this helper in place you can enable it by adding it to your $helpers array in whatever controller you are working with. I will be using the content controller from my previous post about a simple cms.

<?php
class ContentController extends AppController {
    var $name = 'Content';
    var $helpers = array('Fck');

After you have that, open your view and pick the field you want to change. Still following the cms example you will want to edit /app/views/content/add.ctp and /app/views/content/edit.ctp like the following.

1
2
3
4
5
6
7
8
// Replace this
echo $form->input('body', array('rows' => '10', 'cols' => '70'));
// With this
if(!empty($this->data['Content']['body']))
    $fck->Value = $this->data['Content']['body'];
if(!empty($this->validationErrors['Content']['body']))
    $fck->Error = $this->validationErrors['Content']['body'];
echo $fck->Create('Content/body');

There are several other configuration options available. You can look at the documentation for more information. Any options available with their php integration method should also be available with this helper.

The only problem with this method so far is there is no non-JavaScript fall back to a plain text area. There is if the browser is not supported. Maybe there is something there that can be expanded on?

For more information on the PHP Integration method please check out the FCKeditor documentation.

JavaScript Integration Method

There are 3 different JavaScript integration methods to choose from. As I mentioned earlier I personally prefer the textarea replacement method with JQuery. So that is the only one I will go over here.

To get started go ahead and download FCKeditor and place it in your webroot just like with the php method above. Then download JQuery and put it in your /app/webroot/js folder. I usually rename the file to jquery.js to make updates easier. Now enable the JavaScript helper in your controller and add the javascript to your view. Using the cms example the add content view would look like this.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<h2>New Page</h2>
<?php
echo $form->create('Content', array('url' => '/content/add'));
echo '<div>';
echo '  <label for="ContentParentId">Parent</label>';
echo '  <select name="data[Content][parent_id]" id="ContentParentId">';
echo '      <option value="0"'.((@$this->data['Content']['parent_id'] == 0) ? ' selected' : '').'>None</option>';
if(!empty($parents)) {
    foreach($parents as $i) {
        echo '<option value="'.$i['Content']['id'].'" style="padding-left: '.($i['Content']['depth'] + 1).'em;"'.((@$this->data['Content']['parent_id'] == $i['Content']['id']) ? ' selected' : '').'>'.$i['Content']['title'].'</option>';
    }
}
echo '  </select>';
echo '</div>';
echo $form->input('title', array('size' => 60));
echo $form->input('slug', array('size' => '20', 'after' => ' The Slug is the word used for the URL of this page.'));
echo $form->input('body', array('rows' => '10', 'cols' => '70'));
echo '<div><input type="submit" value="Save" /> or '.$html->link('Cancel', array('action' => 'index')).'</div>';
echo '<fieldset>';
echo '  <legend>META Data</legend>';
echo $form->input('keywords', array('size' => '60'));
echo $form->input('description', array('rows' => '3', 'cols' => '65'));
echo '</fieldset>';
echo $form->end();

#FCKeditor stuff
$javascript->link('jquery', false);
$javascript->link('/fckeditor/fckeditor.js', false);
?>
<script type="text/javascript">
    $(document).ready(function() {
        var oFCKeditor = new FCKeditor('ContentBody', '100%', '400', 'Default');
        oFCKeditor.ReplaceTextarea();
    });
</script>

For this to work with everything in your webroot the way it is we also need to add a couple of lines to the bottom of our .htaccess file.

/app/webroot/.haccess

AddType application/x-javascript .js
AddType text/css .css

That should be all you need to do. If you would like more information on the JavaScript integration method please check out the FCKeditor documentation.

Enable The File/Image Upload

First you need to create 4 folders:

  • /app/webroot/files/file
  • /app/webroot/files/flash
  • /app/webroot/files/image
  • /app/webroot/files/media

Each folder need to be writable by the web server.

Now edit /app/webroot/fckeditor/editor/filemanager/connectors/php/config.php and make the following changes for each line (Line numbers may change according to your version).

30
$Config['Enabled'] = false ;
34
$Config['UserFilesPath'] = '/files/' ;

Be sure and set this next one to the full path of your files directory.

40
$Config['UserFilesAbsolutePath'] = '/var/www/mywebsite.com/htdocs/app/webroot/files/' ;

It should now be working. There is also a lot more information on the CakePHP Bakery that could be useful to you.

  1. Sebastian
    February 23rd, 2009 at 09:51
    Reply | Quote | #1

    I did exactly the things you said (both methods), but still it doesn’t work.

    for the javascript method there is the error: “FCKEditor is not defined”.

    Jquery installed, fckeditor in webroot. everything just the way you said.

    hoping for help…i did spend the whole day with this

  2. February 23rd, 2009 at 11:41
    Reply | Quote | #2

    It looks like I left something out for the JavaScript method. You need to include the fckeditor.js file.. here is an example of how you can do it with jquery after your form:

    <?php
    $javascript->link('/fckeditor/fckeditor.js', false);
    ?>
    <script type="text/javascript">
        $(document).ready(function() {
            var oFCKeditor = new FCKeditor('FieldId', '100%', '400', 'Default');
            oFCKeditor.ReplaceTextarea();
        });
    </script>

    The only thing here you will want to change is possibly the path to your fckeditor.js file and the Id of the textarea field you are replacing in the FCKeditor constructor.

    Hope that helps :-/

  3. Sebastian
    February 24th, 2009 at 11:15
    Reply | Quote | #3

    Hello Joseph.

    error is gone, but still it doesn’t work.
    cakephp shows the form and everything, but doesn’t show “body textarea”, where I expect the fckeditor to be. first method didn’t worked as well. what do i wrong?
    it’s really frustrating. i am testing it on my local host (mamp/mac os x)…
    further looking for help…

  4. Sebastian
    February 24th, 2009 at 13:16
    Reply | Quote | #4

    hello again.
    i followed the steps on http://bakery.cakephp.org/articles/view/using-fckeditor-with-cakephp and comment no. 11 helped.

    BUT…still FCKeditor doesn’t work on my local machine (mamp/mac os x). after uploading it to my server it works fine… any clue?

  5. Leo
    February 24th, 2009 at 23:28
    Reply | Quote | #5

    Followed your tutorial line by line. Did your CMS tutorial and replaced those lines… does not work. Instead I get a “cannot find fckeditor.html” message. I copied the whole fckeditor folder into /webroot/ straight from the zip without removing or touching any file. I created the helper. Added the reference to the helper. Line by line. Did it 3 times.. same result. =(

    Will try javascript method.

  6. Leo
    February 24th, 2009 at 23:55
    Reply | Quote | #6

    after doing some tinkering with the code I found that the helper only works if youre working on a project that’s on the ROOT folder of the directory meaning if im working in localhost/myproject I have to replace

    $this->BasePath = ‘/fckeditor/’;
    with $this->BasePath = ‘myproject/fckeditor/’;

    Thanks for the awesome tutorial! hope this helps someone.

  7. Julian
    March 18th, 2009 at 06:08
    Reply | Quote | #7

    Thanks Leo. Your comment really helped me. Firstly, when I try your suggestion I still found error. Then I changed the code with this

    $this->BasePath = ‘../myproject/fckeditor/’;

    and it worked! :)

    FYI, I was using XAMPP and Windows XP. Thanks also for this tutorial :)

  8. May 29th, 2009 at 03:40
    Reply | Quote | #8

    Thank you so much for this tutorial – I wasted a whole evening trying 3 other methods – none of which worked.

    You’re a star!! :)

  9. May 29th, 2009 at 03:48
    Reply | Quote | #9

    Thanks :)

  10. jointklat
    July 6th, 2009 at 12:13

    thx a lot, for the script but i have an error when i try PHP Integration Method, the add.ctp work very good but edit.ctp don’t work!

    link for see error:
    http://www.cakephp-it.org/topic278-problema-con-fckeditor.html

  11. July 31st, 2009 at 17:32

    Hi Joseph, thank you!!
    But i have the same problem with edit.ctp

    Thanks again

  12. July 31st, 2009 at 17:43

    Hi again Joseph, but i fix it, i forgto to include the id field in edit ctp

  13. Eduardo Sorribas
    August 10th, 2009 at 21:39

    Thanks. Saved my life.

  14. Tushar Mahajan
    August 10th, 2009 at 22:28

    Thanks a lot Joseph. Am using php integration method which works fine. But if i want to place fckeditor in vendor insted of js, so how can i do that?

  15. Eduardo Sorribas
    August 11th, 2009 at 12:25

    Hey, I am trying to cahnge the language to sapnish and it doesn’t seem to work. Any help?

  16. August 11th, 2009 at 14:57

    I’m sorry but I don’t know Spanish. You could try the FCKeditor website.

  17. August 11th, 2009 at 15:02

    I have not had luck with using FCKeditor from the vendor folder. I have tried because it seems the obvious place to put it but gave up and took the easy way out.

  18. Vagner
    November 5th, 2009 at 08:38

    Thanks. Saved my life.

  19. Jibu
    November 12th, 2009 at 04:10

    For your info.
    Now the FCKEditor is changed to CKEditor with the relase of CKEditor 3.0.
    Integrating latest version of FCKEditor(CKEditor) with cake php is very easy. You
    can see the simple steps here.
    Integrating CKEditor with CakePHP

  20. February 16th, 2010 at 00:38

    Hi, its great…. after changing in $this->BasePath =Url project/fckeditor/ its working cool thanks for giving this article….

  21. February 16th, 2010 at 01:25

    Hello its working but if we change the name of $fck->create(‘ModelName/ActionName’) then not work. we should always define name like $fck->create(‘ModelName/content’). Is this problem in your helper ???

  22. March 3rd, 2010 at 21:52

    I have inserted Ckeditor 3.x in my page and i submit my form data (along with the text area)to the controller. I am trying to save data to Mysql database but not able to save. I wonder if this is a correct way of doing it.

    Form name = Admin
    Field name = content
    Controller name = Admins
    Modelname = Admin

    Mycontroller code:
    $grn3 = $this->data['Admin']['content'] ;
    $this->Session->setFlash($grn3);
    $this->Admin->set($this->data ); //setting data to model
    $this->Admin->saveField(‘content’, $grn3); //saving single field

    Setflash method flashes the data content, but save is not working. I am not sure if this is the way of saving text editor data to database. Please show me how to save editor data to database.

    Thankx
    John M.

  23. August 6th, 2010 at 06:33

    Now FCKEditor is replaced by CKEditor. So you can see the installation of CKEditor with Cake php in the following URL.

    http://www.robinthomas.in/php/ckeditor-cakephp/

  24. 1 trackbacks
TOP