Lesson 24 – Displaying Professional Admin Success and Error Notices in Your WordPress Plugin

In the previous lesson, we successfully implemented the ability to delete auctions from the Flipnzee Auctions plugin. The feature works correctly, but from a user’s perspective there is one thing missing—feedback.

Imagine clicking Delete and returning to the auction list with no indication whether the deletion actually succeeded. Users may wonder whether the auction was removed or if something went wrong.

In this lesson, we’ll improve the user experience by displaying professional WordPress admin notices after important actions such as creating, updating, and deleting auctions.


Why Admin Notices Matter

WordPress itself uses admin notices throughout the dashboard.

For example:

  • Post published.
  • Settings saved.
  • Plugin activated.
  • Theme installed.

Users have become accustomed to seeing these messages. Your plugin should follow the same design pattern.


What We’ll Build

By the end of this lesson, the plugin will display messages such as:

  • Auction created successfully.
  • Auction updated successfully.
  • Auction deleted successfully.
  • Unable to delete auction.
  • Unable to update auction.

Each message will use the standard WordPress notice styles.


Passing Messages Between Pages

After an action is completed, the user is redirected back to an admin page.

For example:

wp_safe_redirect(
	admin_url(
		'admin.php?page=flipnzee-all-auctions&message=deleted'
	)
);

Notice the query parameter:

message=deleted

This allows the next page to know what happened.


Reading the Message

Inside the destination page we retrieve the message safely.

$message = isset( $_GET['message'] )
	? sanitize_text_field(
		wp_unslash( $_GET['message'] )
	)
	: '';

This ensures that only sanitized input is used.


Displaying a Success Notice

If the message equals deleted, we display a success notice.

if ( 'deleted' === $message ) :
?>

<div class="notice notice-success is-dismissible">
	<p>Auction deleted successfully.</p>
</div>

<?php endif; ?>

The classes are provided by WordPress.

  • notice
  • notice-success
  • is-dismissible

No custom CSS is required.


Displaying an Error Notice

If something goes wrong, we display an error.

<?php if ( 'error' === $message ) : ?>

<div class="notice notice-error is-dismissible">
	<p>Unable to delete auction.</p>
</div>

<?php endif; ?>

WordPress automatically styles it using the familiar red error notice.


Why Redirect Instead of Printing Messages?

Suppose we deleted the record and immediately echoed:

Auction deleted.

The user would remain on the processing page.

Instead, WordPress plugins usually:

  1. Perform the action.
  2. Redirect.
  3. Display a message.

This pattern avoids duplicate submissions when the browser is refreshed.


Benefits of This Approach

Our plugin now provides:

  • Clear feedback to administrators.
  • Consistent WordPress user experience.
  • Cleaner navigation.
  • Better security through redirects.
  • Professional appearance.

Best Practices Learned

Throughout this lesson we reinforced several WordPress development practices:

  • Use wp_safe_redirect() after processing forms.
  • Pass status information using query parameters.
  • Sanitize all incoming data.
  • Use WordPress admin notice classes.
  • Keep users informed after every important action.

What We’ve Achieved So Far

At this point, the Flipnzee Auctions plugin supports:

  • Plugin activation
  • Database creation
  • Admin dashboard
  • Add Auction
  • View Auctions
  • Edit Auction
  • Delete Auction
  • Admin notices
  • Secure nonces
  • CRUD operations

The plugin is beginning to feel like a real production-ready WordPress application rather than a simple demonstration project.


Coming Up Next

In Lesson 25, we’ll make the auction management screen even more powerful by adding Bulk Actions, allowing administrators to delete multiple auctions at once, just like the built-in WordPress Posts and Pages screens.

Lesson 22: Deleting Auctions Securely with Confirmation in WordPress

In the previous lessons, we successfully built the ability to create, view, and edit auctions from the WordPress admin panel. The final piece of the basic CRUD (Create, Read, Update, Delete) functionality is allowing administrators to safely delete auctions.

Deleting records is a destructive operation, so it must be implemented carefully. A poorly designed delete feature could allow accidental deletions or even expose your plugin to security vulnerabilities. In this lesson, we’ll build a secure delete system using WordPress best practices.


Why Deleting Requires Special Attention

