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.)
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;
}
?>
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.