Add Multi-Element Wrapper Class With CKEditor in Drupal 8

 

The task at hand here is to allow the client to create a classed wrapper around multiple elements using CKEditor in Drupal 8.

The fundamental problem here is the CKEditor's built in "Styles" dropdown classes each <p> individually, while we need a class wrapping them.

You could probably make or install your own CKEditor plugin, but that's not what I did.

I did this with Javascript.

Create the class and add it to the menu at /admin/config/content/formats -> my format
2017-08-09_13-17-39.png

Add this setting to allow the class to be added:
2017-08-09_13-20-22.png

Note: If you want to allow any class, add this instead: <p class>

Establish the JS library.
mytheme.libraries.yml

content-sidebar:
  js:
    path-to-file.js: { }
  dependencies:
    - core/jquery

Here's the JS code you need:

(function ($, Drupal) {
  Drupal.behaviors.content_sidebar = {
    attach: function (context) {
      var foundSidebars = 1;
      while (foundSidebars > 0) {
        foundSidebars = wrapSidebarGroup($);
      }
      function wrapSidebarGroup($) {
        return $('p.content-sidebar__unprocessed').first().nextUntil(':not(.content-sidebar__unprocessed)').addBack().removeClass('content-sidebar__unprocessed').addClass('content-sidebar').wrapAll('<div class="content-sidebar__wrapper" />').length;
      }
    }
  };
}(jQuery, Drupal));

In the above, I have three classes:

  • .content-sidebar__unprocessed is the class applied in the WYSIWYG. It is removed by the JS.
  • .content-sidebar is the class that replaces .content-sidebar__unprocessed in the JS.
  • .content-sidebar__wrapper is the class the wraps all the found siblings of .content-sidebar__unprocessed.

Note: this code wraps all sibling classes. This means that you can't have two instances of .content-sidebar__wrapper not separated by any other element.

Add the library in the preprocess hook for the field containing the WYSWYG text in mytheme.theme.

function emulsify_preprocess_field(&$variables, $hook) {
  if ($variables['field_name'] == 'body') {
    $variables['#attached']['library'][] =  'mytheme/mylibrary';
  }
}

This is what it looks like in the end:
2017-08-09_13-28-23.png

If somebody has a better way to do this, comment, and I'll link from this blog entry.

About the Author

Hi. My name is Jeremiah John. I'm a sf/f writer and activist.

I just completed a dystopian science fiction novel. I run a website which I created that connects farms with churches, mosques, and synagogues to buy fresh vegetables directly and distribute them on a sliding scale to those in need.

In 2003, I spent six months in prison for civil disobedience while working to close the School of the Americas, converting to Christianity, as one does, while I was in the clink.