Unlike creating or editing records, deleting permanently removes data from the database. This means we should always:

  • Verify the user’s permissions.
  • Protect against CSRF attacks using WordPress nonces.
  • Ask the administrator for confirmation.
  • Delete only the intended auction.
  • Redirect back with a success or error message.

Fortunately, WordPress provides built-in tools that make implementing secure deletion straightforward.


What We’ll Build

By the end of this lesson, every auction listed in the All Auctions page will include a Delete link.

The workflow will look like this:

  1. Administrator clicks Delete.
  2. A confirmation dialog appears.
  3. Clicking Cancel stops the process.
  4. Clicking OK sends a secure request.
  5. The selected auction is removed from the database.
  6. The administrator is redirected back to the auction list with a success message.

Step 1 — Create a Delete Method in the Auction Manager

Inside:

includes/class-auction-manager.php

we’ll add a new method named:

delete_auction( $auction_id )

This method will use WordPress’s $wpdb->delete() function to remove a single auction based on its ID.

Keeping database operations inside the Auction Manager keeps our plugin organized and follows the same architecture we’ve used for creating and updating auctions.


Step 2 — Handle Delete Requests

Next, we’ll open:

admin/class-admin-posts.php

and register another admin action.

Instead of processing form submissions, this action will process delete requests coming from the auction list.

The handler will:

  • verify the nonce
  • validate the auction ID
  • call delete_auction()
  • redirect back to the auction list

Separating request handling from database logic keeps the code easier to maintain.


Step 3 — Add Delete Links to the Auction Table

Our WP_List_Table currently displays an Edit action for every auction.

We’ll modify the Actions column so that every row displays:

Edit | Delete

The Delete link will include:

  • auction ID
  • WordPress nonce
  • delete action

This allows WordPress to verify that the request genuinely originated from an authorized administrator.


Step 4 — Display a Confirmation Dialog

Even administrators sometimes click the wrong link.

To prevent accidental deletions, we’ll attach a simple JavaScript confirmation dialog.

When the administrator clicks Delete, WordPress will ask:

Are you sure you want to delete this auction?

Selecting Cancel aborts the request.

Selecting OK continues with the deletion.

This small addition greatly improves the user experience while reducing accidental mistakes.


Why WordPress Uses Nonces for Delete Operations

Imagine an administrator is logged into WordPress and unknowingly visits a malicious website.

Without nonce protection, that website could secretly trigger requests that delete auctions from your plugin.

A WordPress nonce ensures that delete requests originate from your own plugin and are intentionally initiated by the administrator.

Although nonces are not passwords or encryption keys, they provide an important layer of protection against Cross-Site Request Forgery (CSRF) attacks.


Expected Result

Once this lesson is complete, the All Auctions page will look similar to this:

Auction IDListingStatusActions
1222DraftEdit | Delete
255ActiveEdit | Delete
3108ClosedEdit | Delete

Clicking Delete will display a confirmation dialog before permanently removing the auction.


What You’ll Learn

By completing this lesson, you’ll understand:

  • How to delete database records using $wpdb->delete()
  • How WordPress processes admin actions
  • Why delete operations require nonces
  • How to generate secure action links
  • How to redirect after completing an operation
  • How to improve usability with confirmation dialogs

Coming Up Next

In Lesson 23, we’ll make the auction management screen much more powerful by adding search, sorting, filtering, and pagination to our custom WP_List_Table. These features become essential as the number of auctions grows, helping administrators quickly locate and manage specific records.


Conclusion

With the addition of secure deletion, our auction plugin will support the complete set of CRUD operations—Create, Read, Update, and Delete. More importantly, we’ll implement this functionality using WordPress coding standards and security best practices, laying the foundation for a robust and production-ready auction management system.

Lesson 20: Building the Edit Auction Form

In the previous lesson, we successfully created an Edit Auction page and retrieved the selected auction from the database. When an administrator clicked the Edit link, the plugin displayed the auction’s current information.

Although this proved that our retrieval logic worked correctly, the page was still read-only. In this lesson, we’ll replace the information table with a fully editable form whose fields are automatically populated with the auction’s existing values.

This approach mirrors how WordPress edits posts, pages, users, and many other objects. Administrators see the current values, make changes, and then save them.


Learning Objectives

