Wysiwyg button with form

At my work i recently had the opportunity to build a wysiwyg plugin in drupal for formatting a token we had created for a customer. This precented a number of challenges which I though others might also have, so I will try to share them here.

This will be a four step tutorial for drupal 7

  1. Step one will be building the module and a simple wysiwyg button
  2. Step two will cover a simple wysiwyg button
  3. Step three will expand the button with a multi field form
  4. Step four will make this form dynamic with ajax callbacks for removing and adding fields

Step 1 - building the module

First step is to create our module so as always we need an info file:

name = Ting token
description = Provides tokens for inserting ting objects in text fields.
core = 7.x
package = Ding!
files[] = ting_token.module
files[] = ting_token.token.inc

I will presume that you are familier with the setup of an info file so I won't go into details here. Now I will go into the token file for this module.

For these tokens we wanted a format which would insert a view_mode and one or more entities to be rendered. First we need a token file with the file name module_name.tokens.inc, in here we need to define hook_token_info

function example_token_info() {
  $type = array(
    'name' => t('Example entity'),
    'description' => t('Display an entity.'),
  );
 
  // Core tokens for nodes.
  $consent['example'] = array(
    'name' => t("Example entity"),
    'description' => t("Show an entity."),
  );

  return array(
    'types' => array('example' => $type),
    'tokens' => array('example' => $consent),
  );
}

Next up we need to handle the tokens once inserted by defining hook_tokens

function example_tokens($type, $tokens, array $data = array(), array $options = array()) {
  $url_options = array('absolute' => TRUE);
  if (isset($options['language'])) {
    $url_options['language'] = $options['language'];
    $language_code = $options['language']->language;
  }
  else {
    $language_code = NULL;
  }
  $sanitize = !empty($options['sanitize']);
  $replacements = array();
  if ($type == 'example') {
    foreach ($tokens as $name => $original) {
      $args = explode(':', $name);
      $view_mode = array_shift($args);
      $eid = implode(':', $args);
      if(strpos($eid, ',') !== FALSE) {
        $eids = explode(',', rawurldecode($eid));
      } else {
        $eids = array(rawurldecode($eid));
      }
      
      $entities = entity_load('example', $eids);
      $output = '<div class="example-inline-list">';
      foreach($entities as $id => $entity) {
        $object = entity_view($entity, $view_mode);
        if($view_mode == 'list_item') {
          $object['#attributes']['class'][] = format_string('compact');
        }
        $output .= drupal_render($object);
      }
      $output .= '</div>';
      $replacements[$original] = $output;
    }
  }

  return $replacements;
}

For this customer our entities are ting entities so we are using specialized functions for these, but this code should work for most purposes. You might want to specialize the rendering of entities to fit your needs.

For this part of the module we actually don't need to write anything in our module file, but we will need it for the next part.