Pull Quotes in Drupal 7 – Using hook_filter_info()
I recently wrote a post called Pull Quotes Shortcodes via Custom Filters in Drupal 7 . This was a good solution, but I decided I wanted a little more flexibility in my filter (like being able to specify attributes in any order) and I wanted to get rid of the required [/pullquote] closing tag. Custom Filter has its limitations (and working through the gui would’ve been a PITA), so I fired up Vim and made a custom filter using hook_filter_info().
Here is part of my original description of what I needed:
I’ve been working on a Drupal 7 site that requires some nicely-formatted pull quotes. The site editors need the ability to add them to their content easily through the “filtered” text fields throughout the site (e.g., body).
End Result
The shortcode (this term makes the most sense here) I want to offer to the editor looks like this:
1 |
[pullquote align="right" author="John Smith" text="This is a right pull quote"] |
The HTML output I’d like to render (given the example above) looks like this:
1 2 3 4 |
<div class="pullquote pullquote-right"> <div class="quote">This is a right pull quote</div> <div class="author">—John Smith</div> </div> |
Rather than explain the different options I’d like to offer, I’ll just include this screenshot of the help text that the editors will see:
Setup and Configuration
Step 1: Create the filter. In this example I’m using a module called “mymodule”. The comments in the code should provide you with an explanation of what’s going on. I’m using hook_filter_info() from the Filter api (this is part of Drupal 7 core; I’d be surprised if you don’t have this enabled already).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
/** * Implements hook_filter_info(). */ function mymodule_filter_info() { $filters = array(); $filters['pullquote'] = array( 'title' => t('Pull quote filter'), 'description' => t('Formats the text as a quote with alignment and author options'), 'process callback' => '_mymodule_filter_pullquote_process', 'tips callback' => '_mymodule_filter_pullquote_tips', ); return $filters; } /** * Implements filter process callback. */ function _mymodule_filter_pullquote_process($text, $filter, $format, $langcode, $cache, $cache_id) { // Loop through all [pullquote] tags if (preg_match_all('/\[pullquote.*\]/i', $text, $matches)) { foreach ($matches[0] as $quote) { $attributes = array(); $quote_clean = str_replace('"', '"', $quote); // Get all of the attributes within this tag; if no attributes are found it's not valid // Currently we're only matching values of standard text including whitespace, &, and ; (for things like ) // TODO: come up with a more reliable regex pattern; (.*) isn't the best idea, but the pattern below may be too limiting if (preg_match_all('/([a-zA-Z_]+)="([0-9a-zA-Z\/\.=?: &;\-_\(\),]+)"/i', $quote_clean, $attributes_matches)) { foreach ($attributes_matches[1] as $key => $value) { $attributes[$value] = $attributes_matches[2][$key]; } // We can only proceed if we have a "text" attribute; skip to next match if not found if (!isset($attributes['text'])) { continue; } // If we don't have the align attribute, or it's not left, center, or right, then use "left" as the default if (!isset($attributes['align']) || ($attributes['align'] != 'left' && $attributes['align'] != 'center' && $attributes['align'] != 'right')) { $attributes['align'] = 'left'; } // Generate some new markup $result = "<div class='pullquote pullquote-{$attributes['align']}'>"; $result .= "<div class='quote'>{$attributes['text']}</div>"; if (!empty($attributes['author'])) { $result .= "<div class='author'>—{$attributes['author']}</div>"; } $result .= '</div>'; // Replace the original tag with the new markup $text = str_replace($quote, $result, $text); } } } return $text; } /** * Implements filter tips callback. */ function _mymodule_filter_pullquote_tips() { return t(' <strong>Pull quotes</strong>: formats the text as a quote positioned either <em>left</em> (default), <em>center</em>, or <em>right</em> of the main text.<br/> <em>Examples:</em> <ul> <li><em>Basic:</em> <code>[pullquote text="This is a pull quote"]</code></li> <li><em>All options:</em> <code>[pullquote align="right" author="John Smith" text="This is a right-aligned pull quote"]</code></li> </ul> '); } |
Step 2: Add the custom filter to the text formats in which you want to use pull quotes. For example, to add this new filter to the Full HTML text format I went to Admin » Configuration » Content authoring » Text formats » Full HTML, then I checked the Pull quote filter checkbox and made sure the filter was in the right position in the filter processing order (in my case, at the top).
Step 3: Try it out! Hit a content type that allows you to use a text format you added the filter to, and try one of the examples.
Step 4: Add styling to your stylesheets to make the output look pretty!
Conclusion
Well, there you have it: another “custom” solution for nice-looking, easy-to-add pull quotes.