By the end of this lesson you will be able to:

  • Build an editable administration form.
  • Pre-populate form fields with database values.
  • Display existing auction information inside HTML inputs.
  • Create the foundation for updating auctions in the next lesson.

Current Workflow

Our current workflow is:

All Auctions
      ↓
Click Edit
      ↓
Retrieve Auction
      ↓
Display Read-only Table

After today’s lesson it becomes:

All Auctions
      ↓
Click Edit
      ↓
Retrieve Auction
      ↓
Editable Form
      ↓
Save Changes (Next Lesson)

Step 1 – Locate the Edit Auction Page

Open:

admin/class-admin.php

Locate the method:

public function edit_auction_page()

Inside the method you’ll find a table displaying the auction details.


Step 2 – Replace the Table with a Form

Replace the existing table with the following form:

<form method="post">

	<table class="form-table">

		<tr>

			<th scope="row">
				<label for="listing_id">Listing ID</label>
			</th>

			<td>
				<input
					type="number"
					id="listing_id"
					name="listing_id"
					value="<?php echo esc_attr( $auction->listing_id ); ?>"
					required
					class="regular-text"
				>
			</td>

		</tr>

		<tr>

			<th scope="row">
				<label for="start_price">Start Price</label>
			</th>

			<td>
				<input
					type="number"
					step="0.01"
					id="start_price"
					name="start_price"
					value="<?php echo esc_attr( $auction->start_price ); ?>"
					class="regular-text"
				>
			</td>

		</tr>

		<tr>

			<th scope="row">
				<label for="reserve_price">Reserve Price</label>
			</th>

			<td>
				<input
					type="number"
					step="0.01"
					id="reserve_price"
					name="reserve_price"
					value="<?php echo esc_attr( $auction->reserve_price ); ?>"
					class="regular-text"
				>
			</td>

		</tr>

		<tr>

			<th scope="row">
				<label for="buy_now_price">Buy Now Price</label>
			</th>

			<td>
				<input
					type="number"
					step="0.01"
					id="buy_now_price"
					name="buy_now_price"
					value="<?php echo esc_attr( $auction->buy_now_price ); ?>"
					class="regular-text"
				>
			</td>

		</tr>

		<tr>

			<th scope="row">
				<label for="status">Status</label>
			</th>

			<td>

				<select
					name="status"
					id="status"
				>

					<option value="draft" <?php selected( $auction->status, 'draft' ); ?>>
						Draft
					</option>

					<option value="active" <?php selected( $auction->status, 'active' ); ?>>
						Active
					</option>

					<option value="closed" <?php selected( $auction->status, 'closed' ); ?>>
						Closed
					</option>

				</select>

			</td>

		</tr>

	</table>

	<?php submit_button( 'Save Changes' ); ?>

</form>

Notice that every input field uses the current auction value. This allows administrators to modify existing information instead of re-entering everything.


Step 3 – Test the Plugin

Create a fresh ZIP and upload the updated plugin.

Navigate to:

Flipnzee Auctions → All Auctions

Click Edit.

Instead of a read-only table you should now see an editable form containing:

  • Listing ID
  • Start Price
  • Reserve Price
  • Buy Now Price
  • Status

The Save Changes button will appear but won’t update the database yet. We’ll implement that functionality in the next lesson.


Why Build the Form First?

Professional software development often separates the user interface from the data processing logic.

Today’s lesson focuses entirely on presenting editable fields.

The next lesson will focus on validating user input and updating the database.

Separating these concerns makes the code easier to understand, test, and maintain.


Lesson Summary

In this lesson we transformed the Edit Auction page from a read-only display into an editable administration form.

Each input field is automatically populated using data retrieved from the database, allowing administrators to modify auction information without retyping existing values.

Although the Save Changes button is now visible, it does not yet perform any updates. That functionality will be implemented in the next lesson.


Key Takeaways

  • Editable forms improve administrator usability.
  • Existing values should always be pre-populated.
  • esc_attr() safely outputs values inside HTML attributes.
  • Building the interface before processing simplifies development.

Common Mistakes

  • Forgetting to pre-populate form values.
  • Using echo without esc_attr() inside HTML attributes.
  • Omitting the Status dropdown.
  • Trying to update the database before the form is complete.

Git Commands Used

git add .

