Wordpress - How do i best handle custom plugin page actions?

As a rule of thumb, you should use a POST request for most actions, to make sure they are not executed by accident. But it is also a good practice to redirect to a normal page after a POST request, to prevent duplicate execution when the user refreshes the page.

So the flow is like this:

  1. Your plugin page with a POST form, which submits to
  2. A page that handles the request, which redirects to
  3. Your plugin page, which shows the result of the action

The middle page doesn't have to be your plugin page. This means that you can use the "generic POST handler" that was included three years ago, the 'admin_action_' . $_REQUEST['action'] hook in admin.php.

An example user is the Akismet plugin. If you want to use it reliably, you have to submit to admin.php directly, not to another page that happens to include admin.php.

Here is a very basic example of how to use it:

add_action( 'admin_action_wpse10500', 'wpse10500_admin_action' );
function wpse10500_admin_action()
{
    // Do your stuff here

    wp_redirect( $_SERVER['HTTP_REFERER'] );
    exit();
}

add_action( 'admin_menu', 'wpse10500_admin_menu' );
function wpse10500_admin_menu()
{
    add_management_page( 'WPSE 10500 Test page', 'WPSE 10500 Test page', 'administrator', 'wpse10500', 'wpse10500_do_page' );
}

function wpse10500_do_page()
{
?>
<form method="POST" action="<?php echo admin_url( 'admin.php' ); ?>">
    <input type="hidden" name="action" value="wpse10500" />
    <input type="submit" value="Do it!" />
</form>
<?php
}

I approached this slightly differently by simply adding noheader=true to the action url on the page where the user submits takes the action

My handler then performs the action (ie. typically an add, update or delete) then finisheswith a wp_redirect() to the next page action (e.g add page -> edit page, delete page -> list page, edit page -> edit page). I also pass a message on the URL so I can displayed a status such as update successfully or failed.

This approach keeps all the actions: list, add, edit, delete, bulk-delete, etc in the same class and with the same admin slug so it is pretty easy to maintain and to understand.