into pirate-speak” (see pirate.module at http://drupal.org/project/ pirate). As shown in Figure 12-1, they take some kind of textual
input, manipulate it, and return output.
Figure 12-1. A filter transforms text in some way and returns the transformed text.
A common use for a filter is to remove unwanted markup from user-submitted input. Figure 12-2 shows Drupal’s HTML filter at
work.
Figure 12-2. The Limit allowed HTML tags filter allows only certain tags through.
This filter is essential for preventing cross-site scripting attacks.
Filters and Text formats
filters do to know what to look for. For filters to perform their jobs, you must assign them to a Drupal Text format as shown in
Figure 12-3. Text formats group filters together so they can run as a batch when processing content. This is much easier than checking
off a handful of filters for each submission. To view a list of installed filters, either configure an existing Text format or create a new one by clicking on the Configuration link at the top of the page, followed by the Text format link on the Configuration page and
the Add text format link.
Figure 12-3. Installed filters are listed on the “Add text format” form.
Drupal ships with three text formats (see Figure 12-4):
• The Filtered HTML text format is made up of four filters:
• The Limit allowed HTML tags filter, which restricts which tags are allowed to pass through the filter
• The Convert URLs into links filter, which transforms web and e-mail addresses into hyperlinks
• The Convert line breaks into HTML line break converter, which converts carriage returns to their HTML counterparts
• The Correct faulty and chopped off HTML filter
• The Full HTML text format doesn’t use the Limit allowed HTML tags filter, but does implement the Convert URLs into links,
Convert line breaks into HTML, and Correct faulty and chopped off HTML filters.
• The Plain Text text format, which displays HTML tags as plain text
• The PHP Code text format is made up of a filter called PHP evaluator, and its job is to execute any PHP within a post. A good
rule of thumb is never to give users the ability to execute a Text format that uses PHP evaluator. If they canrun PHP, they can do
anything PHP can do, including taking down your site, or worse yet, deleting all your data. To protect against this possibility, Drupal
ships with the PHP evaluator filter disabled. If you must make it available,enable the PHP filter module.
Figure 12-4. Drupal installs with four configurable text formats by default.
Because text formats are collections of filters, they are extensible. You can add and remove filters, as shown in Figure 12-5.
You can change the text format’s name, add a filter, remove a filter, or even rearrange the order in which a text format’s filters are
executed to avoid conflicts. For example, you might want to run the URL filter before the Correct faulty and chopped off HTML
filter runs so the filter can inspect the anchor tags created by the URL filter.
Figure 12-5. Text formats are made up of a collection of filters. Shown in this figure are Drupal’s four default Text formats.
Installing a FilterInstalling a filter follows the same procedure as installing a module, because filters live within module files. Making a filter available
to use is therefore as easy as enabling or disabling the corresponding module by clicking on the Modules link in the top menu.Once
installed, click on the Configuration link at the top of the page, and on the Configuration page, click on the Text formats link to assign the new filter to the text format(s) of your choosing. Figure 12-6 shows the relationship between filters and modules.
Figure 12-6. Filters are created as part of modules.
Knowing When to Use Filters
You might be wondering why a filter system is even needed when you can easily manipulate text using existing hooks found else
where. For example, it would be just as easy to use hook_node_view() to convert URLs to clickable links rather than using the URL
filter. But consider the case in which you have five different filters that need to be run on the body field of nodes. Now suppose
you’re viewing the default http://example.com/?q=node page, which displays ten nodes at a time.
That means 50 filters need to be run to generate a single page view, and filtering text can be an expensive operation. It would also
mean that whenever a node is called, it has to run through the filters, even if the text that’s being filtered is unchanged. You’d be
running this operation over and over again unnecessarily.
The filter system has a caching layer that provides significant performance gains. Once all filters have run on a given piece of text,
the filtered version of that text is stored in the cache_filter table, and it stays cached until the text is once again modified
(modification is detected using an sha256 hash of the filtered contents). To go back to our example, loading ten nodes could effectively by pass all filters and just load their data straight from the cache table when that text hasn’t changed—much faster!
Now you could get really clever and say, “Well, what if we resave the filtered text back to the node table in our node_view hook?Then it would behave the same as the filter system.” Although that certainly addresses the performance issue, you’d be breaking a
fundamental concept of the Drupal architecture: never alter a user’s original data. Imagine that one of your novice users goes back
to edit a post only to find it smothered in HTML angle brackets. You’ll most certainly be getting a tech support call on that one. The goal of the filter system is to leave the original data untouched while making cached copies of the filtered data available to the rest of the Drupal framework. You’ll see this principle over and over again with other Drupal APIs.
Creating a Custom Filter
Sure, Drupal filters can make links, format your content, and transform text to pirate-speak on the fly, but what would be really
slick would be for it to write our blog entries for us, or at least help us get our creative juices flowing. Sure, it can do that, too!
Let’s build a module with a filter to insert random sentences into a blog entry. We’ll set it up so that when you run out of juice in
your post and need a creative spurt, you can simply type [juice!] while writing, and when you save your entry, it’ll bereplaced with
a randomly generated sentence. We’ll also make it so that if you need lots of creative juice, you can use the [juice!] tag multiple times
per post.
Create a folder named creativejuice located in sites/all/modules/custom/. First, add the creativejuice.info file to the creativejuice
folder:
name = Creative Juice
description = "Adds a random sentence filter to content." package = Pro Drupal Development
core = 7.x
files[] = creativejuice.module php = 5.2
Next, create the creativejuice.module file and add it, too:
<?php
/**
* @file
* A silly module to assist whizbang novelists who are in a rut by providing a
* random sentence generator for their posts.
*/
Implementing hook_filter_info()
Now that the basics of the module are in place, let’s add our implementation of hook_filter_info() to creativejuice.module:
/**
* Implement hook_filter_info().
*/
function creativejuice_filter_info() {
$filters = array();
$filters['creativejuice'] = array( 'title' => t('Creative Juice filter'),'description' => t('Enables users to insert random
sentences into their post'),'process callback' => '_creativejuice_filter_process', 'tips callback' => '_creativejuice_filter_tips',);
return $filters;}
The Process Function
The process function creativejuice_filter_process is called every time a node is saved—when the input type set for the node
matches a text filter where the creative juices filter is enabled.
/**
* Creativejuice filter process callback
*
* The actual filtering is performed here. The supplied text should be
* returned, once any necessary substitutions have taken place.
*/
function _creativejuice_filter_process($text, $filter, $format) { while (strpos($text, '[juice!]') !== FALSE) {
$sentence = creativejuice_sentence();
$text = preg_replace('&\[juice!\]&', $sentence, $text, 1);
}
return $text;
}
The function is relatively simple. The first step is to call a helper function that returns a random sentence, and the second line of code
simply uses the PHP string replace function to replace every instance of [juice!] with the random string returned fromthe creative
juice_sentence helper function.
Helper Function
I’ve created a helper function that returns a random sentence that will be used by the filter to replace the [juice!] tag.
/**
* Generate a random sentence.
*/
function creativejuice_sentence() {
$beginnings = array();
$beginnings[] = t('A majority of us believe');
$beginnings[] = t('Generally speaking,');
$beginnings[] = t('As times carry on');
$beginnings[] = t('Barren in intellect,');
$beginnings[] = t('Deficient in insight,');
$beginnings[] = t('As blazing blue sky pours down torrents of light,');
$beginnings[] = t('Aloof from the motley throng,');
$beginnings[] = t('While crafting a new Drupal module,');
$middles = array();
$middles[] = t('life flowed in its accustomed stream');
$middles[] = t('he ransacked the vocabulary');
$middles[] = t('the grimaces and caperings of buffoonery sting');
$middles[] = t('the mind freezes at the thought');
$middles[] = t('reverting to another matter enables freedom');
$middles[] = t('he lived as modestly as a hermit');
$middles[] = t('the coder repeatedly invoked hooks');
$ends = array();
$ends[] = t('through the red tape of officialdom.');
$ends[] = t('as it set anew in some fresh and appealing form.');
$ends[] = t('supported by evidence.');
$ends[] = t('as fatal as the fang of the most venomous snake.');
$ends[] = t('as full of spirit as a gray squirrel.');
$ends[] = t('as dumb as a fish.');
$ends[] = t('like a damp-handed auctioneer.');
$ends[] = t('like a bald ferret.');
$ends[] = t('with a frozen, sharpened badger.');
$ends[] = t('and achieve CMS nirvanna.');
// For every phrase group, pick a random value.
$sentence = array($beginnings[mt_rand(0, count($beginnings) - 1)],$middles[mt_rand(0, count($middles) - 1)],
$ends[mt_rand(0, count($ends) - 1)],);
// Take the three random values from the sentence groups,
// implode them together, and return the sentence.
return implode(' ', $sentence);}
The function is pretty simple—it creates an array of sentences and randomly picks a sentence to return to the calling function.
You use _creativejuice_filter_tips() to display help text to the end user. By default, a short message is shown with a link to
http://example.com/?q=filter/tips, where more detailed instructions are given for each filter.
/**
* Filter tips callback for creative juice filter.
*
* The tips callback allows filters to provide help text to users during the content
* editing process. Short tips are provided on the content editing screen, while
* long tips are provided on a separate linked page. Short tips are optional,
* but long tips are highly recommended.
*/
function _creativejuice_filter_tips($filter, $format, $long = FALSE) {
return t('<em>[creativejuice]</em> is replaced with the random sentences.');
}
In the preceding code, you return the same text for either the brief or long help text page, but if you wanted to return a longer
explanation of the text, you’d check the $long parameter as follows:
function _creativejuice filter_tips($filter, $format, $long = FALSE) {
if ($long) {
// Detailed explanation for http://example.com/?q=filter/tips page.
return t('The Creative Juice filter is for those times when your brain is incapable of being creative. These times come for every
one, when even strong coffee and a barrel of jelly beans do not create the desired effect. When that happens, you can simply
enter the [juice!] tag into your posts...');}
else {
// Short explanation for underneath a post's textarea.
return t('Insert a random sentence into your post with the [juice!] tag.');}}
Once this module is enabled on the modules page, the creativejuice filter will be available to be enabled for either an existing Text
format or a new Text format. For example, Figure 12-7 shows what the “Text format” section of the node editing form looks like
after the creative juice filter has been added to the Full HTML Text format.
Figure 12-7. The Full HTML Text format now contains the creative juice filter, as indicated by the
preceding section of the node editing form.
You can create a new blog entry with the correct Text format and submit text that uses the [juice!]
Today was a crazy day. [juice!] Even if that sounds a little odd, it still doesn't beat what I heard on the radio. [juice!]
This is converted upon submission to something like the following:
Today was a crazy day! Generally speaking, life flowed in its accustomed stream through the red tape of officialdom. Even if that sounds a little odd, it still doesn't beat what I heard on the radio. Barren in intellect,reverting to another matter like a damp-handed auctioneer.
Summary
After reading this chapter, you should be able to
• Understand what a filter and a Text format are and how they are used to transform text.
• Understand why the filter system is more efficient than performing text manipulations in
other hooks.
• Understand how Text formats and filters behave.
• Create a custom filter.
• Understand how the various filter operations function.
Không có nhận xét nào:
Đăng nhận xét