git commit -m "Lesson 20: Build Edit Auction form"

git push

Testing Checklist

Before moving to the next lesson, verify that:

  • ✅ The plugin activates successfully.
  • ✅ The Edit page opens correctly.
  • ✅ All fields contain the current auction values.
  • ✅ Status is selected correctly.
  • ✅ The Save Changes button appears.
  • ✅ No PHP errors occur.

Project Status

✅ Dashboard

✅ Add Auction

✅ Save Auction

✅ View Auctions

✅ WP_List_Table

✅ Row Actions

✅ Edit Auction Page

✅ Edit Auction Form

⬜ Update Auction

⬜ Delete Auction

⬜ Bid Engine

⬜ Escrow Workflow

Developer’s Notebook

Creating the editing interface before implementing database updates follows a common development pattern. It allows you to verify that data retrieval and presentation work correctly before adding validation and persistence logic. This incremental approach also makes debugging significantly easier because each lesson introduces only one major concept.

Lesson 14: Completing Your First End-to-End WordPress Plugin Workflow

Introduction

In the previous lesson, we created a dedicated form handler using the WordPress Admin Post API. The form was successfully submitted, the nonce was verified, and WordPress redirected the administrator back to the Add Auction page.

However, no auction was actually created.

In this lesson, we’ll complete the workflow by validating the submitted data, calling the Auction Manager, inserting the auction into the database, and displaying a confirmation message.

This is the first time every layer of our plugin works together.


Learning Objectives

By the end of this lesson, you’ll be able to:

  • Sanitize submitted data.
  • Call the Auction Manager from the form handler.
  • Insert records into the database.
  • Redirect users with status messages.
  • Display confirmation notices.
  • Complete your first end-to-end plugin workflow.

Our Complete Workflow

Administrator

↓

Add Auction Form

↓

admin-post.php

↓

Nonce Verification

↓

Data Validation

↓

Auction Manager

↓

Database

↓

Redirect

↓

Success Message

Every component now has a clearly defined responsibility.


Step 1 – Process Submitted Data

Open:

admin/class-admin-posts.php

Replace the comment:

/*
 * Form processing will be added
 * in Lesson 14.
 */

with:

$listing_id = absint( $_POST['listing_id'] );

$start_price = (float) $_POST['start_price'];

$reserve_price = (float) $_POST['reserve_price'];

$buy_now_price = (float) $_POST['buy_now_price'];

Step 2 – Create the Auction

Immediately below the previous code, add:

$auction_id = Flipnzee_Auction_Manager::create_auction(
	$listing_id,
	$start_price,
	$reserve_price,
	$buy_now_price
);

The Form Handler doesn’t communicate directly with the database.

Instead, it delegates that responsibility to the Auction Manager.


Step 3 – Redirect with Status

Replace:

wp_safe_redirect(
	admin_url( 'admin.php?page=flipnzee-add-auction' )
);

with:

if ( $auction_id ) {

	wp_safe_redirect(
		admin_url(
			'admin.php?page=flipnzee-add-auction&message=success'
		)
	);

} else {

	wp_safe_redirect(
		admin_url(
			'admin.php?page=flipnzee-add-auction&message=error'
		)
	);

}

exit;

Step 4 – Display the Message

Open:

admin/class-admin.php

Inside add_auction_page(), immediately before:

<div class="wrap">

add:

if ( isset( $_GET['message'] ) ) {

	if ( 'success' === $_GET['message'] ) {

		echo '<div class="notice notice-success is-dismissible"><p>Auction created successfully.</p></div>';

	}

	if ( 'error' === $_GET['message'] ) {

		echo '<div class="notice notice-error is-dismissible"><p>Unable to create auction.</p></div>';

	}
}

Step 5 – Test the Plugin

Create a fresh ZIP.

Upload the plugin.

Open:

Flipnzee Auctions → Add Auction

Enter:

  • Listing ID: 1
  • Start Price: 100
  • Reserve Price: 150
  • Buy Now Price: 300

Click:

Create Auction

You should now see:

Auction created successfully.

Step 6 – Verify the Database

Open phpMyAdmin.

Browse:

wp_flipnzee_auctions

Instead of zero rows, you should now see your first auction record.

Return to the plugin dashboard.

