Handling Form Submissions in WordPress Using admin-post.php

After 10 years of using WordPress, I recently came to know about the admin-post.php file — a built-in handler for form submissions in themes and plugins. In this post, I have shared how it works and the hooks it provides for both logged-in and non-logged-in users.

Illustration of a form submission being handled by the WordPress admin-post.php file

Recently, I came to know about the admin-post.php file, which is the WordPress Generic Request (POST/GET) Handler — intended for form submission handling in themes and plugins.

So, I was working on form handling in a plugin recently, and I have used the admin_post_{$action} hook, which executes if the user is logged in. That’s when I learned about admin-post.php. It also allows handling form submissions for non-logged-in users with a different hook. I have been using WordPress for 10 years, but I was not aware of this file. That’s the thing about WordPress — there is so much to learn, even after all these years. That’s why I say, learn WordPress deeply. Also, I think many other developers may not know about this file either — that’s why I am writing this post.

How it works

You point your form’s action attribute to admin-post.php and pass an action field in the request:

PHP
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
	<input type="hidden" name="action" value="submit_feedback">
	<?php wp_nonce_field( 'submit_feedback', 'submit_feedback_nonce' ); ?>
	<textarea name="feedback" required></textarea>
	<?php submit_button( 'Submit Feedback' ); ?>
</form>

Then you register a callback for your action:

PHP
add_action( 'admin_post_submit_feedback', 'my_plugin_handle_feedback' );

function my_plugin_handle_feedback() {
	if ( ! isset( $_POST['submit_feedback_nonce'] ) || ! wp_verify_nonce( $_POST['submit_feedback_nonce'], 'submit_feedback' ) ) {
		wp_die( 'Invalid request.' );
	}

	// Process the form data here.

	wp_safe_redirect( wp_get_referer() );
	exit;
}

Here, WordPress loads admin-post.php, reads the action from the request, and fires the matching hook. Your callback does the rest.

Available hooks

Following are the hooks fired by admin-post.php:

If you want to handle the same form for both logged-in and non-logged-in users, you need to register your callback on both admin_post_{$action} and admin_post_nopriv_{$action} hooks.

Important Notes

  • All these hooks exist since WordPress 2.6.0, so it is safe to use them in any plugin or theme.
  • If no callback is registered for the given action, WordPress responds with a 400 Bad Request using wp_die().
  • admin_post_{$action} only checks if the user is logged in — it does not check capabilities. It is better to verify a nonce and check current_user_can() yourself in the callback.
  • Even though the file lives in wp-admin, non-logged-in users can also hit it — that’s the whole point of the nopriv hooks. Don’t assume it is admin-only.
  • If you want to see how it works internally, the file is small enough to read in one go: admin-post.php source.

tldr; admin-post.php is a built-in WordPress handler for form submissions. Point your form to it, pass an action, and hook into admin_post_{$action} (logged-in) or admin_post_nopriv_{$action} (non-logged-in). No need to build your own form handling from scratch.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.