8

I'm creating a form plugin to handle forms that can be hooked into using actions/filters by developers.

My plug-in needs to be able to handle different forms with different sets of filters and I see 2 ways of doing this.

Method 1

Fire of specific hooks for each form.

So code like this could be called form within my plugin:

$formId = 'contact';
$errors = apply_filters('forms_validate_' . $formId, $errors, $data);

And could be used like so:

add_filter('forms_validate_contact', function($errors, $data){
    if(empty($data['name'])){
        $errors['name'] = 'Name is required';
    }

    return $errors;
} 10, 2)

Method 2

Pass a parameter to the calling function.

So code like this could be called form within my plugin:

$formId = 'contact';
$errors = apply_filters('forms_validate', $formId, $errors, $data);

And could be used like so:

add_filter('forms_validate', function($formId, $error, $data){
    switch($formId){
        case 'contact':
            if(empty($data['name'])){
                $errors['name'] = 'Name is required';
            }
        break;
    }

    return $errors;
}, 10, 3)

Are there any examples in the WordPress core where this sort of issue is tackled?

Is there a preferred method of dealing with this?

2

Method 1 is much more robust and extendable, in my opinion.

Method 1: To add or remove forms, or other functionality, you just add or remove functions. In particular, you can do this from other files, such as separate modules of your plugin or other external plugins. I think this is the main argument in its favor: extensibility and modularity.

Method 2: In order to add or remove forms or other functionality you need to modify an existing function, which is much more bug prone. A switch statement like the one in method 2 easily gets out of hand. The list of cases can get very long, and it is easy to introduce bugs as soon as you have several filters with the same kind of switch statement. For example, you may want filters for validation, display of empty forms to be filled, display of the content of filled out forms, database management,... So now you have a bunch of functions each with a very long list of switch cases, that you have to keep in sync.

(I had some bad experience of this with a popular extension for gravity forms - it's not unmanageable if you are disciplined, e.g. keep the list of cases in the same order in all functions, but it's not pretty either.)

Locating bugs: Much easier with Method 1: the culprit will usually be the newly added filter or form, rather than some typo inadvertently introduced in that very long function of Method 2.

Examples: You'll find tons of examples of Method 1 in the wordpress core (e.g. https://developer.wordpress.org/?s=post+type&post_type[]=wp-parser-hook), but I don't remember a single instance of Method 2.

4

Make the hook name specific to what it does, not where it is called. Do not pass multiple parameters, because that is not easy to extend. Pass a parameter object instead.

Example

Create the parameter object with an interface for dependency injection:

interface Validation_Parameters {

    public function id();

    public function errors();

    // not a good name …
    public function details();
}

class Form_Validation_Parameters implements Validation_Parameters {

    private $id;

    private $errors;

    private $details;

    public function __construct( $id, $errors, $details ) {

        $this->id      = $id;
        $this->errors  = $errors;
        $this->details = $details;
    }

    public function id() {
        return $this->id;
    }

    public function errors() {
        return $this->errors;
    }

    public function details() {
        return $this->details;
    }
}

$params = new Form_Validation_Parameters( 
    'contact',
    new WP_Error(), // should be prepared better.
    [ 'request' => $_SERVER['REQUEST_URI'] ]
);

Now pass it in your filter:

$valid = apply_filters( 'form_is_valid', TRUE, $params );

A third-party developer can read it now, but not change it, so the others can rely on its structure, because there is no way to corrupt it.

add_filter( 'form_is_valid', function( $bool, Validation_Parameters $params ) {
    // do something and return a value
});
  • Although I like your idea of passing through an object for the filter paramaters, i'm not sure it answers my initial question. Also, what do you mean by: "Make the hook name specific to what it does, not where it is called" In the example above the the 'forms_validate' should be hooked into to validate the form based on the $data passed, I have modified the question to make this a bit clearer – veganista Apr 29 '15 at 13:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.