The Total Auctions counter should now display:

1

Congratulations! Your plugin has completed its first full workflow.


Lesson Summary

In this lesson, we completed the first end-to-end workflow of Flipnzee Auctions.

Administrators can now submit auction information through the WordPress Dashboard. The request is securely processed, validated, passed to the Auction Manager, stored in the database, and confirmed with a success message.

This marks the point where the plugin becomes genuinely functional.


Key Takeaways

  • ✓ Separate form processing from page rendering.
  • ✓ Sanitize submitted data.
  • ✓ Let the Auction Manager handle database operations.
  • ✓ Redirect after processing.
  • ✓ Display administrator-friendly status messages.

Common Mistakes

  • Accessing $_POST without validation.
  • Writing SQL inside the form handler.
  • Forgetting to redirect after processing.
  • Displaying raw database errors to users.

Git Commands Used

git add .

git commit -m "Lesson 14: Complete first end-to-end workflow"

git push

Project Status

✅ Development environment

✅ Plugin skeleton

✅ Plugin installation

✅ Plugin lifecycle

✅ .gitignore

✅ Data architecture

✅ Database table

✅ Auction Manager

✅ Retrieve auction records

✅ WordPress admin menu

✅ Plugin dashboard

✅ Add Auction page

✅ Secure form architecture

✅ Admin Post handler

✅ First end-to-end workflow

⬜ Display all auctions

⬜ Edit auctions

⬜ Delete auctions

⬜ Bid engine

⬜ Escrow workflow

⬜ Version 1.0

Project Evolution

Earlier lessons focused on building the plugin’s foundation. This lesson connects those individual pieces into a complete workflow. The administrator no longer interacts directly with the database; instead, each layer performs a specific role, resulting in a cleaner and more maintainable architecture.

This same pattern will be reused for editing auctions, deleting auctions, managing bids, and handling Escrow.com transactions.


Developer’s Notebook

One of the best indicators of a well-designed application is the separation of responsibilities. In Flipnzee Auctions, the form collects information, the Form Handler processes requests, the Auction Manager performs business logic, and the Database class manages storage. Because these responsibilities are clearly separated, the plugin can continue to grow without becoming difficult to understand or maintain.


Looking Ahead

In Lesson 15, we’ll display all saved auctions inside the WordPress Dashboard using a professional table layout. Instead of checking phpMyAdmin, administrators will be able to browse, review, and eventually edit auction records directly from the plugin interface.

Lesson 13: Creating a Dedicated Form Handler with the WordPress Admin Post API

Introduction

In the previous lesson, we improved the architecture of our Add Auction form by submitting it to WordPress’s admin-post.php endpoint and protecting it with a nonce.

However, there is still no code that actually receives the submitted form.

In this lesson, we’ll create a dedicated Form Handler class. This class will verify the nonce, validate the submitted data, and then call the Auction Manager to create the auction.

By keeping form processing separate from page rendering, we make the plugin cleaner, easier to maintain, and more aligned with WordPress best practices.


Learning Objectives

By the end of this lesson, you’ll be able to:

  • Understand the WordPress Admin Post API.
  • Register custom admin actions.
  • Create a dedicated form handler class.
  • Verify WordPress nonces.
  • Validate submitted form data.
  • Prepare the plugin for database insertion.

Why Create a Form Handler?

Instead of mixing everything together:

Form

↓

SQL

↓

HTML

we’ll separate responsibilities:

Form

↓

Form Handler

↓

Auction Manager

↓

Database

Each component now has one responsibility.


Step 1 – Create a New File

Inside the admin folder create:

class-admin-posts.php

Step 2 – Create the Form Handler

Copy the following code into the file.

<?php

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

class Flipnzee_Auction_Admin_Posts {

	/**
	 * Constructor.
	 */
	public function __construct() {

		add_action(
			'admin_post_flipnzee_create_auction',
			array( $this, 'handle_create_auction' )
		);
	}

	/**
	 * Handle Add Auction form submission.
	 */
	public function handle_create_auction() {

		// Verify nonce.
		check_admin_referer(
			'flipnzee_create_auction',
			'flipnzee_nonce'
		);

		// Form processing will be added in Lesson 14.

		wp_safe_redirect(
			admin_url( 'admin.php?page=flipnzee-add-auction' )
		);

		exit;
	}
}

