I'm creating a custom form for a wordpress page, and I'm using admin-post.php as my action. However, whenever I try to submit the form, I get a 404.

Below is the code which outputs the form:

function output_email_verification() {
      $error = '';
      if(isset($_COOKIE['rguroo_form_error'])) {
          $error = $_COOKIE['rguroo_form_error'];
      return '<form action='.esc_url( admin_url("admin-post.php") ).'method="post">
                <p class="error">'.$error.'</p>
                <input type="radio" label="Purchase 12 months access" value="purchase" name="rguroo_desired_action" checked>Purchase 12 months access</input>
                <input type="radio" label="Renew account" name="rguroo_desired_action" value="renewal">Renew account</input>
                <input type="radio" label="Create trial account" name="rguroo_desired_action" value="trial">Create trial account</input>
                <p class="form-subtext">* indicates required field</p>
                <p>Email address*</p>
                <input type="text" name="rguroo_email" required>
                <p>Re-type email address*</p>
                <input type="text" name="rguroo_email_confirmation" required>
                <input type="hidden" name="action" value="rguroo_email_verification_form">
                <input type="submit" value="Submit"> 

This is the action that I've hooked onto admin-post.php

add_action( 'admin_post_nopriv_email_verification_form', 'verify_and_sanitize_email_form', $priority = 10, $accepted_args = 1 );
add_action( 'admin_post_email_verification_form', 'verify_and_sanitize_email_form', $priority = 10, $accepted_args = 1 );

// Email verification callback
function verify_and_sanitize_email_form() {
    if(empty($_POST) || !isset($_POST['rguroo_email']) || !isset($_POST['rguroo_email_confirmation']) || !isset($_POST['rguroo_desired_action'])) {
        send_form_error('There is one or more empty fields');
    $sanitized_email = sanitize_email( esc_html($_POST['rguroo_email'] ));
    $sanitized_email_confirmation = sanitize_email( esc_html($_POST['rguroo_email_confirmation'] ));
    $desired_action = esc_html($_POST['rguroo_desired_action']);

    if(!is_email( $sanitized_email ) || !is_email( $sanitized_email_confirmation )) {
        send_form_error('Email is not valid');

    if($sanitized_email !== $sanitized_email_confirmation) {
        send_form_error('Emails do not match');

    if($desired_action !== 'purchase' || $desired_action !== 'renewal' || $desired_action !== 'trial') {
        send_form_error('Fatal error with radio buttons');

    if(!isset($_COOKIE['rguroo_form_type'])) {
        send_form_error('Server error');

    // student email verification logic
    $form_type = $_COOKIE['rguroo_form_type'];
    if($form_type === 'student') {
        $trail = substr($sanitized_email, -4);
        if($trail !== '.edu') {
            send_form_error('Not a valid student email');
        // Other university specific logic here
    setcookie('rguroo_form_action',$desired_action, 14 * DAY_IN_SECONDS);
    setcookie('rguroo_form_email', $sanitized_email, 14 * DAY_IN_SECONDS);


// Helper. Used to output an error
function send_form_error($msg) {
    setcookie('rguroo_form_error', $msg, 14 * DAY_IN_SECONDS);

Sorry about the mess of error validation.

Any ideas?


First of all...

Your action is called rguroo_email_verification_form, so you should use it when registering your hooks. But you use this instead:

add_action( 'admin_post_nopriv_email_verification_form', 'verify_and_sanitize_email_form', $priority = 10, $accepted_args = 1 );
add_action( 'admin_post_email_verification_form', 'verify_and_sanitize_email_form', $priority = 10, $accepted_args = 1 );

It should be:

add_action( 'admin_post_nopriv_rguroo_email_verification_form', 'verify_and_sanitize_email_form', $priority = 10, $accepted_args = 1 );
add_action( 'admin_post_rguroo_email_verification_form', 'verify_and_sanitize_email_form', $priority = 10, $accepted_args = 1 );

Also... These actions don't take any params, but you declare they should take one param (but later on, your function doesn't take any...)

  • The last parameter in add_action defaults to 1. Excluding the last two parameters of add_action would be completely identical to what I currently have. Also, I've fixed the mistake with the names, but the problem persists
    – Eli
    Jun 19 '19 at 18:00

As pointed out by Krzysiek, there was an inconsistency between the action field in the form and the admin-post hook.

That being said, the real source the issue and the cause of the 404 was a formatting error.

<form action='.esc_url( admin_url("admin-post.php") ).'method="post">

Was outputting

<form action="https://rguroo.com/wp-admin/admin-post.phpmethod=post">

The correct tag was as follows:

<form action="'.esc_url( admin_url("admin-post.php") ).'" method="post">

I'm an idiot...

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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