TinyMCE helper

This article is also available in the following languages:
By daibach
This is a basic helper to make it really easy to use TinyMCE inside CakePHP.

Notes

To specify any TinyMCE options, provide the extra $tinyoptions array with the information. It'll be converted to JavaScript and used when creating the editor.

Tiny MCE

Go and grab TinyMCE from its website http://tinymce.moxiecode.com/download.php and copy the /tinymce/jscripts/tiny_mce folder to the /app/webroot/js

Controller


var $helpers = Array('Form', 'Tinymce');

Helper code

app/views/helpers/tinymce.php

<?php
class TinyMceHelper extends AppHelper {
    
// Take advantage of other helpers
    
var $helpers = array('Javascript''Form');
    
// Check if the tiny_mce.js file has been added or not
    
var $_script false;
    
    
/**
     * Adds the tiny_mce.js file and constructs the options
     *
     * @param string $fieldName Name of a field, like this "Modelname.fieldname", "Modelname/fieldname" is deprecated
     * @param array $tinyoptions Array of TinyMCE attributes for this textarea
     * @return string JavaScript code to initialise the TinyMCE area
     */
    
function _build($fieldName$tinyoptions = array()) {
        if (!
$this->_script) {
            
// We don't want to add this every time, it's only needed once
            
$this->_script true;
            
$this->Javascript->link('/js/tiny_mce/tiny_mce.js'false);
        }
        
// Ties the options to the field
        
$tinyoptions['mode'] = 'exact';
        
$tinyoptions['elements'] = $this->__name($fieldName);
        return 
$this->Javascript->codeBlock('tinyMCE.init(' $this->Javascript->object($tinyoptions) . ');');
    }
    
    
/**
     * Creates a TinyMCE textarea.
     *
     * @param string $fieldName Name of a field, like this "Modelname.fieldname", "Modelname/fieldname" is deprecated
     * @param array $options Array of HTML attributes.
     * @param array $tinyoptions Array of TinyMCE attributes for this textarea
     * @return string An HTML textarea element with TinyMCE
     */
    
function textarea($fieldName$options = array(), $tinyoptions = array()) {
        return 
$this->Form->textarea($fieldName$options) . $this->_build($fieldName$tinyoptions);
    }

    
/**
     * Creates a TinyMCE textarea.
     *
     * @param string $fieldName Name of a field, like this "Modelname.fieldname", "Modelname/fieldname" is deprecated
     * @param array $options Array of HTML attributes.
     * @param array $tinyoptions Array of TinyMCE attributes for this textarea
     * @return string An HTML textarea element with TinyMCE
     */
    
function input($fieldName$options = array(), $tinyoptions = array()) {
        
$options['type'] = 'textarea';
        return 
$this->Form->input($fieldName$options) . $this->_build($fieldName$tinyoptions);
    }
}
?>

View example


<div class="form-container">
  <?php echo $form->create('Page'); ?>
    <fieldset>
      <legend>Page</legend>
      <?php
        
echo $form->input('title');
        echo 
$tinymce->input('content');
      
?>
    </fieldset>
  <?php echo $form->end('Save'); ?>
</div>
Here's an example supplying some extra tinyMCE configuration options

<div class="form-container">
  <?php echo $form->create('Page'); ?>
    <fieldset>
      <legend>Page</legend>
      <?php
        
echo $form->input('title');
        echo 
$tinymce->input('content'null, array(
          
'theme'                             => 'advanced',
          
'theme_advanced_toolbar_location'   => 'top',
          
'theme_advanced_toolbar_align'      => 'left',
          
'theme_advanced_statusbar_location' => 'bottom',
        ));
      
?>
    </fieldset>
  <?php echo $form->end('Save'); ?>
</div>

Suggestions


Everyone should know that letting users submit HTML can be a bit risky when it comes to displaying it, unless you trust them of couse (like an admin user). If you want more general users taking advantage of something like this, I'd suggest looking into something like http://htmlpurifier.org/. This parses the HTML and can remove anything you don't want submitted.

