Author: Edit Olah

Take control over the HTML markup in the WYSIWYG editor!

Drupal custom module - WYSIWYG - accordion and 2-column section

You can create different custom WYSIWYG plugins for site editors to be able to click a button in the WYSIWYG editor’s toolbar and inject specific markup with clickable areas where they can input content.

Mentor:
Chris Maiden

There is always a love and hate relationship with WYSIWYG editors in content management systems. Clients love them, developers … well, not so much.
Giving access to the source code within a WYSIWYG editor opens up Pandora’s box for broken HTML and inline CSS that is inconsistent with the site branding to say the least.

If it was the developers’ decision, they would probably only provide a button for making the text bold, and a further few buttons for lists, links, and indentation in the WYSIWYG toolbar, additional to the essential cut, copy, and paste buttons.

On the other hand, for a client, it is important to take all that flexibility and ease of use that a WYSIWYG editor can offer. It is also useful to minimise confusion by getting a visual confirmation about the element inserted into the WYSIWYG editor through inputting the HTML markup that picks up the right styling where possible.

The approach that I discuss in this article builds upon the best of both worlds. While it leaves the source code button disabled, it provides custom coded WYSIWYG plugins that are tailored to the needs of the site editors.

Click here for our beginner-friendly step-by-step guide to adding a button to the WYSIWYG editor that allows the user to add a block quotation with specific HTML markup.

This solution allows site editors to insert page elements such as an accordion or columns through the WYSIWYG editor. You can also specify the styling of the inserted elements as they appear in the WYSIWYG editor’s text area to aid the ease of use.

GitHub Gist:

Custom WYSIWYG plugin for Drupal 7 - accordion

Custom WYSIWYG plugin for Drupal 7 - accordion element

Custom WYSIWYG plugin for Drupal 7 - 2-column section

Prerequisites:

Create a WYSIWYG plugin to insert an accordion

Let’s look at the accordion first. Our specified markup for the accordion encompasses description lists within which the <dt> tag holding the accordion titles, and the <dd> tag holdind the associated content.

The desired markup looks like this:

<dl class="accordion">
  <dt class="accordion__title">
    <a href="#" href="#">Accordion title 1</a>
  </dt>
  <dd class="accordion__description">
    <p>Some text 1</p>
  </dd>
  <dt class="accordion__title">
    <a href="#" href="#">Accordion title 2</a>
  </dt>
  <dd class="accordion__description">
    <p>Some text 2</p>
  </dd>
</dl>

For our WYSIWYG plugin, we create a custom module. Inside the module folder we have another folder called ‘plugins’. (For further details on the folder structure, the files and their contents click here.)
Inside the ‘plugins’ folder, each plugin has its respective folder and its ‘.inc’ file.

d -| custom_wysiwyg
d --| plugins
d ----| accordion
d ------| icons
  --------| accordion.png
  ------| plugin.js
  ----| accordion.inc
  --| custom_wysiwyg.info
  --| custom_wysiwyg.module

Inside the ‘.inc’ file, define your plugin by providing the necessary meta information for Drupal about where to look for the icon for your new button in the WYSIWYG toolbar, and how to find the ‘plugin.js’ file.

<?php
/**
 * Implements hook_INCLUDE_plugin().
 */
function custom_wysiwyg_accordion_plugin() {
  $plugins['accordion'] = array(
    'title' => t('Accordion description list'),
    'icon path' => drupal_get_path('module', 'custom_wysiwyg') . '/plugins/accordion/icons',
    'icon file' => 'accordion.png',
    'icon title' => t('Insert Accordion - a description list wrapper'),
    'js path' => drupal_get_path('module', 'custom_wysiwyg') . '/plugins/accordion',
    'js file' => 'plugin.js',
    'settings' => array(),
  );

  return $plugins;
}

The ‘plugin.js’ file provides the JavaScript integration - tapping into the functions and methods of the Wysiwyg module - that will determine the markup and the behaviour:

Drupal.wysiwyg.plugins.accordion = {
  invoke: function (data, settings, instanceId) {
    if (data.format == 'html') {
        var content = '<dl class="accordion"><dt class="accordion__title"><a href="#">Title placeholder</a></dt><dd class="accordion__description"><p>Content placeholder</p></dd></dl>';
    }
    if (typeof content != 'undefined') {
      Drupal.wysiwyg.instances[instanceId].insert(content);
    }
  }
};

The above code handles only the description list wrapper (<dl>) and inserts the first element of the accordion. To keep things simple, create a separate plugin, and therefore a separate button, for inserting additional accordion elements (<dt>-s and <dd>-s) into the accordion.

The ‘.inc’ file and the ‘plugin.js’ file of the new ‘accordionelement’ plugin will be very similar to the example above. You can copy the ‘accordion.inc’ and the ‘plugin.js’ file from the ‘accordion’ folder, paste them and rename them to be used for the ‘accordionelement’ plugin.

d -| custom_wysiwyg
d --| plugins
d ----| accordion
d ------| icons
  --------| accordion.png
  ------| plugin.js
  ----| accordion.inc
d ----| accordionelement
d ------| icons
  --------| accordionelement.png
  ------| plugin.js
  ----| accordionelement.inc
  --| custom_wysiwyg.info
  --| custom_wysiwyg.module