new Flipnzee_Auction_Admin_Posts();

Understanding admin_post

WordPress automatically looks for an action matching:

admin_post_{action}

Our form contains:

<input
	type="hidden"
	name="action"
	value="flipnzee_create_auction">

WordPress therefore executes:

admin_post_flipnzee_create_auction

which calls our handler.


Understanding check_admin_referer()

This function verifies the nonce we added in Lesson 12.

If the nonce is invalid:

  • Processing stops immediately.
  • WordPress displays an error.
  • The request is rejected.

This protects our plugin against Cross-Site Request Forgery (CSRF) attacks.


Why Redirect?

After processing the form, we redirect back to the Add Auction page.

This prevents duplicate submissions if the administrator refreshes the page and follows the standard Post/Redirect/Get (PRG) pattern used by professional web applications.


Step 3 – Load the New Class

Open:

flipnzee-auctions.php

Immediately after loading the Admin class, add:

/**
 * Load Admin Posts Class
 */
if ( file_exists( FLIPNZEE_AUCTION_PATH . 'admin/class-admin-posts.php' ) ) {
	require_once FLIPNZEE_AUCTION_PATH . 'admin/class-admin-posts.php';
}

Step 4 – Test the Plugin

Create a new ZIP.

Upload the plugin.

Activate it.

Open:

Flipnzee Auctions → Add Auction

Complete the form.

Click:

Create Auction

Nothing will be saved yet.

However, if everything has been configured correctly, the form should redirect back to the Add Auction page without errors.

That’s exactly what we want at this stage.


Lesson Summary

In this lesson, we created a dedicated Form Handler using the WordPress Admin Post API.

Although the handler currently verifies the nonce and redirects the user, it establishes the architecture we’ll use for all future form processing.

In the next lesson, we’ll finally connect this handler to the Auction Manager and insert our first auction into the database.


Key Takeaways

  • ✓ Use admin_post for processing administration forms.
  • ✓ Verify nonces before processing data.
  • ✓ Separate form handling from page rendering.
  • ✓ Redirect after successful processing.
  • ✓ Build applications one layer at a time.

Common Mistakes

  • Forgetting to register the admin_post action.
  • Processing forms inside page-rendering methods.
  • Omitting nonce verification.
  • Forgetting to call exit after wp_safe_redirect().

Git Commands Used

git add .

git commit -m "Lesson 13: Create Admin Post form handler"

git push

Project Status

✅ Plugin dashboard

✅ Add Auction page

✅ Secure form architecture

✅ Admin Post handler

⬜ Save auction

⬜ Display auctions

⬜ Edit auction

⬜ Bid engine

⬜ Escrow workflow

⬜ Version 1.0

Project Evolution

Our plugin now follows a cleaner architecture by separating administration pages from form processing. This makes future features such as editing auctions, deleting auctions, and managing bids much easier to implement because every form can follow the same pattern.

As the project continues to grow, this separation of concerns will keep the codebase organized and easier to maintain.


Developer’s Notebook

One of the defining characteristics of well-designed WordPress plugins is that user interfaces and request processing are kept separate. While beginners often process forms directly inside page-rendering methods, larger plugins typically use dedicated handlers that can be reused, tested, and extended independently. Adopting this pattern early prepares the project for long-term growth and makes the code easier for other developers to understand.

Lesson 12: Processing WordPress Admin Forms the Professional Way

Introduction

In the previous lesson, we created our first Add Auction page inside the WordPress Dashboard. Although administrators can now fill in auction details, the form doesn’t yet save any information.

There are several ways to process WordPress forms. For small plugins, it’s common to process the submitted data inside the same function that displays the form. While this works, it mixes presentation with business logic.

In this lesson, we’ll adopt a more professional approach by using WordPress’s Admin Post API. This separates form processing from page rendering and produces cleaner, more maintainable code.

By the end of this lesson, administrators will be able to submit an auction through the dashboard, and the Auction Manager will store it in the database.


Learning Objectives

By the end of this lesson, you’ll be able to:

  • Understand the WordPress Admin Post API.
  • Protect forms with WordPress nonces.
  • Process form submissions in a dedicated handler.
  • Validate and sanitize submitted data.
  • Call the Auction Manager to save data.
  • Redirect users safely after processing.

