4.6 core.php hook_filter($op, $delta = 0, $format = -1, $text = '')
4.7 core.php hook_filter($op, $delta = 0, $format = -1, $text = '')
5 core.php hook_filter($op, $delta = 0, $format = -1, $text = '')
6 core.php hook_filter($op, $delta = 0, $format = -1, $text = '', $cache_id = 0)

Define content filters.

Content in Drupal is passed through all enabled filters before it is output. This lets a module modify content to the site administrator's liking.

This hook contains all that is needed for having a module provide filtering functionality.

Depending on $op, different tasks are performed.

A module can contain as many filters as it wants. The 'list' operation tells the filter system which filters are available. Every filter has a numerical 'delta' which is used to refer to it in every operation.

Filtering is a two-step process. First, the content is 'prepared' by calling the 'prepare' operation for every filter. The purpose of 'prepare' is to escape HTML-like structures. For example, imagine a filter which allows the user to paste entire chunks of programming code without requiring manual escaping of special HTML characters like @< or @&. If the programming code were left untouched, then other filters could think it was HTML and change it. For most filters however, the prepare-step is not necessary, and they can just return the input without changes.

Filters should not use the 'prepare' step for anything other than escaping, because that would short-circuits the control the user has over the order in which filters are applied.

The second step is the actual processing step. The result from the prepare-step gets passed to all the filters again, this time with the 'process' operation. It's here that filters should perform actual changing of the content: transforming URLs into hyperlinks, converting smileys into images, etc.

An important aspect of the filtering system are 'input formats'. Every input format is an entire filter setup: which filters to enable, in what order and with what settings. Filters that provide settings should usually store these settings per format.

If the filter's behaviour depends on an extensive list and/or external data (e.g. a list of smileys, a list of glossary terms) then filters are allowed to provide a separate, global configuration page rather than provide settings per format. In that case, there should be a link from the format-specific settings to the separate settings page.

For performance reasons content is only filtered once; the result is stored in the cache table and retrieved the next time the piece of content is displayed. If a filter's output is dynamic it can override the cache mechanism, but obviously this feature should be used with caution: having one 'no cache' filter in a particular input format disables caching for the entire format, not just for one filter.

Beware of the filter cache when developing your module: it is advised to set your filter to 'no cache' while developing, but be sure to remove it again if it's not needed. You can clear the cache by running the SQL query 'DELETE FROM cache_filter';


$op: Which filtering operation to perform. Possible values:

  • list: provide a list of available filters. Returns an associative array of filter names with numerical keys. These keys are used for subsequent operations and passed back through the $delta parameter.
  • no cache: Return true if caching should be disabled for this filter.
  • description: Return a short description of what this filter does.
  • prepare: Return the prepared version of the content in $text.
  • process: Return the processed version of the content in $text.
  • settings: Return HTML form controls for the filter's settings. These settings are stored with variable_set() when the form is submitted. Remember to use the $format identifier in the variable and control names to store settings per input format (e.g. "mymodule_setting_$format").

$delta: Which of the module's filters to use (applies to every operation except 'list'). Modules that only contain one filter can ignore this parameter.

$format: Which input format the filter is being used in (applies to 'prepare', 'process' and 'settings').

$text: The content to filter (applies to 'prepare' and 'process').

$cache_id: The cache id of the content.

Return value

The return value depends on $op. The filter hook is designed so that a module can return $text for operations it does not use/need.

For a detailed usage example, see filter_example.module. For an example of using multiple filters in one module, see filter_filter() and filter_filter_tips().

Related topics

3 functions implement hook_filter()

Note: this list is generated by pattern matching, so it may include some functions that are not actually implementations of this hook.

filter_filter in modules/filter/filter.module
Implementation of hook_filter().
path_admin_filter_form_submit_filter in modules/path/path.admin.inc
Process filter form submission when the Filter button is pressed.
php_filter in modules/php/php.module
Implementation of hook_filter(). Contains a basic PHP evaluator.
6 invocations of hook_filter()
check_markup in modules/filter/filter.module
Run all the enabled filters on a piece of text.
filter_admin_configure in modules/filter/filter.admin.inc
Build a form to change the settings for a format's filters.
filter_admin_format_form in modules/filter/filter.admin.inc
Generate a filter format form.
filter_admin_format_form_submit in modules/filter/filter.admin.inc
Process filter format form submissions.
filter_list_all in modules/filter/filter.module
Build a list of all filters.

... See full list


developer/hooks/core.php, line 637
These are the hooks that are invoked by the Drupal core.


function hook_filter($op, $delta = 0, $format = -1, $text = '', $cache_id = 0) {
  switch ($op) {
    case 'list':
      return array(0 => t('Code filter'));

    case 'description':
      return t('Allows users to post code verbatim using &lt;code&gt; and &lt;?php ?&gt; tags.');

    case 'prepare':
      // Note: we use [ and ] to replace < > during the filtering process.
      // For more information, see "Temporary placeholders and
      // delimiters" at http://drupal.org/node/209715.
      $text = preg_replace('@<code>(.+?)</code>@se', "'[codefilter-code]' . codefilter_escape('\\1') . '[/codefilter-code]'", $text);
      $text = preg_replace('@<(\?(php)?|%)(.+?)(\?|%)>@se', "'[codefilter-php]' . codefilter_escape('\\3') . '[/codefilter-php]'", $text);
      return $text;

    case "process":
      $text = preg_replace('@[codefilter-code](.+?)[/codefilter-code]@se', "codefilter_process_code('$1')", $text);
      $text = preg_replace('@[codefilter-php](.+?)[/codefilter-php]@se', "codefilter_process_php('$1')", $text);
      return $text;

      return $text;


For Drupal 7, see hook_filter_info().

To invoke "process" from filters on custom content, use the function check_markup.

I've been looking a whole day why the filter didn't work. Until i found your comment. Thanks!

Hope you can help.
I need to replace with a custom content like:

case 'process':
  $out = _return_form();
  $process = str_replace('foo', $out, $text);
  return $process;
function _return_form() {
  return 'Some content';

When I call any function, the site is down.
How can I solve it?

Looks like brackets are not escaped in preg_replace, am I wrong?
Should be

('@\[codefilter-php\](.+?)\[\/codefilter-php\]@se', "codefilter_process_php('$1')", $text);