Make changes in the new ‘.inc’ file so that your new plugin picks up the right icon and uses the right ‘plugin.js’ file.

Remove the markup for the <dl> tag from the ‘plugin.js’ file of the ‘accordionelement’ plugin, so it looks like this:

Drupal.wysiwyg.plugins.accordionelement = {
  invoke: function (data, settings, instanceId) {
    if (data.format == 'html') {
        var content = '<dt class="accordion__title"><a href="#">Title placeholder</a></dt><dd class="accordion__description"><p>Content placeholder</p></dd>';
    }
    if (typeof content != 'undefined') {
      Drupal.wysiwyg.instances[instanceId].insert(content);
    }
  }
};

And that’s it!

Make sure that you enable your new buttons in the relevant WYSIWYG profile, and add the tags specified in the markup injected to the ‘Allowed HTML tags’ in the respective text format.

Now, your site administrators can breeze through inserting an accordion by first clicking into the WYSIWYG text area where they would like the accordion to appear, then clicking the button you have added to the WYSIWYG toolbar, and voilà! They should see the fruit of your hard work!

Screenshot of WYSIWYG editor with the new button in the toolbar for inserting an accordion section.

Needless to say, site editors can overwrite the placeholder texts to add their desired content. Moreover, they can insert a new accordion element by placing their cursor at the end of the accordion element’s content and clicking the button of your second plugin, ‘accordionelement’. This should insert an additional accordion element after the one they have placed their cursor in.

Screenshot of WYSIWYG editor with the new button in the toolbar for inserting an accordion element.

- ! TIP ! -

To enjoy the styling of the site inside the WYSIWYG editor, make use of the ‘CSS’ section in the configuration of the WYISWYG profile that is in use. Go to 'admin/config/content/wysiwyg/profile/profile_in_use/edit'; under ‘Editor CSS’, select ‘Define CSS’; under ‘CSS path’, specify a path to a CSS file or a comma-separated list of CSS files. In your comma-separated list, you can specify multiple CSS files from multiple sources. You can pull CSS files from a CDN (content delivery network) here as well, by leaving the ‘https:’ off.
E.g.
‘//cdn.my.organisation/my/path/css/mystylesheet.min.css,/sites/all/themes/custom_admin/css/editor.css’

How about a WYSIWYG plugin to insert a 2-column section?

The same approach can be used to create a plugin that inserts columns into the WYISWYG text area for your site editors to input content in.

In the ‘plugin.js’ file, the markup and the JavaScript will allow site editors to insert a 2-column section in 2 ways:

1. Blank:
By placing their cursor where they want to insert the 2-column section inside the WYSIWYG text area and then clicking the button. This will insert the 2-column section with the components of the columns empty, waiting for the content to be input.

2. With dummy text:
By selecting a piece of text to use as dummy text, and inserting 2 columns with the same selected text appearing in all components of the injected markup that they can overwrite later.

The ‘plugin.js’ file in the ‘twocolumns’ plugin directory should look something like this:

Drupal.wysiwyg.plugins.twocolumns = {
 invoke: function (data, settings, instanceId) {
  if (data.format == 'html') {
   if (data.content) {
    var content = '<section class="middle-split">'
                   + '<section class="middle-split__column1">'
                    + '<h2 class="heading">' + data.content + '</h2>'
                    + '<p>' + data.content + '</p>'
                   +'</section>'
                   + '<section class="middle-split__column2">'
                    + '<h2 class="heading">' + data.content + '</h2>'
                    + '<p>' + data.content + '</p>'
                   +'</section>'
                  + '</section>';
   } else {
    var content = '<section class="middle-split">'
                   + '<section class="middle-split__column1">'
                    + '<h2 class="heading"></h2>'
                    + '<p></p>'
                   +'</section>'
                   + '<section class="middle-split__column2">'
                    + '<h2 class="heading"></h2>'
                    + '<p></p>'
                   +'</section>'
                  + '</section>';
   }
  }
  if (typeof content != 'undefined') {
   Drupal.wysiwyg.instances[instanceId].insert(content);
  }
 }
};

As you can see there is nothing too complex happening here. It is just a simple buy useful custom WYSIWYG plugin.

Resources:

Wysiwyg module

CKEditor library

Solution for ‘CKEditor version could not be detected’

Adding custom styles to your WYSIWYG

DrupalContrib - wysiwyg.api.php

Related blog posts

  • Create a CKEditor plugin powered by the CKEditor API

    Create a CKEditor plugin powered by the CKEditor API

    Drupal custom module - WYSIWYG - block quotation

    How to create a WYSIWYG plugin - tapping into the powers of the CKEditor...

    More details >>

  • Create a CKEditor plugin using Drupal’s Wysiwyg module

    Create a CKEditor plugin using Drupal’s Wysiwyg module

    Drupal custom module - WYSIWYG - block quotation

    How to create a CKEditor plugin - tapping into the goodness of Drupal’s...

    More details >>

Contact Edit

Get in touch

If you are interested in hiring me, please drop me an email. I would be happy to send you my up-to-date resume.

Drupal Association member
Image of Edit