I'm building a WordPress plugin that has a page that consists of multiple forms. Each form is a step. Here's my form-handler:
<?php
class Form_Handler
{
public function init_funnel()
{
ob_start();
$this->handle_steps();
return ob_get_clean();
}
private function handle_steps()
{
error_log('CURRENT STEP: ' . ($_SESSION['current_step'] ?? 'not set'));
error_log('POST: ' . print_r($_POST, true));
error_log('SESSION: ' . print_r($_SESSION, true));
if (!isset($_SESSION['current_step']))
$_SESSION['current_step'] = 1;
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['funnel_nonce'])) {
$this->process_form();
}
error_log('AFTER PROCESS SESSION: ' . print_r($_SESSION, true));
switch ($_SESSION['current_step']) {
case 1:
include FUNNEL_PLUGIN_PATH . 'templates/step1.php';
break;
case 2:
include FUNNEL_PLUGIN_PATH . 'templates/step2.php';
break;
case 3:
include FUNNEL_PLUGIN_PATH . 'templates/step3.php';
break;
default:
include FUNNEL_PLUGIN_PATH . 'templates/final.php';
break;
}
}
private function process_form()
{
if (!isset($_POST['funnel_nonce']) || !wp_verify_nonce($_POST['funnel_nonce'], 'funnel_nonce')) {
wp_die('Security check failed.');
}
switch ($_SESSION['current_step']) {
case 1:
$_SESSION['step1'] = [
'satisfaction' => sanitize_text_field($_POST['satisfaction'])
];
$_SESSION['current_step'] = 2;
break;
case 2:
if (!empty($_POST['email']) && !empty($_POST['name'])) {
$_SESSION['email'] = sanitize_email($_POST['email']);
$_SESSION['name'] = sanitize_text_field($_POST['name']);
$_SESSION['current_step'] = 3;
} else {
$_SESSION['form_error'] = 'Please fill in all required fields.';
}
break;
case 3:
if (isset($_POST['review']) && strlen(trim($_POST['review'])) >= 40) {
$_SESSION['review'] = sanitize_textarea_field($_POST['review']);
$_SESSION['current_step'] = 4;
} else {
$_SESSION['form_error'] = 'Please write at least 40 characters review.';
}
break;
}
}
}
if (isset($_SESSION['form_error'])): ?>
<div class="error-message">
<?php
echo esc_html($_SESSION['form_error']);
unset($_SESSION['form_error']);
?>
</div>
<?php endif; ?>
When I run this, I get step1.php rendered properly. Logs printed properly. I fill in the step1 form, I submit it. step2.php
is rendered properly, I get step2.php
rendered. When I submit the step2.php
, I see the post request on the dev tools network tab but nothing gets printed on the logs, no code works. After submitting the step2, I get Page not Found
error on the browser. When I click to the back button in browser and refresh the page, I get logs printed sometimes but even then the post request is empty. So it doesn't work because it's empty.
step1.php:
<div class="funnel-container">
<h2>We value your feedback!</h2>
<p>Please answer the following questions:</p>
<form method="POST">
<?php wp_nonce_field('funnel_nonce', 'funnel_nonce'); ?>
<!-- Question 1 -->
<div class="form-group">
<label for="marketplace">Which marketplace did you purchase from? <span class="required">*</span></label>
<select name="marketplace" id="marketplace" required>
<option value="">Select a marketplace</option>
<option selected="selected" value="United States">United States</option>
<option value="United Kingdom">United Kingdom</option>
<option value="Canada">Canada</option>
<option value="Germany">Germany</option>
</select>
</div>
<!-- Question 2 -->
<div class="form-group">
<label for="order_number">Amazon Order Number <span class="required">*</span> <small><a target="_new"
href="https://www.amazon.com/gp/css/order-history">(What is this?)</a></small></label>
<input type="text" name="order_number" id="order_number" placeholder="000-0000000-0000000" required
pattern="\d{3}-\d{7}-\d{7}">
</div>
<!-- Question 3 -->
<div class="form-group">
<label>How happy are you with our product? <span class="required">*</span></label><br>
<label><input type="radio" name="satisfaction" value="Very Satisfied" required> Very Satisfied</label><br>
<label><input type="radio" name="satisfaction" value="Somewhat Satisfied" required> Somewhat
Satisfied</label><br>
<label><input type="radio" name="satisfaction" value="Neither Satisfied Nor Dissatisfied" required> Neither
Satisfied Nor Dissatisfied</label><br>
<label><input type="radio" name="satisfaction" value="Somewhat Dissatisfied" required> Somewhat
Dissatisfied</label><br>
<label><input type="radio" name="satisfaction" value="Very Dissatisfied" required> Very Dissatisfied</label>
</div>
<button type="submit" class="funnel-button">Continue ></button>
</form>
</div>
step2.php:
<div class="funnel-container">
<img src="/path-to-your-ebook-image.jpg" alt="Free Ebook" class="ebook-image">
<h2>Free Amazon $5 Gift Card</h2>
<form method="POST">
<?php wp_nonce_field('funnel_nonce', 'funnel_nonce'); ?>
<!-- Name Field -->
<div class="form-group">
<label for="name">Your Name <span class="required">*</span></label>
<input type="text" name="name" id="name" required>
</div>
<!-- Email Field -->
<div class="form-group">
<label for="email">E-mail Address <span class="required">*</span></label>
<input type="email" name="email" id="email" required>
</div>
<!-- Info Note -->
<p class="small-note">Your gift will be sent to your e-mail address</p>
<button type="submit" class="funnel-button">Continue ></button>
</form>
</div>
I'd really appreciate any help. I register the Form Handler as a short code in my main plugin file.
add_shortcode('custom_funnel', [new Form_Handler(), 'init_funnel']);
I tried adding filters to resolve 404 like:
add_action('template_redirect', function() {
if (is_404() && $_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['funnel_nonce'])) {
global $wp, $wp_query;
$page = get_page_by_path(trim($wp->request, '/'));
if ($page) {
$wp_query->is_404 = false;
$wp_query->is_page = true;
$wp_query->queried_object = $page;
$wp_query->queried_object_id = $page->ID;
$wp_query->post = $page;
$wp_query->post_type = 'page';
$wp_query->posts = [$page];
status_header(200);
}
}
});
But didn't solve anything.
I found out that the problem is some input names are reserved by WordPress and you can not use them. When I changed name attribute of the inputs, It's solved.
<div class="form-group">
<label for="name_user">Your Name <span class="required">*</span></label>
<input type="text" name="name_user" id="name" required>
</div>
<!-- Email Field -->
<div class="form-group">
<label for="email_user">E-mail Address <span class="required">*</span></label>
<input type="email" name="email_user" id="email" required>
</div>