I have seen and been using the following technique for adding php scripts to my plugin for handling custom forms in a wordpress plugin.

from the quizzin plugin:

$code_pages = array('quiz_form.php','quiz_action.php', 'question_form.php', 'question.php');
        foreach($code_pages as $code_page) {
            $hookname = get_plugin_page_hookname("quizzin/$code_page", '' );
            $_registered_pages[$hookname] = true;

For example, the 'quiz_action.php' is later used as the target for an administration form (these forms are used only in wp-admin)

  <form name="post" action="<?php echo $GLOBALS['my_plugin_folder'] ?>/quiz_action.php" method="post" id="post">

UPDATE: This method is discussed here - Admin config screen without menu

The final comment below by a Wordpress core dev seems to discourage this:


So what is best practice here? Should administration forms be posting to wp-admin/admin.php?action=foo or wp-admin/edit.php?action=bar. How does one register these actions? Is this documented anywhere? To be clear, these files should not be linked from an admin menu.

I'm using Wordpress 3.0.4



I personally just add a menu link and in the function for it handle the form. With $_SERVER['REQUEST_URI'] as the action. Example below.

add_action("admin_menu", "menu" );
function menu(){
    add_menu_page('Test form', 'Test form', 'manage_options', 'show_form' );
function show_form(){
    if ( $_SERVER["REQUEST_METHOD"] == "POST" ){
            print "do stuff";
    } else {
         ?><form method="post" action="<?php echo $_SERVER['REQUEST_URI']; ?>"><input type="submit" /></form><?php
  • My only problem with this is that I would like to split my plugin into several files so it is easier to maintain. But thanks for the reply :) – codecowboy Jan 26 '11 at 12:13
  • 2
    You can do an include call in a function, it's what I do. One file for logic and if then logic file I do an include to the file with the html. – Backie Jan 26 '11 at 12:19
  • Ideally though, the form action could be pointed at the appropriate URL, eg. admin_url('admin.php?page=show_form') and not use the REQUEST_URI ..(which could contain any number of invalid query arguments, which you'd then be passing onto your form action). – t31os Jan 26 '11 at 13:56
  • Well I've found it easier to use REQUEST_URI as I may have added a few get queries to the page. But if your form is a post method then all it's fields will be in the $_POST super global. So if you just work on that then any extra get queries won't affect the data in the form. Also the REQUEST_URI has already proven itself as a valid way of getting to that form so it's extremely unlikely that it wouldn't work on the submission. – Backie Jan 26 '11 at 14:05
  • @t31os. What would be required for the plugin to respond to that admin url? Just a function called show_form() ? – codecowboy Jan 26 '11 at 14:20

Basically, it seems there are two ways to do this:

1) The $_registered_pages way detailed in the original question. This seems a bit non-standard and might confuse someone looking at your code.

2) Post your form to an admin url like admin_url('admin.php?page=show_form') where show_form() is a registered menu item/function. Inside show_form(), you can switch on whether or not a form has been submitted. If it has you can include another php file conditionally i.e:

function show_form()
    if ( $_SERVER["REQUEST_METHOD"] == "POST" && isset($_POST['submit'])) {


    } else {
        //do something else. 

Or just include the file and do any processing / switching in there (probably cleaner).

If you try and just use a file you have created as the form's post action you will get an error. As mentioned in the comments above above you should prevent your files from being called directly and protect and guard against CSRF attacks using nonces.

Apologies for the long comment thread. Would be grateful if people could confirm this is what they meant.

  • Fixed your code block for you. – t31os Feb 2 '11 at 18:03
  • A simple isset( $_POST ) would be sufficient to determine if a submission has occured, but yes no.2 would be the easy way to do it(you have full access to WordPress functions using this approach). I'd suggest adding some nonces to your form though, see: codex.wordpress.org/WordPress_Nonces – t31os Feb 2 '11 at 18:10

My approach for the last 12 months has been to call every function that processes $_POST or $_GET request. Within every function a couple of values, sometimes more, are checked to determine if that function is the applicable one i.e. a form name and a specific value from the form or URL that data validation can also be applied to.

I put all $_POST and $_GET through a single function which checks nonce, so that the nonce function is not called within every function. That process_POST_GET() function then includes() form processing functions.


It works fine and has no performance drawback. We're simply talking about 100 x if(isset()) and a very simple way to keeping it all tidy. I considered an add_action() for every function and realized that this adds more work for Wordpress than my approach because it still needs to call every function.

The example below has a lot of "wpecus_" because I was not using classes originally. We wouldn't need to prefix everything otherwise.


Today I'm considering using eval() to call the function using the form_name.

* $_POST and $_GET request processing procedure.
* Checks nonce from any form or URL, then includes functions that processing submission, then includes the
* file that determines which function to use to process the submission.
* @package WP e-Customers
* @since 0.0.1  
public function process_POST_GET(){       

    // form submission
    if(isset($_POST['wpecus_post_processing_required']) && $_POST['wpecus_post_processing_required'] == true){        
            // a few forms have the wpecus_admin_referer where the default hidden values are not in use
            check_admin_referer( $_POST['wpecus_admin_referer'] );         
            // 99% of forms will use this method
            check_admin_referer( $_POST['wpecus_hidden_panel_name'] );

    // url submission
    if(isset($_GET['wpecusprocess']) && isset($_GET['nonceaction'])){           
        check_admin_referer( $_GET['nonceaction'] );        

    // arriving here means check_admin_referer() security is positive       
    global $wpecus_debug_mode,$cont,$wpecus_is_free;

    // if $wpecus_debug_mode set to true or 1 on wpecustomers.php we dump $_POST
        echo '<h1>$_POST</h1>';
        echo '<h1>$_GET</h1>';

    // include form processing functions
    require_once(WTG_WPECUS_PATH . 'processing/wpecus_form_two.php');   
    require_once(WTG_WPECUS_PATH . 'processing/wpecus_form_one.php');

    eval('wpecus_postget_' . $_POST['wpecus_form_name']);                        


WP e-Customers I expect WP e-Customers to have around 200 admin forms by 2015. There will be a large collection of "Tools" for administrators to perform all sorts of tasks on Wordpress and phpBB through the Wordpress admin.

Debug var_dump() My approach to putting all requests through a single function creates a good point to do a dump. You may want to do this without the headers. My wpecus_var_dump() function also ensures an administrator is logged in, important security. Another point to consider is $wpecus_debug_mode is only set to true when the plugin is on the development blog. It checks the domain and installation path in the plugins main file. This means I can quickly distribute a copy of my plugins and debugging is automatically off. Accidentally leaving it on is fatal so if you want to setup a procedure for debugging Wordpress $_POST and $_GET requests do not just use var_dump(). You want the dumps to vanish when your no the one viewing the screen.

  • I should mentioned that "wpecus_hidden_panel_name" would be the form_name in your case. This is something that will be changed in WP e-Customers as I'm ditching my panel layout approach, invented by me lol – Ryan Bayne Sep 19 '13 at 14:50
  • I changed the above code a bit. The dump is handled better and more importantly I created a class for handling all form submissions. I use method_exists() and if it does not I use wp_die() which asks user to report. This should never happen though. WP e-Customers has multiple sections. Each with their own class for processing requests. A simple chain of extends will make this simple. – Ryan Bayne Sep 21 '13 at 2:26

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.