0

I am trying to add an apply_filters function to a property of a class so that the form fields could be added to from another plugin or functions.php but I just can't get the $filter_fields to set. Can anyone tell me what I'm doing wrong? When I echo out $form_fields I get the h4 and the submit button but no fields.

class-registration-form.php

class RegForm {


         // Properties
        private $fields;

        private $filter_fields;

         // Constructor
        function __construct(){

            $this->fields = array(
                'name'      => '<label>Name.</label><br>
                                <input type="text" name="name"><br>',
                'business name' => '<label>Business Name.</label><br>
                                <input type="text" name="business_name"><br>',
                'email'     => '<label>Email.</label><br>
                                <input type="email" required="required" name="email"><br>',
                'password'  => '<label>Password.</label><br>
                                <input type="password" required="required" name="password"><br>'
                );

            add_shortcode('registerform', array($this, 'create_reg_form'));

        }

          // Methods

            public function init (){
                $filter_fields = apply_filters('tbg_reg_fields', $this->fields);
            }

            public function create_reg_form ($filter_fields){

                $form_fields = implode($this->filter_fields);


                ?>
                    <h4>Register as a New Store Owner</h4>
                        <form method="post" class="tbg_reg_form" action="' . admin_url( 'admin-ajax.php' ) . '">
                            <?php echo $form_fields; ?>
                            <input type="hidden" name="action" value="tbg_form_submit">
                            <input type="submit" value="Start Selling Now">
                        </form>
                    <?php
                    }
                }

        $newForm = new RegForm;
        add_action ('plugins_loaded', [$newForm, 'init']);

and in the themes functions.php file I have

    // Registration Fields 

function add_age_field($new_fields) {
    $new_fields[] = '<label>Website.</label><br><input type="text" name="website"><br>';
    return $new_fields;
}

add_filter('tbg_reg_fields', 'add_age_field');
1
  • you don't use the variable $filter_fields in init() then the new value is lost. you can add this filter in the constructor when you define the field list.
    – Kaperto
    Jan 3, 2020 at 14:49

1 Answer 1

2

Your problem has nothing to do with apply_filters, it's a basic PHP mistake:

            public function init (){
                $filter_fields = apply_filters('tbg_reg_fields', $this->fields);
            }

Here, you create a brand new variable in the init method scope named $filter_fields, then never use it.

$this->filter_fields and $filter_fields are not the same.

Additionally, because you used a filter and stored the fully formed HTML in advance, it's impossible to late escape, leading to security issues.

So instead, replace this:

                    <h4>Register as a New Store Owner</h4>
                        <form method="post" class="tbg_reg_form" action="' . admin_url( 'admin-ajax.php' ) . '">
                            <?php echo $form_fields; ?>
                            <input type="hidden" name="action" value="tbg_form_submit">
                            <input type="submit" value="Start Selling Now">
                        </form>

With a do_action, like this:

                    <h4>Register as a New Store Owner</h4>
                        <form method="post" class="tbg_reg_form" action="' . admin_url( 'admin-ajax.php' ) . '">
                            <?php do_action( 'tbg_reg_fields', $this->fields ); ?>
                            <input type="hidden" name="action" value="tbg_form_submit">
                            <input type="submit" value="Start Selling Now">
                        </form>

That way:

  1. you can output the HTML directly
  2. the action only runs when the code is being generated, unlike the original which runs even when there are no shortcodes on the page
  3. You can escape the fields in the functions that output them
  4. The call to init method and the filter_fields variable can be completely eliminated

Further general code quality notes:

  • You're using array( $this, '.... use PHP 5.3+ short array syntax instead [ $this, '... instead
  • It's impossible to load class-registration-form.php without creating that class, making it impossible to create unit tests
  • There's no reason for this to be a class, the entire thing could be simplified to a function named create_reg_form, moving the fields array into that function, and calling add_shortcode on the init hook. The class provides nothing, it isn't object oriented, and makes the code more complex, not less, and you only ever have one instance, so it's a waste of memory to create an object
  • admin-ajax.php is for really old AJAX handlers! Stop abusing it as a form handler! Leave the action blank and then check $_POST on init to check if your form got submitted and handle it there. Don't abuse admin-ajax.php for things it was never intended for. if ( !empty( $_POST['action'] ) && $_POST['action'] === 'tbg_form_submit' ) on the init action is more than enough

Your Answer

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

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