cakephp ckeditor elfinder

How to use Elfinder with CkEditor in CakePHP This article refers to CakePHP 4, but actually the same technique can be used for CakePHP 2.x This works both and without with Vue (and does not require...

Scopri di più »

How to use Elfinder with CkEditor in CakePHP
This article refers to CakePHP 4, but actually the same technique can be used for CakePHP 2.x
This works both and without with Vue (and does not require...

H

ow to use Elfinder with CkEditor in CakePHP

This article refers to CakePHP 4, but actually the same technique can be used for CakePHP 2.x

This works both and without with Vue (and does not require jquery in your template - consider that the windows that contains elfinder will use jquery).

Our setup

  • CakePHP 4 (but is almost the same in CakePHP 2.x)

  • CKEditor 4 (please read below: why-not-ckeditor-5)

  • Elfinder 2

  • Vue 2.x and Bootstrap Vue in the admin template (no jquery)

Why Not CKEditor 5

Starting a new project in 2021 I assumed to use the newest version of CKEditor, ie v.5

The editor has a clean modern look, does not require jquery and seems to integrate quite well with Vue and bootstrap.

So I started my project with this. The installation was ok but I found a couple of problems:

  • Several plugins can only be installed using webpack or similar. CKEditor and some of the official plugins support browser installation, but most of the contributed stuff you find around do not.

    If you have a browser based setup (ie: you include the script in your HTML, without building them, things get really complex, because CKEditor 5 is meant for such a webpack and a lot of modules use 'require xxx'). You get mad to make things work without it.

  • Basic things become complex - ckeditor is slim by design, meaning that most of the normal buttons that you would expect are plugins (so install, dependencies, things that do not work, etc.)

  • Images are a nightmare - if you were used to the normal image management button in CKEditor4, just forget about it. The new toolbar is much simpler, but much less powerfull. You can't move images around, you can position and resize... too basic for my customers who started to complain.

  • No source code - sometimes we need to edit HTML directly, maybe to insert a specific class or to add some span or div which are not "visual"... Well forget it. By design CKEditor 5 does not support source editing. There is an interesting thread about this on github, with more than 100 comments (most of which complaining ;-) - but still: no source code allowed.

So after one months of work and complains, I decided to switch back to the good old CKEditor 4.

CKEditor 4 + Vue

My cakephp admin backend is vue based, so I wanted something "compatible with vue".

Fortunately ckeditor4 has a vue wrapper, and it's quite easy to install.

The Vue integration allows you to implement CKEditor 4 as a Vue component, using the <ckeditor /> tag.

In CakePHP i put all node_modules in the webroot/js folder.

cd webroot/js
npm install -S ckeditor4-vue

This way in your layout.default (or admin.default) you can simply include a line like this:

<script src="/js/node_modules/ckeditor4-vue/dist/ckeditor.js"></script>

and then used like this

Vue.use( CKEditor );

CKEditor 4 + Vue + Plugins

The problem you will encounter now is that this way you can't add non standard plugins to ckeditor.

If you need them (in my case: image upload, and others), you will rather build CKEditor Online using the - CKEditor 4 online builder | CKEditor.com

This will generate a zip file that you can extract in:

/webroot/js/ckeditor4

In order to use it, I create a simple script which I place in /webroot/js and I include in the pages where I need ckeditor, for example, in my Articles/edit.php page, I have at the bottom of my page

  <?= $this->Html->script('add-ckeditor.js',['block'=>true]) ?>

And in /webroot/js

// I attach a CKEditor to all element with class="editor"
if (document.querySelector('.editor')) {
    var editors = document.querySelectorAll(".editor");
    editors.forEach(function(edt) {
        CKEDITOR.replace(edt, {
            customConfig: '/js/ckeditor.config.js'
        })
    });
}

Notice that I load the configuration from one external file, so to be able to load different configurations for different sites or user profiles (eg: admin can edit source, normal users can't)

This is my ckeditor.config.js

CKEDITOR.editorConfig = function(config) {
    config.height = 550;
    config.extraPlugins = 'widget,lineutils,uploadimage';
    config.contentsCss = [
        '/js/node_modules/bootstrap/dist/css/bootstrap.min.css',
    ];
    config.allowedContent = true;
    config.toolbarGroups = [
        { name: 'document', groups: ['mode', 'document', 'doctools'] },
        { name: 'clipboard', groups: ['clipboard', 'undo'] },
        { name: 'editing', groups: ['find', 'selection', 'spellchecker', 'editing'] },
        { name: 'forms', groups: ['forms'] },
        { name: 'styles', groups: ['styles'] },
        { name: 'colors', groups: ['colors'] },
        { name: 'tools', groups: ['tools'] },
        { name: 'others', groups: ['others'] },
        { name: 'about', groups: ['about'] },
        '/',
        { name: 'basicstyles', groups: ['basicstyles', 'cleanup'] },
        { name: 'paragraph', groups: ['list', 'indent', 'blocks', 'align', 'bidi', 'paragraph'] },
        { name: 'links', groups: ['links'] },
        { name: 'insert', groups: ['insert'] },
    ];

    config.removeButtons = 'Save,NewPage,Preview,Print,Find,Replace,SelectAll,Scayt,BidiLtr,BidiRtl,Language,Flash,Smiley,Font,TextColor,BGColor,Maximize,About';
};

With this setup your ckeditor will play well with any textarea which has a class="editor" attribute.

CKeditor4 + Elfinder + CakePHP

elFinder - Web File Manager is in my opinion the best js file manager around. Even if it's a little old (based on JQuery UI), I've not found a similar tool in more modern stuff, so I switched back to the good old elFinder.

Step 1 - Install Elfinder

The best way to install elfinder is via composer

composer require studio-42/elfinder

This will install elfinder in your /vendor folder.

I reccomend to create a symbolic link to the library from your /webroot/js/ in order to be able to access the library from the browser (if you can't create symbolic links, simply copy eflinder everytime it's updated).

 ln -s vendor/studio-42/elfinder webroot/js/elFinder

Step 2 - Create a connector in CakePHP

Now you should go to your Controller (in my case ArticlesController.php) and create a methods which will take care of uploading the file that the user has selected.

use Cake\Core\Configure;
use elFinder;
use elFinderConnector;

public function ckeconnector()
  {
    $opts = [
      'debug' => false,
      'roots' => [
        // Items volume
        [
          'driver'        => 'LocalFileSystem',           // driver for accessing file system (REQUIRED)
          'path'          =>  WWW_ROOT . Configure::read('sitedir') . '/' . 'attachments', // path to files (REQUIRED)
          'URL'           => '/' . Configure::read('sitedir') . '/' . 'attachments', // URL to files (REQUIRED)
          'winHashFix'    => DIRECTORY_SEPARATOR !== '/', // to make hash same to Linux one on windows too
          'uploadDeny'    => array('all'),                // All Mimetypes not allowed to upload
          'uploadAllow'   => [
            'image/x-ms-bmp', 'image/gif', 'image/jpeg', 'image/png', 'image/x-icon',
            'text/plain', 'application/pdf',
            'application/msword',
            'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
            'application/vnd.ms-excel',
            'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
            'application/vnd.ms-powerpoint',
            'application/vnd.openxmlformats-officedocument.presentationml.presentation',
            'application/vnd.oasis.opendocument.text',
            'application/vnd.oasis.opendocument.spreadsheet',
            'application/vnd.oasis.opendocument.presentation',
          ], // Mimetype `image` and `text/plain` allowed to upload
          'uploadOrder'   => array('deny', 'allow'),      // allowed Mimetype `image` and `text/plain` only
          'accessControl' => 'access'                     // disable and hide dot starting files (OPTIONAL)
        ],
      ]
    ];

    // run elFinder
    $this->autoRender = false;
    $connector = new elFinderConnector(new elFinder($opts));
    $connector->run();
  }

In your configuration file (app_local.php) you should configure the folder where you want to write files (in my case this configuration variable is called sitedir)

Of course you should adapt the configurations to your case (which files you allow, where to store them, etc.).

Step 3 - Make CKEditor realize that elFinder exists

In order to make the two talk to one another, you need to edit your layout

//in templates/layout/default.php add (before ckeditor)
//in every template/Article/edit.php (wherever you need it) 
//- adding ['block'=>true]  
<?= $this->Html->script('ckeditor/ckeditor') ?>
<?= $this->Html->script('add-ckeditor.js') ?>

Then edit the ckeditor configuration (see the last lines)

CKEDITOR.editorConfig = function(config) {
    config.height = 550;
    config.extraPlugins = 'widget,lineutils,uploadimage';
    config.contentsCss = [
        '/js/node_modules/bootstrap/dist/css/bootstrap.min.css',
    ];
    config.allowedContent = true;
    config.toolbarGroups = [
        { name: 'document', groups: ['mode', 'document', 'doctools'] },
        { name: 'clipboard', groups: ['clipboard', 'undo'] },
        { name: 'editing', groups: ['find', 'selection', 'spellchecker', 'editing'] },
        { name: 'forms', groups: ['forms'] },
        { name: 'styles', groups: ['styles'] },
        { name: 'colors', groups: ['colors'] },
        { name: 'tools', groups: ['tools'] },
        { name: 'others', groups: ['others'] },
        { name: 'about', groups: ['about'] },
        '/',
        { name: 'basicstyles', groups: ['basicstyles', 'cleanup'] },
        { name: 'paragraph', groups: ['list', 'indent', 'blocks', 'align', 'bidi', 'paragraph'] },
        { name: 'links', groups: ['links'] },
        { name: 'insert', groups: ['insert'] },
    ];

    config.removeButtons = 'Save,NewPage,Preview,Print,Find,Replace,SelectAll,Scayt,BidiLtr,BidiRtl,Language,Flash,Smiley,Font,TextColor,BGColor,Maximize,About';

    //Configurazioni per elFinder
    config.allowedContent = true;
    config.filebrowserBrowseUrl = '/js/elFinder/elfinder-cke.html';

};

Then go to /webroot/js/elFinder and create a file called elfinder-cke.html, based on elfinder.html, where you should edit the relevant files, in particular

line 11: 
<script data-main="./main.js" src="//cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js"></script>
line 18: 
url : '/admin/articles/ckeconnector' (the url of your connector)

That's it: it should work!