3

This question is purely hypothetical. I use WordPress a lot and know the filter structure from an implementation point of view. I'm now wondering what's the best way to implement such a structure (not the way WordPress uses, but the best way).

I will give a short overview of what the WordPress filter structure is. After that, I'll list my requirements and thoughts. At last, I'll ask some questions.

WordPress' filter structure

WordPress sends nearly every data through a filter function before it outputs the data to the browser. The WordPress Codex gives information in the Plugin API and the Filter Reference.

For a plugin developer, it's quite easy to add a filter:

  1. Create the PHP function that filters the data.
  2. Hook to the filter in WordPress, by calling add_filter()
  3. Put your PHP function in a plugin file, and activate it.

Let's look at these steps in some more detail:

  1. A filter function is a PHP function that takes one parameter, the input, and returns the output. It should not echo or print anything.
  2. The add_filter function (reference) looks like:

    add_filter ( 'hook_name', 'your_filter', [priority], [accepted_args] );
    

    hook_name is the action hook at which the filter should be called.
    your_filter is the name of your filter function.
    priority gives the, well, the priority of the filter (default: 10), where lower numbers are more important.
    accepted_arguments tells WordPress the filter function will take more parameters, but let's leave that out here, it's not one of my requirements.

  3. I don't have to explain this step, I think.

Requirements

I'd like to know how to implement a filter structure like WordPress has and for the sake of an actual answerable question, I have made up a hypothetical case with some requirements.

My case is a forum, in which I have several cases in which I'd want to use filters for the content, like:

  • A linkify filter to make bare URLs into nice, working hyperlinks
  • A smiley filter to replace ASCII smileys like ':D' into an image enter image description here (sorry for the imgur abuse)

I think the advantages of using filters for this would be:

  • Code clarity
  • Filters can be easily reused
  • Making it easy to implement that a user can switch a filter on and off
  • Easy implementation of additional filters in the future

My thoughts

I imagine WordPress keeps a multidimensional array like $filters[$hook][$filter]. Here is $hook the name of the hook when the filter has to be called and $filter an array of the filter settings, basically those that were passed to the add_filter() function. When an action hook point is reached, WordPress can iterate through the $filters[$current_hook] array and execute every filter.

Questions

  1. Is this the best way to include a filter system with the requirements I listed? If so, why? If not, why not; and what would be a better system and why?

  2. As I said I want users to be able to switch filters on and off.

    I thought of adding a enabled_filters column to the user table in the database, which would be a bitmask of the enabled filters. That would mean every filter would have a unique identifier, but more important that there aren't very much filters possible. So this wouldn't be the way to go.

    I also thought of adding a table enabled_filters with columns userId, filterName and enabled, to set the filters on and off with a new row. With using the filter name in every row, this would cost some data space on much users and filters, so a better but similar idea would be adding a table filters with id and filterName, and changing the filterName column of the enabled_filters table into a filterId column. This would also allow an additional field in the filters table, allow_disable, to disable the disabling of the filter.

    Is this second approach a good one, or are there better options? Key requirement is that I don't want to have to modify the base system when adding a filter.

  3. WordPress wants programmers to not print anything in a filter function, but return a new string. That means you'll have a variable $return in your filter function, to which you append new data all the time with $return .= '...';. Using echo or print() could be easier for programmers, also to make it easier to port existing code (which uses print functions) to a filter function. The filter system could use the ob_* functions to capture the printed data instead of sending it to the browser. Would this be a good way to implement filters? Are there any disadvantages, like speed?

  4. The last question is about when to use filters, and when not. It seems clear to me that the listed cases (linkify and smileys) are cases where filters are well-used. For things like signatures or avatars, to stick with the forum, it's different. I've tried to figure out why it feels different, and think it's because that would limit the use of a filter to one place.

    For example, avatars and profile overview filters could only be used next to a post. One of the nice things of a filter is that you can add the same filter function to a different action hook, so that you can pass both the post and the signature content through the linkify filter. Am I right here?

    Is it true that one shouldn't use filters for avatars, profile overviews and signatures? What can be said about general rules when and when not to use a filter? If I were to write documentation on my system for third-party developers, what should I write down on this topic?

2
  • 1
    Sounds like a good use case for the Decorator Pattern
    – Mike
    May 8, 2013 at 19:01
  • @Mike thanks a lot, interesting technique. Could you write an answer on it?
    – user76821
    May 9, 2013 at 5:41

1 Answer 1

2

Implementation

Is this the best way to include a filter system with the requirements I listed? If so, why? If not, why not; and what would be a better system and why?

WordPress is a grown system with the goal to be backward compatible all the time. Thus, it still uses techniques to mimic things, that can be done more straight with modern PHP. The hook system mimics the Observer pattern. WordPress' hooks are events in this context.

Storage

I want users to be able to switch filters on and off.

Your second approach is reasonable with slightly different semantics. You need a table for the filters and a map for the user's setting. You can even add per-filter configurations (serialized).

+-----------+
| Filters   |
+-----------+
| +id       | // unique filter id
| +name     | // unique name (ie., [part of] filename)
| +title    | // human readable name
| +enabled  | // whether or not the filter is available to users
| +settings | // default settings managed by admin
+-----------+

+---------------+
| FilterUserMap |
+---------------+
| +user_id      | // the user
| +filter_id    | // the filter
| +enabled      | // whether or not the user has enabled the filter
| +settings     | // the user's preferrences
+---------------+

Output

The filter system could use the ob_* functions to capture the printed data instead of sending it to the browser. Would this be a good way to implement filters? Are there any disadvantages, like speed?

Performance should never be your first concern. Most important is the readability and maintainability of the code. Using the output buffering is a good approach, if you add larger chunks of HTML, because that increases readability very much. Usually a filter will change the content instead of add something, so you mostly end up using preg_* functions.

Nevertheless, I guess, output buffering will be faster than string concatenation, since it is done on a level closer to the machine, but I don't have any figures.

Usage

Is it true that one shouldn't use filters for avatars, profile overviews and signatures? What can be said about general rules when and when not to use a filter? If I were to write documentation on my system for third-party developers, what should I write down on this topic?

No, I don't think so. It is normal that a filter does not fit into all situations. Think of html_specialchars, strip_tags, or mysqli_real_escape_string as some of PHP's native filter functions - they have special use cases and are not suitable everywhere.

You could define a FilterInterface extending PHP's SplObserver interface, and use it to implement special filter classes, so can control, where what kind of filter is usable.

2
  • This has been really helpful, thanks a lot! You say WordPress uses old methods for compatibility. Would a different approach than the Observer pattern be better in any way?
    – user76821
    May 9, 2013 at 11:22
  • No, the Observer pattern is is the right approach. Just the way it is implemented in WordPress is outdated.
    – nibra
    May 10, 2013 at 9:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.