1

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.

1
  • Your title says "Empty Post Request", but the problem you describe is a not-empty (confirmed in devtools) POST which returns a 404 ...? When your browser is displaying step2, what is the URL in the location bar? When you submit step2, and inspect the request in devtools, what is the URL the request was POSTed to? Commented Apr 27 at 22:27

2 Answers 2

0

main plugin File

<?php
/*
Plugin Name: Your Plugin Name
*/

// Include your class file
require_once 'includes/class-form-handler.php'; // Adjust the path if needed

function my_plugin_shortcode($atts) {
    $form_handler = new Form_Handler();
    return $form_handler->init_funnel();
}
add_shortcode('custom_funnel', 'my_plugin_shortcode');

add_action('template_redirect', 'my_plugin_handle_form_submission');

function my_plugin_handle_form_submission() {
    if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['funnel_nonce'])) {
        $form_handler = new Form_Handler(); //create new instance
        $form_handler->process_form();

        $redirect_url = $_SERVER['REQUEST_URI'];
        wp_safe_redirect($redirect_url);
        exit(); //important
    }
}

includes/class-form-handler.php

<?php
class Form_Handler {
    public function init_funnel() {
        ob_start();
        $this->handle_steps();
        $output = ob_get_clean();
        return $output;
    }

    private function handle_steps() {
        

        if (!isset($_SESSION['current_step'])) {
            $_SESSION['current_step'] = 1;
        }

        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;
        }
    }

    public 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;
        }
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

Code-only answers are considred low quality on SO. What did you change? What was the problem, and how does your code fix it? Edit your question, add explanations.
0

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>

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.