Hướng dẫn custom CKEditor để thêm tag mới Drupal WYSIWYG Module

The WYSIWYG module in Drupal is a great way of integrating a client side HTML editor (better known as a WYSIWYG editor) into a Drupal site. It supports a variety of different editors, all of which can be configured depending on the input format being used by the user. The ability to incorporate many different content editors into a site using a single module means that the configuration interface for them all is pretty much the same. It also means that it isn't a disaster if a different editor is needed for an existing site. You just need to ensure that the correct configuration options are set to allow a similar user experience.

I normally use a combination of the WYSIWYG module and the CKEditor on my Drupal sites, which tends to be a good combination of components. Much of the configuration of CKEditor can be done through the WYSIWYG module, but I have found the need to add additional configuration options on recent projects. This is done using the hook_wysiwyg_editor_settings_alter() hook from the WYSIWYG module. This hook is called from a function called wysiwyg_get_editor_config() and is used to set configurations before the WYSIWYG JavaScript is written to the page. This hook has two parameters:

  • $settings : This is an associative array of JavaScript settings to pass to the editor. This can be altered to change things within the editor.
  • $context : This is another associative array containing information about the environment that is being loaded and will contain the following elements:
    • editor: The name of the editor being used (e.g. ckeditor).
    • profile: The editor profile object, which is loaded from the database.
    • theme: The name of the current editor theme, not the current site theme.

It is possible to go in and alter the config.js file found in the CKEditor folder. However, this can cause problems in the future, especially if you want to update CKEditor to the latest version. You will need to reintegrate any changes you've made all over again. For this reason the hook approach is must more robust and future proof.

We can now create an implementation of this hook in a module that can do a variety of different things. The elements of the $settings variable map directly with the CKEditor configuration settings, which means that any setting the CKEditor has can be altered just by addressing the correct element. The CKEditor documentation details exactly what settings can be applied to the editor using this setting. For example, to change the height of the WYSIWYG editor you would set the height element of the $settings array. The height value defaults to 200px and accepts any CSS compatible value. The following is an example implementation of the hook that checks for the CKEditor being loaded and then sets the height of the editor window to 100px.

/**
 * Implements hook_wysiwyg_editor_settings_alter().
 */
function MY_MODULE_wysiwyg_editor_settings_alter(&$settings, $context) {
  if ($context['profile']->editor == 'ckeditor') {
    // Set height of WYSIWYG element to be 100px tall.
    $settings['height'] = '100px';
  }
}

One of the first things that I normally do in this hook is to load in an external JavaScript file so that certain options can be set for the editor using JavaScript. Doing this makes sense as the settings of CKEditor are JavaScript based anyway and so you will be setting the configuration options natively. It also means that you don't need to know the WYSIWYG hooks inside and out and so you can allow your designers to add options to this file without having to edit any PHP. The customConfig element of the $settings array allows you to add a custom JavaScript file to the editor configuration. This file is loaded along with the other configuration files when a WYSIWYG text area containing the CKEditor is found.

/**
 * Implements hook_wysiwyg_editor_settings_alter().
 */
function MY_MODULE_wysiwyg_editor_settings_alter(&$settings, $context) {
  if ($context['profile']->editor == 'ckeditor') {
    // Using ckeditor, set custom config file.
    $settings['customConfig'] = base_path() . drupal_get_path('module', 'MY_MODULE') . '/MY_MODULE_ckeditor_config.js';
  }
}

All that is then needed is to create the JavaScript options file and place it into the module directory. Here is an example of a typical customConfig file that sets up a couple of options. In this case we are allowing two types of HTML tags to be added to the WYSIWYG input, and also activating automatic content stripping. The allowedContent option is used to prevent bad formatting as a result of pasted text, usually from programs like Word.

/**
 * @file MY_MODULE_ckeditor_config.js
 *
 * Custom configuration for CKEditor.
 */
 
/**
 * Set up custom configurations for the CKEditor editor.
 */
CKEDITOR.editorConfig = function(config) {
 
  // Allow <i class="xyz"></i> for Font Awesome.
  config.protectedSource.push( /<i class=\".*\"\><\/i\>/g );
 
  // Allow <div class="xyz"></div> tags through.
  config.protectedSource.push( /<div class=\".*\"\>.*?<\/div\>/g );
 
  // Activate automatic AFC mode (if not already set).
  config.allowedContent = true;
};

What is good about the options I have discussed above is that they both work in the Drupal 6 and Drupal 7 versions of the WYSIWYG module. This means that you can use pretty much exactly the same module in your legacy projects without any alterations to the WYSIWYG hook and editor configuration detail.

Your <script> tags are not being stripped out, but the funky <ins> tag is. From that blog post you should be able to add a protectedSource to the AFC rules so that those elements are not stripped. This is untested but deriving from the blogpost:

// Allow Google Adsense <ins> tags, I'm being more specific

// than allowing any raw <ins> tag here. This may be too specific, but

// play with it.

config.protectedSource.push( /<ins class=\"adsbygoogle\"\>.*?<\/ins\>/g );

In order for this configuration to work you may have to install the WYSIWYG module (or append to your own ckeditor javascript profile directly).