Why Change Our Architecture?

A common beginner approach looks like this:

Display Form
      │
      ▼
Read $_POST
      │
      ▼
Save Database

This mixes multiple responsibilities inside one function.

Instead, we’ll use:

Display Form
      │
      ▼
admin-post.php
      │
      ▼
Form Handler
      │
      ▼
Auction Manager
      │
      ▼
Database

Each component now has one clearly defined responsibility.


What We’ll Build

Our plugin will now consist of:

  • Admin Class – Registers menus and displays pages.
  • Auction Manager – Handles auction business logic.
  • Form Handler – Processes submitted forms.
  • Database Class – Creates and manages database tables.

This separation makes the plugin easier to maintain as it grows.


Step 1 – Add a Nonce to the Form

Every administrative form should include a nonce.

Immediately before the submit button, add:

<?php wp_nonce_field(
	'flipnzee_create_auction',
	'flipnzee_nonce'
); ?>

This generates a hidden security token that WordPress verifies when the form is submitted.


Step 2 – Submit to admin-post.php

Instead of submitting the form back to the same page, we’ll submit it to WordPress.

Our form will eventually look like this:

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

We’ll also include a hidden field named:

<input
	type="hidden"
	name="action"
	value="flipnzee_create_auction">

The value of this field tells WordPress which handler should process the request.


Step 3 – Create a Form Handler

Rather than placing processing code inside the page-rendering method, we’ll create a dedicated handler class.

This handler will:

  • Verify the nonce.
  • Validate the submitted data.
  • Call the Auction Manager.
  • Redirect back to the dashboard.

This keeps the user interface completely separate from the business logic.


Step 4 – Validate and Sanitize Input

Before saving anything, we’ll clean the submitted data.

Examples include:

  • absint() for IDs.
  • (float) for prices.
  • sanitize_text_field() for text values.
  • wp_unslash() when appropriate.

Never trust raw $_POST values.


Step 5 – Save the Auction

Once the data has been validated, we’ll call:

Flipnzee_Auction_Manager::create_auction();

Notice that the form handler doesn’t execute SQL directly.

The Auction Manager remains responsible for interacting with the database.


Step 6 – Redirect Back

After processing the form, the handler redirects the administrator back to the Add Auction page.

This prevents duplicate submissions if the page is refreshed and follows the standard WordPress Post/Redirect/Get pattern.


Why This Is Better

Separating page rendering from form processing provides several advantages:

  • Cleaner code.
  • Easier debugging.
  • Better security.
  • Easier testing.
  • Simpler future enhancements.

As the plugin grows, we’ll reuse this same architecture for editing auctions, deleting auctions, placing bids, and updating settings.


Lesson Summary

In this lesson, we redesigned the way our plugin handles administration forms.

Rather than processing submitted data inside the page-rendering method, we adopted the WordPress Admin Post API. This keeps the user interface, form processing, and business logic separated into dedicated components.

Although this approach requires a little more setup, it scales much better as the plugin becomes more sophisticated.


Key Takeaways

  • ✓ Use WordPress nonces for every administration form.
  • ✓ Process forms through admin-post.php.
  • ✓ Keep HTML separate from business logic.
  • ✓ Validate and sanitize all user input.
  • ✓ Let the Auction Manager handle database operations.

Common Mistakes

  • Processing $_POST directly inside the view.
  • Forgetting nonce verification.
  • Trusting user input without validation.
  • Mixing SQL with HTML.

Git Commands Used

git add .

git commit -m "Lesson 12: Process admin forms using Admin Post API"

git push

Project Status

✅ Plugin dashboard

✅ Add Auction page

✅ Secure form architecture

⬜ Form handler

⬜ Save auction

⬜ Auction listing

⬜ Edit auction

⬜ Bid engine

⬜ Escrow workflow

Project Evolution

Earlier in this series, our focus was simply getting a working plugin. As the project has matured, we’ve begun adopting architectural patterns used in production-quality WordPress plugins.

Introducing the Admin Post API is one such refinement. Although it requires slightly more code, it provides a cleaner separation of responsibilities and lays the foundation for a plugin that will remain maintainable as features such as bidding, escrow integration, and website transfers are added.