Best Practices for Creating and Handling Forms with Plugins?

I’m writing a plugin that creates and handles a simple form. This has been my approach sofar, but it’s turned out to have some major flaws:

1) On plugin activation, create a blank page for the form at mysite.com/form, and another blank page to process the form at mysite.com/processform. (They need to be separate pages with distinct URLs so that submissions can be tracked via google analytics. Otherwise, I’d just do all this via AJAX. I know, I know… not my decision.)

Read More

2) On the “wp” action, check to see what page we’re on.

2a) If it’s my form page, add a “the_content” filter to render the form (it needs some dynamic hidden elements like a nonce, which is why I didn’t just include the form markup when I created the form page originally).

2b) If it’s my processform page, add a “the_content” filter to process the POST and render any feedback.

The major problem is with my POST handling. I’m hooking it to the “the_content” filter (because I need it to supply feedback), but this filter is sometimes run multiple times during a page load, causing the POST to be handled multiple times.

I’ve included what I have below, but I can’t help thinking I’m completely on the wrong track with my approach. How would you create and handle a form with your plugin if you needed it to hit a success URL (ie. not via AJAX)?

My code:

<?php

    // On activation, create the blank pages
    function my_form_install() {

        // CREATE THE FORM PAGE
        $page_markup = '';

        $arr_page_options = array(
            'post_status' => 'publish',
            'post_type' => 'page',
            'post_author' => 1,
            'post_title' => 'Form',
            'post_content' => $page_markup,
            'comment_status' => 'closed'
        );

        // CREATE THE FORM PROCESSING/SUCCESS PAGE
        $success_page_markup = '';

        $arr_success_page_options = array(
            'post_status' => 'publish',
            'post_type' => 'page',
            'post_author' => 1,
            'post_title' => 'Form Process',
            'post_content' => $success_page_markup,
            'comment_status' => 'closed'
        );

    }
    register_activation_hook(__FILE__,'my_form_install');


    // On the wp action, check to see if this is one of our pages. If so, add our filters.
    function check_current_page($obj_wp) {

        if(isset($obj_wp->query_vars["pagename"])) {
            $page_name = $obj_wp->query_vars["pagename"];

            switch($page_name) {

                case "form":
                    add_filter('the_content', 'my_render_form');
                    break;

                case "form-process":
                    add_filter('the_content', 'my_process_form');
                    break;

            }   

        }

    }
    add_action('wp', 'check_current_page');

    // Function to render the form
    function my_render_form($page_markup) {


        $page_markup .= '<form method="post" action="/form-process">
        <input type="text" name="some_input_field" />
        <input type="submit" value="submit" />
        </form>';

        return $page_markup;

    }

    // Function to process the form
    function my_process_form($page_markup) {

        if($_POST) {

            // Do the form processing. This would involve many possible returns, 
            // but I've just included one to simplify thigns.
            $page_markup .= 'Your form has been processed.';

        }

        return $page_markup;

    }

?>

Related posts

Leave a Reply

1 comment

  1. That’s just a quick feedback: Use a shortcode to insert your form into content. Those are quite flexible. And for the processed form’s need to have another URL you can add a rewrite endpoint like /form/processed/ you can check after submission then. That’s probably more modular.

    In the end that prevents you to deal with the the_content filter as you can deal with anything within the shortcode callback.

    It’s a rough suggestion only, but probably does the job for you.