Comments

  • Posted 11/02/10 11:55:25 AM

    Html->script('/js/tiny_mce/tiny_mce.js', array('inline' => false, 'once' => true));
    // Ties the options to the field
    $tinyoptions['mode'] = 'exact';
    $tinyoptions['elements'] = $this->_name($fieldName);
    return $this->Html->scriptBlock('tinyMCE.init(' . $this->Js->object($tinyoptions) . ');', array('inline' => false));
    }

    /**
    * Creates a TinyMCE textarea.
    *
    * @param string $fieldName Name of a field, like this "Modelname.fieldname", "Modelname/fieldname" is deprecated
    * @param array $options Array of HTML attributes.
    * @param array $tinyoptions Array of TinyMCE attributes for this textarea
    * @return string An HTML textarea element with TinyMCE
    */
    function textarea($fieldName, $options = array(), $tinyoptions = array()) {
    return $this->Form->textarea($fieldName, $options) . $this->_build($fieldName, $tinyoptions);
    }

    /**
    * Creates a TinyMCE textarea.
    *
    * @param string $fieldName Name of a field, like this "Modelname.fieldname", "Modelname/fieldname" is deprecated
    * @param array $options Array of HTML attributes.
    * @param array $tinyoptions Array of TinyMCE attributes for this textarea
    * @return string An HTML textarea element with TinyMCE
    */
    function input($fieldName, $options = array(), $tinyoptions = array()) {
    $options['type'] = 'textarea';
    return $this->Form->input($fieldName, $options) . $this->_build($fieldName, $tinyoptions);
    }
    }
    ?>
    • Posted 11/02/10 11:58:38 AM
      Where is the f**king help on how to
      - delete/edit you own post
      - properly include codeblocks

      ???

      And why is "oldest" and "most recent" in the wrong place here?
  • Posted 08/14/10 05:24:37 PM
    Warning (512): Method TinyMceHelper::__name does not exist [CORE/cake/libs/view/helper.php, line 154]
    Using CakePHP 1.3
    I think I've followed the tutorial faithfully, and I'm pretty sure I'm not supposed to edit anything in the libs directory. But that's where it seems to be looking for the TinyMceHelper method. Not sure why. Any help?

    Thanks,
    Sean
    • Posted 07/13/11 10:49:41 AM
      [quote] Warning (512): Method TinyMceHelper::__name does not exist [CORE/cake/libs/view/helper.php, line 154]
      Using CakePHP 1.3
      I think I've followed the tutorial faithfully, and I'm pretty sure I'm not supposed to edit anything in the libs directory. But that's where it seems to be looking for the TinyMceHelper method. Not sure why. Any help?

      Thanks,
      Sean
      [end quote] open your TinymceHelper class file in your editor
      press Ctrl + F (Find & replace)
      find '__name' and replace it with '_name'
    • Posted 09/30/10 02:48:29 AM
      Yes, there is a mistake in tiny_mce.php on line 23.
      The method wich have to be called, have to be named: _name() and not __name().

      Sorry for my bad english...

      I hope this tipp helps you.

      Best regards
  • Posted 03/30/10 06:15:12 AM
    I can make it to work only under debug mode, but can't see any UI when set debug=0, why?
    • Posted 06/15/10 03:00:50 PM
      I can make it to work only under debug mode, but can't see any UI when set debug=0, why?
      I too had the same problem, TinyMCE would work fine with debug set to 1 or higher, UI would not display with cakephp's debug set to 0. No errors in Firebug or Chrome's tools.

      After a lot of trial and error, found that I had imagemanager and filemanager in Tiny's plugin list, which didn't exist. After removing these, it worked fine with Debug set to 0. Why CakePHP's debug level affects this, I have no clue.
      • Posted 07/18/10 08:37:34 AM
        Thanks Bryan saved me a lot of time with the tinymce debug issue ...


        I can make it to work only under debug mode, but can't see any UI when set debug=0, why?
        I too had the same problem, TinyMCE would work fine with debug set to 1 or higher, UI would not display with cakephp's debug set to 0. No errors in Firebug or Chrome's tools.

        After a lot of trial and error, found that I had imagemanager and filemanager in Tiny's plugin list, which didn't exist. After removing these, it worked fine with Debug set to 0. Why CakePHP's debug level affects this, I have no clue.
  • Posted 10/11/09 01:56:30 PM
    Thanks for this good helper !

    I have update this to allow multi TinyMCE and add preset if we don't want to write every times the tinyoptions:

    Helper Class:

    <?php 
    class TinyMceHelper extends AppHelper
    {
        
        
    // Take advantage of other helpers
        
    var $helpers = array('Javascript''Form');
        
    // Check if the tiny_mce.js file has been added or not
        
    var $_script false;
        
        
    /**
         * Adds the tiny_mce.js file and constructs the options
         *
         * @param string $fieldName Name of a field, like this "Modelname.fieldname", "Modelname/fieldname" is deprecated
         * @param array $tinyoptions Array of TinyMCE attributes for this textarea
         * @return string JavaScript code to initialise the TinyMCE area
         */
        
    function _build($fieldName$tinyoptions = array())
        {
            if(!
    $this->_script)
            {
                
    // We don't want to add this every time, it's only needed once
                
    $this->_script true;
                
    $this->Javascript->link('tiny_mce/tiny_mce.js'false);
            }
            
    // Ties the options to the field
            
    $tinyoptions['mode'] = 'exact';
            
    $tinyoptions['elements'] = $this->domId($fieldName); 
            return 
    $this->Javascript->codeBlock('tinyMCE.init(' $this->Javascript->object($tinyoptions) . ');');
        }
        
        
    /**
         * Creates a TinyMCE textarea.
         *
         * @param string $fieldName Name of a field, like this "Modelname.fieldname", "Modelname/fieldname" is deprecated
         * @param array $options Array of HTML attributes.
         * @param array $tinyoptions Array of TinyMCE attributes for this textarea
         * @return string An HTML textarea element with TinyMCE
         */
        
    function textarea($fieldName$options = array(), $tinyoptions = array(), $preset null)
        {
            
    // If a preset is defined
            
    if(!empty($preset))
            {
                
    $preset_options $this->preset($preset);
                
                
    // If $preset_options && $tinyoptions are an array
                
    if(is_array($preset_options) && is_array($tinyoptions))
                {
                    
    $tinyoptions array_merge($preset_options$tinyoptions);
                }
                else
                {
                    
    $tinyoptions $preset_options;
                }
            }
            
            return 
    $this->Form->textarea($fieldName$options) . $this->_build($fieldName$tinyoptions);
        }

        
    /**
         * Creates a TinyMCE textarea.
         *
         * @param string $fieldName Name of a field, like this "Modelname.fieldname", "Modelname/fieldname" is deprecated
         * @param array $options Array of HTML attributes.
         * @param array $tinyoptions Array of TinyMCE attributes for this textarea
         * @return string An HTML textarea element with TinyMCE
         */
        
    function input($fieldName$options = array(), $tinyoptions = array(), $preset null)
        {
            
    // If a preset is defined
            
    if(!empty($preset))
            {
                
    $preset_options $this->preset($preset);
                
                
    // If $preset_options && $tinyoptions are an array
                
    if(is_array($preset_options) && is_array($tinyoptions))
                {
                    
    $tinyoptions array_merge($preset_options$tinyoptions);
                }
                else
                {
                    
    $tinyoptions $preset_options;
                }
            }
            
            
    $options['type'] = 'textarea';
            return 
    $this->Form->input($fieldName$options) . $this->_build($fieldName$tinyoptions);
        }
        
        
    /**
         * Creates a preset for TinyOptions
         * 
         * @param string $name
         * @return array
         */
        
    private function preset($name)
        {
            
    // Full Feature
            
    if($name == 'full')
            {
                return array(
                    
    'theme' => 'advanced',
                    
    'plugins' => 'safari,pagebreak,style,layer,table,save,advhr,advimage,advlink,emotions,iespell,inlinepopups,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras,template',
                    
    'theme_advanced_buttons1' => 'save,newdocument,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,styleselect,formatselect,fontselect,fontsizeselect',
                    
    'theme_advanced_buttons2' => 'cut,copy,paste,pastetext,pasteword,|,search,replace,|,bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code,|,insertdate,inserttime,preview,|,forecolor,backcolor',
                    
    'theme_advanced_buttons3' => 'tablecontrols,|,hr,removeformat,visualaid,|,sub,sup,|,charmap,emotions,iespell,media,advhr,|,print,|,ltr,rtl,|,fullscreen',
                    
    'theme_advanced_buttons4' => 'insertlayer,moveforward,movebackward,absolute,|,styleprops,|,cite,abbr,acronym,del,ins,attribs,|,visualchars,nonbreaking,template,pagebreak',
                    
    'theme_advanced_toolbar_location' => 'top',
                    
    'theme_advanced_toolbar_align' => 'left',
                    
    'theme_advanced_statusbar_location' => 'bottom',
                    
    'theme_advanced_resizing' => true,
                    
    'theme_advanced_resize_horizontal' => false,
                    
    'convert_fonts_to_spans' => true
                
    );
            }
      
            
    // Basic
            
    if($name == 'basic')
            {
                return array(
                    
    'theme' => 'advanced',
                    
    'theme_advanced_toolbar_location' => 'top',
                    
    'theme_advanced_toolbar_align' => 'left',
                    
    'theme_advanced_statusbar_location' => 'bottom',
                    
    'theme_advanced_resizing' => true,
                    
    'theme_advanced_resize_horizontal' => false,
                    
    'convert_fonts_to_spans' => true
                
    );
            }
            
            
    // BBCode
            
    if($name == 'bbcode')
            {
                return array(
                    
    'theme' => 'advanced',
                    
    'plugins' => 'bbcode',
                    
    'theme_advanced_buttons1' => 'bold,italic,underline,undo,redo,link,unlink,image,forecolor,styleselect,removeformat,cleanup,code',
                    
    'theme_advanced_buttons2' => '',
                    
    'theme_advanced_buttons3' => '',
                    
    'theme_advanced_toolbar_location' => 'top',
                    
    'theme_advanced_toolbar_align' => 'left',
                    
    'theme_advanced_styles' => 'Code=codeStyle;Quote=quoteStyle',
                    
    'theme_advanced_statusbar_location' => 'bottom',
                    
    'theme_advanced_resizing' => true,
                    
    'theme_advanced_resize_horizontal' => false,
                    
    'entity_encoding' => 'raw',
                    
    'add_unload_trigger' => false,
                    
    'remove_linebreaks' => false,
                    
    'inline_styles' => false
                
    );
            }
            
            return 
    null;
        }
    }
    ?>

    Sorry for my english =D
  • Posted 07/25/09 08:47:27 AM
    The problem was that I didnt have


    <?php echo $scripts_for_layout?>


    in my view...just in case anyone else new to cake is wondering.
    Taff
  • Posted 06/18/09 03:54:01 AM
    I'm having some problem when the debug is set to 0 (all the javascript and css files are packed so I guess they couldn't link up with each other). I have followed the instruction to put "/tinymce/jscripts/tiny_mce" folder to the "/app/webroot/js"
  • Posted 02/06/09 10:51:27 AM
    Great code, David!

    Really cool, though I found one problem: One of my entries in the tinyMCE.init is not a variable, but a function:

    setup : function(ed) {
        ed.onDblClick.add(function(ed, e) {
            var attribute = ed.dom.getAttrib(e.target,'class');
            // make sure it is the MathML span tag which has been doubleclicked
            if(e.target.nodeName=="IMG" && attribute=="InteractiveGraph"){
                var id = ed.dom.getAttrib(e.target,'id');
                ed.execCommand("mceinteractivegraphs",false,id);
            }
        });
    },
    When using $this->Javascript->object, it assumes that all values in the array are to be quoted, but this function is not.

    Hence, I came up with this extension:

    Helper Class:

    <?php 
    function _build($fieldName$tinyoptions = array()) {
        if (!
    $this->_script) {
            
    // We don't want to add this every time, it's only needed once
            
    $this->_script true;
            
    $this->Javascript->link('/js/tiny_mce/tiny_mce.js'false);
        }
        
    // Ties the options to the field
        
    $tinyoptions['mode'] = 'exact';
        
    $tinyoptions['elements'] = $this->domId($fieldName);

        
    $manual_json $tinyoptions['manual_json'];
        unset(
    $tinyoptions['manual_json']);
        
    $json $this->Javascript->object($tinyoptions);
        
    $json substr($json,0,strlen($json)-1).',';
        if (!empty(
    $manual_json)) {
            foreach (
    $manual_json as $k => $v) {
                
    $json .= '"'.$k.'":'.$v;
            }
        }
        
    $json .= "}";
        return 
    $this->Javascript->codeBlock('tinyMCE.init(' $json ');',array('inline'=>false));
    }
    ?>

    I furthermore changed $this_>__name() to $this->domId(), because the 'elements' should be passed the id of the textarea, not the name.

    My textarea element looks like this:

    View Template:


    <?php print $tinymce->textarea('Lesson.source',array(),array(
        
    "theme" => "advanced",
        
    "cleanup" => "true",
        
    "manual_json" => array(
            
    "setup" => str_replace("\n","",str_replace("\t","","function(ed) {
                ed.onDblClick.add(function(ed, e) {
                    var attribute = ed.dom.getAttrib(e.target,'class');
                    if(e.target.nodeName=='IMG' && attribute=='InteractiveGraph') {
                        var id = ed.dom.getAttrib(e.target,'id');
                        ed.execCommand('mceinteractivegraphs',false,id);
                    }
                });
            }"
    ))
        ),
    ));
    ?>

    I hope that is is of some help to others using advanced tinymce techniques!

    Best regards,
    Jesper :-)
  • Posted 01/03/09 03:16:27 PM
    In order to use multiple instances of TinyMce you can't use the script in that form anymore.

    First you have to choose between a way:

    If it's easier to convert all textareas to TinyMce-Editors (and optionally exclude some of them by CSS-class):



    <?php
    function _build($fieldName$tinyoptions = array()) {
            [...]
            
    // Converts all textareas to TinyMCE-Editors, excluding textareas having the CSS-Class 'mceNoEditor'
            
    $tinyoptions['mode'] = 'textareas';
            
    $tinyoptions['editor_deselector'] = 'mceNoEditor';
            [...]
    }
    ?>

    If you want have only editors on textareas having a certain CSS-class.


    <?php
    function _build($fieldName$tinyoptions = array()) {
            [...]
            
    // converts only these textareas to TinyMCE-Editors having the CSS-Class 'mceEditor'
            
    $tinyoptions['mode'] = 'specific_textareas';
            
    $tinyoptions['editor_selector'] = 'mceEditor';
            [...]
    }
    ?>

    For the second option you can modify to code of the input/textarea function to always insert the class. So if you use $tinymce->input the area will automatically turned into tinymce fields but fields created by $forms->textarea won't.

    To achieve that you have to insert:

    <?php
    function textarea($fieldName$options = array(), $tinyoptions = array()) {
            if(isset(
    $options['class'])){
                
    $options['class'] = $options['class'].' mceEditor';
            }else{
                
    $options['class'] = 'mceEditor';
            }
            return 
    $this->Form->textarea($fieldName$options) . $this->__build($fieldName$tinyoptions);
    }
    ?>

    (Do the same with function input.)

    Hope that helps, Stevie :)
    • Posted 06/08/09 10:30:21 PM
      Hope that helps, Stevie :)
      Stevie any chance you can give a little more explanation? I tried what you did, and when I save my data is getting lost somewhere... it's not showing up in $this->data. Do you have any idea what the issue may be?
  • Posted 12/04/08 04:54:20 AM
    Like the above comment, I am also wondering how I can get multiple instances working on a page, my current code is as follows:

    View Template:


            echo $form->label('description', 'Description:');
            echo $tinymce->input('description', array('label' => false, 'rows' => 20, 'cols' => 50));
            
            echo $form->label('tech_description', 'Technical Description:');
            echo $tinymce->input('tech_description', array('label' => false, 'rows' => 20, 'cols' => 50));

    However this does not create two instances, the first one works fine, but the second one just creates a normal textarea box. Any suggestions?
  • Posted 08/26/08 09:18:25 AM
    great helper, simple and effective
  • Posted 08/18/08 10:10:10 AM
    How can I get multiple instances of it in the same page?
    I need for multiple language editing.
    Thanks
  • Posted 07/11/08 08:49:14 AM
    Hi Greg, I've updated the article to include an example of setting TinyMCE options.

    You basically pass the helper a third parameter that is a php array similar to the JavaScript object that TinyMCE usually gets.

    Note that you shouldn't supply a "mode" since the helper will create that bit for you and tie it to the textarea automatically.

    Hope that explains things,
    Dave
  • Posted 07/10/08 11:18:01 AM
    Could you please give an example to set the $tinyoptions array .

    Actually I need a configuration like the following one:


    tinyMCE.init({
    mode : "textareas",
    theme : "advanced",
    plugins : "inlinepopups,style,layer,table,save,advhr,advimage,advlink,emotions,iespell,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras",
    theme_advanced_buttons1 : "save,newdocument,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,styleselect,formatselect,fontselect,fontsizeselect",
    theme_advanced_buttons2 : "cut,copy,paste,pastetext,pasteword,|,search,replace,|,bullist,numlist,|,outdent,indent,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code,|,insertdate,inserttime,preview,|,forecolor,backcolor",
    theme_advanced_buttons3 : "tablecontrols,|,hr,removeformat,visualaid,|,sub,sup,|,charmap,emotions,iespell,media,advhr,|,print,|,ltr,rtl,|,fullscreen",
    theme_advanced_buttons4 : "insertlayer,moveforward,movebackward,absolute,|,styleprops,|,cite,abbr,acronym,del,ins,|,visualchars,nonbreaking",
    theme_advanced_toolbar_location : "top",
    theme_advanced_toolbar_align : "left",
    theme_advanced_statusbar_location : "bottom",
    extended_valid_elements : "a[name|href|target|title|onclick],img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name],hr[class|width|size|noshade],font[face|size|color|style],span[class|align|style]"
    });

    Thank you very much for you help.
    • Posted 08/01/08 02:10:59 AM
      The following code is working....

      View Template:


      <div>
       <?php echo $form->create('Page'); ?> 
        <?php        
              
      echo $tinymce->input('content'null, array( 
               
      'theme' => 'advanced',                                
              
      "plugins" => "safari,pagebreak,style,layer,table,save,advhr,advimage,advlink,emotions,iespell,inlinepopups,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras,template",
                
      "theme_advanced_buttons1" => "newdocument,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,formatselect,fontselect,fontsizeselect",
              
      "theme_advanced_buttons2"=> "bullist,numlist,|,outdent,indent,|,undo,redo,|,link,unlink,image,code,|,insertdate,inserttime,preview,|,forecolor,backcolor,advhr,|,print,|fullscreen",
              
      "theme_advanced_buttons3" => "",
              
      //theme_advanced_buttons4 : "insertlayer,moveforward,movebackward,absolute,|,styleprops,|,cite,abbr,acronym,del,ins,attribs,|,visualchars,nonbreaking,template,pagebreak",
               
      "theme_advanced_toolbar_location" => "top",
               
      "theme_advanced_toolbar_align" => "left",
               
      "theme_advanced_statusbar_location" => "bottom",
               
      "theme_advanced_resizing" => true,
                
              )); 
            
      ?> 
       <?php echo $form->end('Save'); ?> 
      </div>

Comments are closed for articles over a year old