Using the Token module to enhance the Editor experience

The Setting: A planet far, far away. Our valiant heroine struggles to climb a volcano in time to rescue a darling puppy. Clouds of ash drift in the late afternoon wind, and the heat waves from the flowing lava distort the horizon. The ground shifts under her feet and we see crevices open in the rock of the slope ahead...

Errrr, well, not really. In reality, there is a Drupal 7 site, running on an Apache server, that displays large amounts of really cool content for a pretty big company in the entertainment industry. As you might assume, the content on this site is very rich and design heavy.

The Ask: This client came to us a little while ago with an interesting question: Is there an easy way for our content editors to include certain "widgets" in the flow of our news article text? For example, a carousel of related content, a really cool slideshow of images, or maybe a user poll about the article subject?

We would like the selection/insertion process to be as painless as possible, and we have a short list of the types of content we'd like to embed. We'd also like some of this embedded content to break out of the visual site layout and span the full width of the browser. Oh, and we should think about how this layout behaves on mobile.

Possible solutions: My first thought after hearing these details was "we need a shortcodes module with an api for Drupal, like Wordpress!" After a bit of research I turned up some options:

Returning to the client's ask, I realized that the "Is there an easy way" piece of the question would be the hardest part. The Shortcode module proved to not quite fit this use case, but luckily, Token/Token Insert solved this problem by giving me a nice way to add a button to the wysiwyg that triggers a modal window of insertable items.

Implemented solution: Drupal's Token module is pretty darn cool. After installing Token and Token Insert, here are the hooks I used to create some custom shortcodes, with a little bit of explanation as to my thought process.

Our goal was to give the editor a nice flow that looks something like this:

  1. Create an Article.
  2. Use the "Gallery" field to fill in a reference the gallery to be inserted.
  3. While entering content in the body of the Article, at the point where they'd like to display the gallery
    they just simply click the "Insert" button and choose the Gallery from the popup list of available shortcodes.
  4. Continue entering Article content.

With that in mind, let's dive into the code.

Define an example token: the purpose of this token is to display a gallery of images that the editor has already referenced via an Entity Reference field. The Gallery content type in this case is relatively complex in itself, so it's separate from the Article and therefore reusable across content if needed.

/**
 * Implements hook_token_info().
 */
function example_token_info() {
  $info = array();
  // Define a new token type.
  $info['types']['custom'] = array(
    'name' => t('Custom Shortcodes'),
    'description' => t('Description here'),
  );
  // Example Image Gallery: This is pulled from an entity reference field on the Article.
  $info['tokens']['custom']['gallery'] = array(
    'name' => t('Gallery Shortcode'),
    'description' => t('Display the gallery specified on this article.'),
  );
}

Then define the replacement for it when it's found in the content:

/**
 * Implements hook_tokens().
 */
function example_tokens($type, $tokens, array $data = array(), array $options = array()) {
  $replacements = array();
  $sanitize = !empty($options['sanitize']);
  // Check that the incoming token is our new "Custom" type
  if ($type == 'custom') {
    // Grab the current node, so that we can get field values from it
    $node = menu_get_object();
    if (!empty($node)) {
      // Step through our tokens, this example only has one.
      foreach ($tokens as $name => $original) {
        switch ($name) {
          case 'gallery':
            // Function call to a helper to grab the content we want to use
            $replacements[$original] = _construct_gallery_token();
          break;
        }
      }
    }
  }
}

And finally, go get the actual content and return it as rendered html.

/**
 * Helper function to construct Gallery token output
 * @see dc_shortcodes_tokens()
 * @return [string]                   Formatted output for display.
 */
function _construct_gallery_token() {
  // Get the gallery view
  $view = views_get_view('gallery_view');
  $view->set_display('block_gallery');
  $view->set_arguments(array($node->nid));
  $view->pre_execute();
  $execute = $view->execute();
  $output = '<div class="wrapper">';
  $output .= $view->render();
  $output .= '</div>';
  return $output;
}

In the end our client got multiple types of tokens, from galleries to poll embeds from an external service, and their editors are doing quite a bit less head scratching while entering the content. Visit DC Comics news to see some of these tokens living in the wild.

Comments

I truly prize your function, Wonderful post. dbddedbddbgcddef

Add new comment

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • You can enable syntax highlighting of source code with the following tags: <code>, <blockcode>, <cpp>, <java>, <php>. The supported tag styles are: <foo>, [foo].
  • Web page addresses and email addresses turn into links automatically.
  • Lines and paragraphs break automatically.

Ready for transformation?