Lesson 78: Processing Administrator Payment Status Updates and Beginning Payment Verification

Overview

In the previous lesson, a dedicated Administrator Payments Dashboard was introduced, allowing administrators to view submitted buyer payments, inspect transaction details, and access a payment management interface.

However, the interface was still informational. Although administrators could select a payment status from a dropdown, those changes were not yet saved to the database.

In this lesson, we will connect the user interface to the backend by implementing secure form processing and updating payment records.


Objectives

By the end of this lesson, we will:

  • Register a secure administrator POST action.
  • Process payment status update requests.
  • Verify administrator permissions.
  • Validate WordPress nonces.
  • Update the payment_status field in the database.
  • Redirect administrators with success messages.
  • Prepare the payment verification workflow for future approval actions.

Why This Lesson Is Important

Until now, administrators could only view payment information.

This lesson transforms the payment dashboard into a working management system by allowing administrators to update payment progress after reviewing submitted payment proofs.


Current Workflow

Current administrator workflow:

Buyer Uploads Payment Proof
            │
            ▼
Payment Appears in Dashboard
            │
            ▼
Administrator Opens Details
            │
            ▼
Select Payment Status
            │
            ▼
Nothing Happens ❌

Desired Workflow

After this lesson:

Buyer Uploads Payment Proof
            │
            ▼
Payment Appears in Dashboard
            │
            ▼
Administrator Opens Details
            │
            ▼
Select Payment Status
            │
            ▼
Click Update
            │
            ▼
Database Updated
            │
            ▼
Success Message Displayed

Planned Implementation

1. Register the Admin POST Action

The payment management form already submits to WordPress using admin-post.php.

This lesson will register a dedicated action handler for processing payment updates.


2. Verify Administrator Permissions

Before processing any request, the plugin will confirm that the current user has sufficient privileges.

Only administrators should be allowed to modify payment records.


3. Verify the Nonce

Every request will validate the security nonce before updating the database.

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


4. Validate Submitted Data

Incoming data will be sanitized and validated before use.

Examples include:

  • Transaction ID
  • Payment Status

This ensures only expected values are processed.


5. Update the Database

The selected payment status will be written to the payment_status column of the transaction table.

Typical status transitions include:

  • Pending
  • Processing
  • Paid
  • Completed
  • Cancelled
  • Refunded

6. Redirect Back to the Transaction

After processing, administrators will be redirected back to the Transaction Details page instead of the generic transactions list.

This provides a smoother workflow.


7. Display Success Notices

Administrators should immediately know whether the update succeeded.

Examples include:

Payment status updated successfully.

or

Unable to update payment status.

8. Prepare for Payment Approval

Although this lesson focuses on updating payment statuses, the implementation prepares the foundation for future verification actions.

Upcoming lessons will introduce dedicated buttons such as:

  • Approve Payment
  • Reject Payment
  • Request New Payment Proof

Database Changes

This lesson will primarily update the following transaction field:

payment_status

Possible values include:

  • pending
  • submitted
  • processing
  • paid
  • completed
  • cancelled
  • refunded

Future lessons may introduce additional verification-specific statuses if needed.


Security Considerations

The payment verification process will follow standard WordPress security practices:

  • Capability checks
  • Nonce verification
  • Data sanitization
  • Safe database updates
  • Secure redirects

Expected Outcome

After completing this lesson:

  • Administrators can update payment status.
  • Database records are updated securely.
  • Transaction details immediately reflect the latest payment state.
  • Payment management becomes fully functional.
  • The administrator workflow becomes suitable for production use.

What You Will Learn

During this lesson, you will learn how to:

  • Process administrator forms using admin-post.php.
  • Secure backend form submissions.
  • Update custom database tables.
  • Redirect users after successful processing.
  • Separate payment management from transaction management.

Looking Ahead

Once payment status updates are working, the Flipnzee Auctions plugin will be ready for the next stage of payment verification.


Next Lesson Preview

Lesson 79: Reviewing Uploaded Payment Proofs and Approving Buyer Payments

In the next lesson, we will enhance the administrator experience by allowing payment proofs to be viewed directly from the Transaction Details page. Administrators will be able to inspect uploaded receipts, preview images or PDFs, and approve or reject payments before initiating the website ownership transfer process.

This will bring Flipnzee one step closer to a complete end-to-end marketplace workflow and lay the groundwork for integrating Escrow.com as the preferred payment gateway for live auctions.

Lesson 77 Implementation: Building the Administrator Payment Review Dashboard for Flipnzee Auctions

In the previous lesson, buyers were able to upload payment proof securely through the payment page, with uploaded receipts stored in the WordPress Media Library and linked to the corresponding transaction.

This lesson shifted focus from the buyer to the administrator by introducing a dedicated payment review dashboard. Administrators can now view submitted payments, inspect transaction details, and prepare payments for verification.


Objective

The primary goal of this lesson was to create an administrator interface that allows the Flipnzee team to review buyer payment submissions before approving website ownership transfers.

By the end of this implementation, administrators could:

  • View all submitted payments.
  • Open detailed transaction information.
  • Review payment metadata.
  • Prepare payment status management.
  • Lay the foundation for future payment verification.

Step 1 – Creating the Admin Payments Page

A new administrator page was created.

File created

admin/class-admin-payments.php

The page was implemented as a dedicated admin class.

class Flipnzee_Admin_Payments {

    /**
     * Render Payments page.
     *
     * @return void
     */
    public static function render_page() {

        ?>

        <div class="wrap">

            <h1>Buyer Payments</h1>

            <p>

                Review buyer payment submissions before approving
                the transfer of ownership.

            </p>

        </div>

        <?php
    }
}

This provided a clean starting point for the administrator payment workflow.


Step 2 – Registering the Payments Menu

A new submenu was added beneath the Flipnzee Auctions admin menu.

add_submenu_page(
    'flipnzee-auctions',
    'Payments',
    'Payments',
    'manage_options',
    'flipnzee-payments',
    array(
        'Flipnzee_Admin_Payments',
        'render_page',
    )
);

This created a dedicated Payments section for administrators.


Step 3 – Loading Submitted Payments

The Payments page was connected to the transaction table.

global $wpdb;

$table = $wpdb->prefix . 'flipnzee_transactions';

$payments = $wpdb->get_results(
    "
    SELECT *
    FROM {$table}
    WHERE payment_status = 'submitted'
    ORDER BY updated_at DESC
    "
);

Only transactions that had submitted payment proofs were displayed.


Step 4 – Handling Empty Results

Before rendering the table, the plugin checks whether submitted payments exist.

if ( empty( $payments ) ) {

    echo '<p>No payment submissions found.</p>';

} else {

    // Display payment table.

}

This prevents empty tables and provides useful feedback to administrators.


Step 5 – Building the Payments Table

A professional WordPress admin table was introduced.

<table class="widefat striped">

    <thead>

        <tr>

            <th>ID</th>
            <th>Listing</th>
            <th>Buyer</th>
            <th>Amount</th>
            <th>Gateway</th>
            <th>Status</th>
            <th>Submitted</th>
            <th>Actions</th>

        </tr>

    </thead>

The table closely follows the standard WordPress administration interface.


Step 6 – Displaying Submitted Payments

Each submitted payment is displayed using a loop.

<?php foreach ( $payments as $payment ) : ?>

<tr>

    <td><?php echo esc_html( $payment->id ); ?></td>

    <td><?php echo esc_html( $payment->listing_id ); ?></td>

    <td><?php echo esc_html( $payment->buyer_id ); ?></td>

    <td><?php echo esc_html(
        number_format_i18n(
            $payment->winning_bid,
            2
        )
    ); ?></td>

    <td><?php echo esc_html(
        $payment->payment_gateway
    ); ?></td>

    <td><?php echo esc_html(
        ucfirst( $payment->payment_status )
    ); ?></td>

    <td><?php echo esc_html(
        $payment->updated_at
    ); ?></td>

</tr>

<?php endforeach; ?>

The administrator can immediately identify submitted payments requiring review.


Step 7 – Adding the View Details Button

Instead of displaying placeholder text, each payment now links to a detailed transaction page.

<td>

    <a
        class="button button-primary"
        href="<?php echo esc_url(
            admin_url(
                'admin.php?page=flipnzee-transaction-details&transaction_id=' .
                absint( $payment->id )
            )
        ); ?>">

        View Details

    </a>

</td>

This significantly improves navigation between the payment dashboard and transaction details.


Step 8 – Enhancing the Transaction Details Page

The existing transaction details page was expanded with payment information.

Additional rows were added to display:

<tr>
    <th>Payment Status</th>
    <td><?php echo esc_html(
        ucfirst( $transaction['payment_status'] )
    ); ?></td>
</tr>

<tr>
    <th>Payment Gateway</th>
    <td><?php echo esc_html(
        $transaction['payment_gateway']
    ); ?></td>
</tr>

<tr>
    <th>Payment Submitted</th>
    <td><?php echo esc_html(
        $transaction['payment_submitted_at']
    ); ?></td>
</tr>

Administrators can now review payment-specific information alongside the transaction details.


Step 9 – Creating the Payment Management Section

A dedicated Payment Management panel was introduced.

<h2>Payment Management</h2>

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

This prepares the interface for future payment verification actions.


Step 10 – Securing the Form

The management form was protected using a WordPress nonce.

wp_nonce_field(
    'flipnzee_update_payment_status',
    'flipnzee_payment_nonce'
);

This ensures only legitimate administrators can submit payment updates.


Step 11 – Payment Status Dropdown

Administrators can now select a payment status.

<select
    name="payment_status"
    id="payment_status">

    <option value="pending">Pending</option>

    <option value="processing">Processing</option>

    <option value="paid">Paid</option>

    <option value="completed">Completed</option>

    <option value="cancelled">Cancelled</option>

    <option value="refunded">Refunded</option>

</select>

Although the update handler will be implemented in the next lesson, the interface is now fully prepared.


Challenges Encountered

Several issues arose during development.

Method Name Mismatch

Initially, the Payments submenu referenced render_page(), while the class still used render().

Standardizing on render_page() resolved the fatal error.


PHP and HTML Mixing

While building the Payment Management form, HTML was accidentally placed inside an open PHP block.

Example:

<?php

wp_nonce_field(...);

<input ...>

Closing PHP before the HTML resolved the syntax error.


Duplicate Status Rows

During iterative development, duplicate Payment Status rows were unintentionally introduced.

Cleaning up duplicate markup produced a clearer transaction details page.


Payment vs Transaction Status

One important architectural decision emerged during development.

The plugin now distinguishes between:

  • status (overall transaction lifecycle)
  • payment_status (buyer payment lifecycle)

This separation prepares the plugin for multiple payment gateways, including Escrow.com, without affecting the broader transaction workflow.


Testing Performed

The implementation was tested by:

  • Opening the new Payments admin menu.
  • Confirming submitted transactions appear in the table.
  • Verifying payment amounts and gateways display correctly.
  • Opening transaction details using the View Details button.
  • Confirming payment metadata is displayed.
  • Checking the Payment Management form renders correctly.
  • Validating PHP syntax after each modification.

Lessons Learned

This implementation reinforced several WordPress development practices:

  • Separate administrator workflows from buyer workflows.
  • Keep transaction management and payment management independent.
  • Use dedicated admin pages instead of overloading existing screens.
  • Secure administrator forms using nonces.
  • Build reusable interfaces that can support additional payment gateways in future.

Download Source Code

Download the starting version of the plugin before the lesson:

Download the completed version after this lesson:


Current Progress

At the end of Lesson 77, the Flipnzee Auctions plugin now includes:

  • ✅ Administrator Payments menu
  • ✅ Submitted Payments dashboard
  • ✅ Payment listing table
  • ✅ View Details navigation
  • ✅ Enhanced transaction details page
  • ✅ Payment metadata display
  • ✅ Payment Management interface
  • ✅ Secure administrator form ready for processing

The actual processing of payment status updates will be completed in the next lesson.


Next Lesson

Lesson 78: Processing Administrator Payment Status Updates

In the next lesson, we will connect the Payment Management form to the backend by:

  • Registering the administrator POST handler.
  • Verifying administrator permissions and nonces.
  • Updating the payment_status field in the database.
  • Redirecting administrators with success messages.
  • Preparing the workflow for payment approval, rejection, and future Escrow.com integration.

This will complete the first functional administrator payment verification workflow in the Flipnzee Auctions plugin.

Lesson 77: Improving the Buyer Payment Experience After Payment Proof Submission

Overview

In the previous lesson, buyers gained the ability to upload payment proof securely using WordPress’ Media Library. Uploaded receipts were successfully stored, linked to transactions, and duplicate uploads were prevented.

Although the functionality worked correctly, the user experience could still be improved. After submitting payment proof, buyers continued to see payment options and generic transaction statuses, making it unclear whether their submission had been received successfully.

In this lesson, the focus shifts from functionality to user experience by redesigning the payment page after proof submission.


Objectives

By the end of this lesson, we will:

  • Replace generic Pending messages with clearer payment statuses.
  • Hide payment options after payment proof has been uploaded.
  • Display a professional confirmation message.
  • Add a “View Uploaded Payment Proof” link.
  • Prevent buyers from attempting another payment.
  • Prepare the plugin for administrator verification.

Why This Improvement Matters

Once a buyer uploads payment proof, their next question is usually:

  • Did my upload succeed?
  • Will someone review it?
  • What happens next?

Showing payment options again creates uncertainty.

Instead, the page should reassure buyers that everything has been received and explain the next step.


Current Workflow

Current payment flow:

Auction Won
      │
      ▼
Choose Manual Payment
      │
      ▼
Complete Bank Transfer
      │
      ▼
Upload Payment Proof
      │
      ▼
Success Message
      │
      ▼
Payment Options Still Visible ❌

Desired Workflow

After this lesson:

Auction Won
      │
      ▼
Choose Manual Payment
      │
      ▼
Complete Bank Transfer
      │
      ▼
Upload Payment Proof
      │
      ▼
Payment Submitted
      │
      ▼
Waiting for Admin Verification
      │
      ▼
Payment Options Hidden

Planned Improvements

1. Improve Payment Status

Instead of displaying:

Pending

buyers should see something more meaningful, such as:

Submitted for Verification

or

Awaiting Verification

2. Hide Payment Method Selection

Once payment proof exists, buyers should no longer see:

  • Manual Payment
  • Escrow
  • Stripe
  • PayPal
  • Razorpay
  • USDT

These options are no longer relevant after submission.


3. Hide Action Buttons

Buttons such as:

  • Continue to Payment
  • I’ve Completed Payment

should disappear after payment proof submission.


4. Display a Confirmation Card

Instead of payment controls, buyers should see a professional confirmation message.

Example:

✓ Payment Proof Submitted

Reference:
FLIP-000001

Payment Status:
Submitted for Verification

Thank you.

Our team will review your payment shortly.

Ownership transfer will begin once payment has been verified.

5. Add “View Uploaded Proof”

Since the uploaded receipt already exists in the WordPress Media Library, buyers should be able to confirm exactly what they uploaded.

Example:

View Uploaded Receipt

This will help buyers verify that the correct document was submitted.


6. Improve Transaction Summary

The transaction table should become more informative.

Example:

FieldValue
Transaction1
Winning Bid₹55,555,609
Payment StatusSubmitted for Verification
Payment MethodManual Payment
Payment ProofUploaded ✓

7. Introduce a Timeline

A simple progress indicator makes the payment journey much easier to understand.

✓ Auction Won

✓ Manual Payment Selected

✓ Payment Proof Uploaded

⏳ Verification Pending

□ Ownership Transfer

8. Prepare for Admin Approval

This lesson also prepares the foundation for administrator workflows.

Future lessons will allow administrators to:

  • Review uploaded receipts.
  • Approve payments.
  • Reject invalid payment proofs.
  • Request new payment proof.
  • Notify buyers automatically.

Expected Outcome

After completing this lesson:

  • Buyers clearly understand their payment has been received.
  • Duplicate payment attempts are eliminated.
  • The payment page becomes cleaner and more professional.
  • The plugin is ready for administrator verification features.
  • The overall user experience aligns with real-world marketplace payment workflows.

What You Will Learn

Throughout this lesson, you will learn how to:

  • Render different interfaces based on transaction state.
  • Improve user experience using conditional rendering.
  • Present payment progress more clearly.
  • Separate buyer actions from administrator actions.
  • Design workflows that scale as new payment gateways are added.

Next Lesson Preview

Lesson 78 – Building the Administrator Payment Verification Dashboard

In the next lesson, we will begin the administrator side of the payment system by creating a dashboard where site administrators can:

  • View submitted payment proofs.
  • Open uploaded receipts directly from the Media Library.
  • Approve or reject payments.
  • Update transaction statuses.
  • Trigger the next stage of the website ownership transfer workflow.

This will complete the first full end-to-end manual payment verification process in the Flipnzee Auctions plugin.

Lesson 76: Building Secure Payment Proof Uploads for Manual Payments in the Flipnzee Auctions Plugin

In the previous lesson, the Flipnzee Auctions plugin was refactored to separate the payment page into reusable methods. With the foundation now in place, the next logical step was to allow buyers to securely upload proof of payment after completing a manual bank transfer or other offline payment.

This lesson focused on implementing a complete payment proof upload workflow using WordPress’ built-in Media Library functions while ensuring security through nonce verification and preventing duplicate uploads.


Objective

Implement a secure payment proof upload system that:

  • Allows buyers to upload payment receipts.
  • Stores uploaded files in the WordPress Media Library.
  • Saves the attachment ID in the transaction table.
  • Prevents duplicate uploads.
  • Displays appropriate confirmation messages.
  • Prepares the plugin for future admin verification.

Step 1 – Creating the Upload Section

A new upload section was added beneath the manual payment instructions.

<h3>Upload Payment Proof</h3>

<p>
After completing your payment, upload your receipt or screenshot below.
</p>

<form
    method="post"
    enctype="multipart/form-data"
>

Using multipart/form-data is essential whenever files are uploaded.


Step 2 – Protecting the Form with a WordPress Nonce

Every upload request should be protected against CSRF attacks.

wp_nonce_field(
    'flipnzee_upload_proof',
    'flipnzee_upload_nonce'
);

The nonce is later verified before processing the upload.


Step 3 – Creating the File Input

The upload field accepts common payment proof formats.

<input
    type="file"
    name="flipnzee_payment_proof"
    accept=".jpg,.jpeg,.png,.pdf"
    required
>

Supported file types include:

  • JPG
  • JPEG
  • PNG
  • PDF

Step 4 – Detecting Upload Requests

Inside the main render method, the plugin detects whether the buyer submitted a payment proof.

if (
    isset( $_POST['flipnzee_upload_payment_proof'] ) &&
    isset( $_FILES['flipnzee_payment_proof'] ) &&
    ! empty( $_FILES['flipnzee_payment_proof']['name'] )
) {

}

This ensures uploads are only processed when the upload button is pressed.


Step 5 – Verifying the Nonce

Before accepting any uploaded file, the nonce is validated.

if (
    ! isset( $_POST['flipnzee_upload_nonce'] ) ||
    ! wp_verify_nonce(
        sanitize_text_field(
            wp_unslash( $_POST['flipnzee_upload_nonce'] )
        ),
        'flipnzee_upload_proof'
    )
) {
    return '<p>Security check failed.</p>';
}

This protects the upload endpoint from forged requests.


Step 6 – Loading WordPress Upload Libraries

Instead of manually moving files, WordPress provides built-in upload helpers.

require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/media.php';
require_once ABSPATH . 'wp-admin/includes/image.php';

These libraries automatically handle:

  • Uploads
  • File validation
  • Image metadata
  • Media Library integration

Step 7 – Uploading the File

The upload is performed using WordPress’ native API.

$attachment_id = media_handle_upload(
    'flipnzee_payment_proof',
    0
);

Successful uploads immediately become Media Library attachments.


Step 8 – Saving the Attachment ID

After a successful upload, the attachment ID is saved against the transaction.

Flipnzee_Payment_Manager::save_payment_proof(
    $transaction->id,
    $attachment_id
);

This updates the transaction record with:

  • payment_proof_id
  • payment_status

Step 9 – Refreshing the Transaction

One subtle issue appeared during testing.

Although the database updated successfully, the current $transaction object still contained the old values because it had been loaded before the upload.

Refreshing the transaction solved the issue.

$transaction = Flipnzee_Payment_Manager::get_transaction(
    $transaction->id
);

This immediately reflects the latest payment information.


Step 10 – Preventing Duplicate Uploads

Instead of always displaying the upload form, the page now checks whether a payment proof already exists.

<?php if ( empty( $transaction->payment_proof_id ) ) : ?>

<!-- Upload Form -->

<?php else : ?>

<div class="notice notice-success">

    <p>

        <strong>Payment Proof Already Submitted.</strong>

        Your payment proof has already been uploaded and is awaiting verification by the Flipnzee team.

    </p>

</div>

<?php endif; ?>

This prevents accidental duplicate submissions.


Step 11 – Testing

The upload workflow was tested thoroughly.

Successful tests included:

  • Uploading PNG payment receipts.
  • Verifying files appear in the WordPress Media Library.
  • Confirming payment_proof_id is stored in the database.
  • Confirming payment_status changes to submitted.
  • Confirming duplicate uploads are prevented.
  • Confirming success messages appear after upload.

Challenges Encountered

Several issues were encountered during implementation.

Transaction Not Refreshing

Although the database updated correctly, the upload form continued appearing because the transaction object had not been refreshed after saving the payment proof.

Reloading the transaction solved this issue.


Media Library Confusion

Initially it appeared that uploads were failing because the uploaded image was not immediately visible.

The issue turned out to be Media Library filtering and caching rather than the upload itself.


Conditional Rendering

Wrapping the upload form inside a conditional block required careful placement of the opening and closing PHP tags to avoid syntax errors.

Once corrected, the page behaved exactly as expected.


What Was Achieved

By the end of this lesson, the Flipnzee Auctions plugin could:

  • Accept secure payment proof uploads.
  • Store uploaded receipts in the Media Library.
  • Save attachment IDs with transactions.
  • Prevent duplicate uploads.
  • Display confirmation messages.
  • Prepare transactions for future verification.

Lessons Learned

Several important WordPress development concepts were reinforced:

  • Always use nonces when processing forms.
  • Prefer WordPress Media APIs over custom upload code.
  • Refresh database objects after updates.
  • Use conditional rendering to improve user experience.
  • Store Media Library attachment IDs instead of file paths whenever possible.

Download Source Code

Download the starting version of the plugin before the lesson:

Download the completed version after this lesson:


Next Lesson

In Lesson 77, the payment experience will be polished further by:

  • Displaying Submitted for Verification instead of Pending.
  • Hiding payment options once proof has been uploaded.
  • Showing a cleaner buyer confirmation page.
  • Adding links to view uploaded payment proof.
  • Beginning the admin verification workflow.

This will complete the buyer-side manual payment journey and prepare the plugin for administrator approval of submitted payments.

Lesson 76: Uploading Payment Proof and Recording Buyer Payment Submission

Introduction

With the Buyer Payment Page now refactored into modular components, the payment system is ready for its next major milestone.

In previous lessons, buyers could:

  • View their transaction details
  • Select a payment gateway
  • Read manual payment instructions
  • Receive a unique payment reference number

However, after making a payment, there is still no mechanism for buyers to notify the marketplace or provide proof that the payment has been completed.

In this lesson, we will implement the Payment Proof Upload feature. Buyers will be able to upload a payment receipt or screenshot directly from the payment page, and Flipnzee will securely store the uploaded file while associating it with the transaction for later administrator review.

This marks the beginning of the complete manual payment verification workflow.


Why This Feature Is Important

Manual payments require evidence before ownership of a digital asset can be transferred.

Instead of asking buyers to send screenshots through email or messaging apps, Flipnzee will manage everything inside the marketplace.

Benefits include:

  • Centralized payment records
  • Better buyer experience
  • Easier administrator verification
  • Improved transaction tracking
  • Foundation for dispute resolution
  • Scalable payment workflow

What We Will Build

After completing this lesson, buyers will be able to:

  • Upload payment proof directly from the payment page.
  • Submit JPG, PNG, or PDF payment receipts.
  • Securely upload files using WordPress.
  • Associate uploaded proof with the transaction.
  • Receive confirmation that the proof has been submitted.
  • Prepare the transaction for administrator verification.

Learning Objectives

By the end of this lesson, you will learn how to:

  • Create secure file upload forms.
  • Handle multipart form submissions.
  • Validate uploaded files.
  • Upload files to the WordPress Media Library.
  • Store attachment IDs against marketplace transactions.
  • Use WordPress upload APIs safely.
  • Prepare transactions for manual verification.

Implementation Roadmap

Step 1

Extend the payment form to support file uploads.


Step 2

Add a Payment Proof upload section.


Step 3

Allow supported file formats:

  • JPG
  • JPEG
  • PNG
  • PDF

Step 4

Secure the upload using the existing WordPress nonce.


Step 5

Upload the file into the WordPress Media Library.


Step 6

Store the uploaded attachment ID against the payment transaction.


Step 7

Display a success confirmation to the buyer.


Step 8

Prepare the transaction for administrator verification.


Files We’ll Modify

Primary files:

includes/class-payment-page.php
includes/class-payment-manager.php

Depending on your current database schema, we may also update the transaction table to include a field for the uploaded payment proof (for example, an attachment ID or file reference).


Expected Buyer Workflow

Buyer Wins Auction
        │
        ▼
Open Payment Page
        │
        ▼
Choose Manual Payment
        │
        ▼
View Payment Instructions
        │
        ▼
Complete Bank Transfer
        │
        ▼
Upload Payment Proof
        │
        ▼
Payment Proof Stored
        │
        ▼
Awaiting Verification

Skills You’ll Learn

During this lesson, you’ll gain experience with:

  • WordPress file upload handling
  • Media Library integration
  • Secure file validation
  • Transaction file associations
  • Payment workflow design
  • Preparing data for administrator approval

Expected Outcome

By the end of Lesson 76, Flipnzee will support one of the most important features of a marketplace payment system: allowing buyers to submit proof of payment directly within the platform. This removes the need for external communication channels and creates a streamlined, auditable workflow for manual payment verification.


Coming Next

Lesson 77: Administrator Payment Verification Dashboard

In the next lesson, administrators will be able to:

  • Review uploaded payment proofs.
  • View associated transaction details.
  • Approve or reject submitted payments.
  • Update payment and transaction statuses.
  • Notify buyers of verification results.
  • Continue the website ownership transfer process.

This will complete the first end-to-end manual payment workflow in the Flipnzee Auction plugin.

Lesson 75 Implementation: Refactoring the Buyer Payment Page into Modular Components

As the Flipnzee payment system evolved, the class-payment-page.php file gradually accumulated multiple responsibilities. It was responsible for retrieving transactions, validating payment requests, rendering payment instructions, displaying transaction information, and generating the payment gateway interface.

Rather than continuing to add more features to an increasingly large method, this lesson focused on improving the internal architecture of the payment page through refactoring.

Although no new user-facing functionality was introduced, this refactoring significantly improves code readability, maintainability, and prepares the payment system for future features such as payment proof uploads, administrator verification, and live payment gateway integrations.


Why Refactor?

One of the most common problems in software development is allowing a single function to become too large.

Our original render() method was responsible for:

  • Loading transactions
  • Validating requests
  • Processing payment gateway selection
  • Rendering manual payment instructions
  • Displaying transaction information
  • Displaying the payment gateway selector

Instead of adding even more functionality to this method, we separated the interface into reusable helper methods.


Step 1 – Extract the Transaction Summary

The payment summary table was moved into its own private method.

Instead of embedding the HTML directly inside render(), we created:

private static function render_transaction_summary( $transaction ) {
?>

<h2>Payment</h2>

<table class="widefat striped">

<tr>
    <th>Transaction ID</th>
    <td><?php echo esc_html( $transaction->id ); ?></td>
</tr>

<tr>
    <th>Winning Bid</th>
    <td>
        <?php
        echo esc_html(
            number_format_i18n(
                $transaction->winning_bid,
                2
            )
        );
        ?>
    </td>
</tr>

<tr>
    <th>Status</th>
    <td><?php echo esc_html( ucfirst( $transaction->status ) ); ?></td>
</tr>

<tr>
    <th>Payment Status</th>
    <td><?php echo esc_html( ucfirst( $transaction->payment_status ) ); ?></td>
</tr>

<tr>
    <th>Payment Gateway</th>
    <td>
        <?php
        echo esc_html(
            Flipnzee_Payment_Manager::get_gateway_name( $transaction )
        );
        ?>
    </td>
</tr>

</table>

<?php
}

The main render method now simply calls:

self::render_transaction_summary( $transaction );

Step 2 – Extract the Gateway Selector

Next, the payment gateway selection form was moved into a dedicated helper method.

private static function render_gateway_selector( $gateways ) {
?>

<form method="post">

<?php
wp_nonce_field(
    'flipnzee_payment_action',
    'flipnzee_payment_nonce'
);
?>

<h3>Select Payment Method</h3>

<div class="flipnzee-payment-gateways">

<?php foreach ( $gateways as $gateway_id => $gateway ) : ?>

<p>

<label>

<input
    type="radio"
    name="payment_gateway"
    value="<?php echo esc_attr( $gateway_id ); ?>"
    <?php checked( $gateway['enabled'] ); ?>
    <?php disabled( ! $gateway['enabled'] ); ?>
>

<?php echo esc_html( $gateway['label'] ); ?>

<?php if ( ! $gateway['enabled'] ) : ?>

<em>(Coming Soon)</em>

<?php endif; ?>

</label>

</p>

<?php endforeach; ?>

</div>

<p class="flipnzee-payment-actions">

<button
    type="submit"
    name="flipnzee_payment_completed"
    class="button"
>
I've Completed Payment
</button>

<button
    type="submit"
    name="flipnzee_continue_payment"
    class="button button-primary"
>
Continue to Payment
</button>

</p>

</form>

<?php
}

This method now encapsulates the entire payment gateway interface.


Step 3 – Extract Manual Payment Instructions

The manual payment interface was also separated into its own method.

private static function render_manual_payment( $transaction ) {
?>

<div class="notice notice-success">

    <p><strong>Manual Payment Selected</strong></p>

    <p>Please complete your payment using the instructions below.</p>

</div>

<div class="flipnzee-manual-payment">

<h3>Payment Instructions</h3>

<p>Thank you for choosing Manual Payment.</p>

<p>Please use the transaction reference below when sending your payment.</p>

<table class="widefat striped">

<tr>
    <th>Reference Number</th>
    <td>
        <?php
        echo esc_html(
            'FLIP-' . str_pad(
                $transaction->id,
                6,
                '0',
                STR_PAD_LEFT
            )
        );
        ?>
    </td>
</tr>

<tr>
    <th>Amount</th>
    <td>
        <?php
        echo esc_html(
            number_format_i18n(
                $transaction->winning_bid,
                2
            )
        );
        ?>
    </td>
</tr>

<tr>
    <th>Status</th>
    <td>Awaiting Payment</td>
</tr>

</table>

<h4>Important</h4>

<ul>

<li>Include the reference number with your payment.</li>

<li>Keep proof of payment for verification.</li>

<li>Your transaction will be reviewed before ownership transfer.</li>

</ul>

</div>

<?php
}

Step 4 – Simplify the Gateway Router

Previously, the switch statement contained a large block of HTML for the Manual Payment gateway.

After refactoring, it became much cleaner:

switch ( $selected_gateway ) {

    case 'manual':

        self::render_manual_payment( $transaction );

        break;

    case 'escrow':
        // Escrow placeholder.
        break;

    case 'stripe':
    case 'paypal':
    case 'razorpay':
    case 'crypto':
        // Future gateways.
        break;

    default:
        ?>
        <div class="notice notice-error">
            <p>Unknown payment gateway.</p>
        </div>
        <?php
        break;
}

The routing logic now clearly expresses intent without mixing presentation and control flow.


Benefits of the Refactoring

This refactoring provides several long-term advantages:

  • Cleaner render() method
  • Smaller, focused helper methods
  • Easier debugging
  • Improved readability
  • Better separation of concerns
  • Simpler extension for future payment gateways
  • Reduced code duplication
  • Easier maintenance as the payment workflow grows

Testing

After completing the refactoring:

  • The Buyer Payment Page displayed exactly the same information as before.
  • Manual Payment instructions continued to work.
  • The transaction summary rendered correctly.
  • Payment gateway selection remained functional.
  • No user-facing functionality changed.
  • PHP syntax validation completed successfully.

This confirmed that the refactoring preserved existing behavior while improving the internal architecture.


Lessons Learned

As features accumulate, it is often beneficial to pause and improve the code structure before introducing additional functionality. Separating presentation into dedicated helper methods makes the codebase easier to navigate, simplifies future enhancements, and reduces the risk of introducing bugs when extending existing features.

This lesson also reinforced the importance of keeping rendering logic modular so that future components—such as payment proof uploads, administrator verification, and live gateway integrations—can be added with minimal impact on existing code.

Download Source Code

Download the starting version of the plugin before the lesson:

Download the completed version after this lesson:


Conclusion

Lesson 75 focused on improving the maintainability of the Buyer Payment Page through thoughtful refactoring. By extracting the transaction summary, payment gateway selector, and manual payment instructions into reusable helper methods, the payment page is now significantly cleaner and better organized. This modular architecture provides a solid foundation for the next stage of development, where buyers will be able to upload payment proof and administrators will verify completed payments before ownership transfer.

Lesson 75: Refactoring the Buyer Payment Page for Better Maintainability

Introduction

As new payment features were added in previous lessons, the class-payment-page.php file began taking on multiple responsibilities. It was loading transactions, processing form submissions, rendering payment instructions, displaying transaction summaries, and generating the payment gateway interface.

Before adding more complex features such as payment proof uploads, transaction status updates, and administrator verification, it became important to reorganize the code into smaller, reusable methods.

In this lesson, we refactor the Buyer Payment Page without changing its functionality. The goal is to improve readability, maintainability, and prepare the payment architecture for future enhancements.


Why Refactor?

Rather than allowing one method to grow indefinitely, we separate different responsibilities into dedicated helper methods.

Benefits include:

  • Cleaner code
  • Easier debugging
  • Better readability
  • Improved reusability
  • Simpler future development
  • Better alignment with object-oriented programming principles

What We Refactored

1. Transaction Summary

The payment summary table was moved into its own method:

private static function render_transaction_summary( $transaction )

This isolates all transaction display logic from the main rendering workflow.


2. Gateway Selection

The payment gateway form was extracted into:

private static function render_gateway_selector( $gateways )

This method now handles:

  • Gateway radio buttons
  • WordPress nonce
  • Payment action buttons

3. Manual Payment Instructions

The manual payment instructions were extracted into:

private static function render_manual_payment( $transaction )

This keeps all manual payment presentation in one place and makes future enhancements (payment proof upload, bank details, etc.) much easier.


4. Cleaner Main Render Method

Instead of containing hundreds of lines of mixed HTML and PHP, the main render() method now delegates responsibilities to helper methods, making the overall flow much easier to understand.


Architecture Before Refactoring

render()

├── Transaction Summary
├── Manual Payment HTML
├── Gateway Form
├── Payment Instructions
├── Form Processing
└── Validation

Architecture After Refactoring

render()
│
├── Process Request
│
├── render_manual_payment()
│
├── render_transaction_summary()
│
└── render_gateway_selector()

This modular approach makes each method easier to read, test, and extend.


Files Modified

includes/class-payment-page.php

Skills Learned

During this lesson, we practiced:

  • Refactoring legacy code
  • Separating responsibilities
  • Creating reusable helper methods
  • Improving object-oriented design
  • Preparing a codebase for future expansion

Outcome

Although this lesson did not introduce new user-facing functionality, it significantly improved the internal architecture of the payment system. The Buyer Payment Page is now modular, easier to maintain, and ready for upcoming features such as payment proof uploads, transaction status updates, administrator verification, and future payment gateway integrations.


Lesson 74 Implementation: Displaying Professional Manual Payment Instructions on the Payment Page

After completing the payment gateway selection workflow in the previous lessons, the next improvement was making the payment page more informative for buyers who choose Manual Payment.

Previously, selecting Manual Payment only displayed a simple confirmation message. In this lesson, the payment page was enhanced to show a professional payment instruction section containing a unique payment reference, payment amount, current status, and important guidance for the buyer.


What We Built

The payment page now displays a dedicated Payment Instructions section whenever the buyer selects Manual Payment.

The section includes:

  • Unique payment reference number
  • Winning bid amount
  • Current payment status
  • Important payment instructions
  • Existing transaction details remain visible below

This provides buyers with the information they need before sending payment.


Step 1 – Detect Manual Payment Selection

After validating the form submission and selected gateway, the payment page checks which payment method the buyer selected.

switch ( $selected_gateway ) {

    case 'manual':

        // Display manual payment instructions.

        break;

    default:

        // Unsupported gateway.

        break;
}

This structure prepares the plugin for adding more gateways like Escrow.com, Stripe, PayPal and USDT in future lessons.


Step 2 – Create the Manual Payment Instruction Section

Inside the Manual Payment case, a dedicated container was added.

<div class="flipnzee-manual-payment">

    <h3>Payment Instructions</h3>

    <p>
        Thank you for choosing Manual Payment.
    </p>

    <p>
        Please use the transaction reference below when sending your payment.
    </p>

</div>

This creates a clear visual separation between payment instructions and transaction information.


Step 3 – Generate a Unique Payment Reference

Instead of using only the transaction ID, a formatted payment reference was generated.

<?php

echo esc_html(

    'FLIP-' . str_pad(

        $transaction->id,

        6,

        '0',

        STR_PAD_LEFT

    )

);

?>

Example:

FLIP-000001

Using a formatted reference looks much more professional and is easier for buyers to include in payment notes.


Step 4 – Display Important Payment Information

A table was created to display the essential payment information.

<table class="widefat striped">

<tr>

    <th>Reference Number</th>

    <td>

        <?php

        echo esc_html(
            'FLIP-' . str_pad(
                $transaction->id,
                6,
                '0',
                STR_PAD_LEFT
            )
        );

        ?>

    </td>

</tr>

<tr>

    <th>Amount</th>

    <td>

        <?php

        echo esc_html(
            number_format_i18n(
                $transaction->winning_bid,
                2
            )
        );

        ?>

    </td>

</tr>

<tr>

    <th>Status</th>

    <td>

        Awaiting Payment

    </td>

</tr>

</table>

This gives buyers an organized summary before making payment.


Step 5 – Add Important Buyer Instructions

An instruction list was added below the payment summary.

<h4>Important</h4>

<ul>

    <li>
        Include the reference number with your payment.
    </li>

    <li>
        Keep proof of payment for verification.
    </li>

    <li>
        Your transaction will be reviewed before ownership transfer.
    </li>

</ul>

These reminders help reduce payment mistakes and prepare buyers for the verification process.


Final Result

After selecting Manual Payment, buyers now see:

  • Professional payment instruction heading
  • Payment reference number
  • Winning amount
  • Awaiting payment status
  • Important payment reminders
  • Original transaction details below

The payment page now feels much closer to a production-ready marketplace instead of a placeholder page.


What I Learned

This lesson demonstrated that payment pages should do much more than simply display transaction details. Buyers need clear instructions, a recognizable payment reference, and confirmation of the amount and status before making payment.

Generating a formatted reference number and presenting information in a structured table significantly improves usability and prepares the payment workflow for future enhancements.

Download Source Code

Download the starting version of the plugin before the lesson:

Download the completed version after this lesson:


What’s Next?

In Lesson 75, we will build the Payment Proof Upload feature, allowing buyers to submit proof of payment after completing a manual transfer. This will move the Flipnzee payment workflow one step closer to a complete marketplace transaction process.

Lesson 74: Manual Payment Instructions and Buyer Confirmation Workflow

Introduction

With the payment gateway routing architecture completed in the previous lessons, buyers can now securely select their preferred payment method. However, selecting Manual Payment currently only displays a placeholder message.

In this lesson, we’ll implement the first real payment workflow in Flipnzee Auctions by displaying manual payment instructions after the buyer selects the Manual Payment gateway.

Rather than integrating a live payment processor immediately, we’ll build a professional workflow that guides buyers through the payment process while preparing the plugin for future automation.


What We’ll Build

After selecting Manual Payment and clicking Continue to Payment, the buyer will see:

  • A payment confirmation notice
  • Transaction reference number
  • Amount to be paid
  • Payment instructions
  • Placeholder bank/account details
  • Buyer checklist
  • “I’ve Completed Payment” button
  • Architecture ready for payment verification in future lessons

Why This Matters

Many marketplace platforms begin with manual payments before integrating payment gateways.

This approach allows:

  • Faster marketplace launch
  • Manual verification by administrators
  • Easy transition to automated gateways later
  • Reusable payment workflow

The same workflow will later support:

  • Escrow.com
  • Stripe
  • PayPal
  • Razorpay
  • USDT Cryptocurrency

Learning Objectives

By the end of this lesson you will:

  • Display professional payment instructions
  • Generate a transaction reference for buyers
  • Show payment amount clearly
  • Build a buyer payment confirmation interface
  • Prepare the plugin for payment verification
  • Create a reusable payment workflow

Planned User Experience

Instead of seeing only:

Manual Payment selected.

The buyer will see something similar to:

Manual Payment

Transaction Reference:
FLIP-000001

Amount:
₹55,555,609.00

Payment Instructions

✓ Transfer the exact amount.

✓ Use the reference number.

✓ Keep your payment receipt.

✓ Click "I've Completed Payment" after payment.

[ I've Completed Payment ]

What We’ll Implement

Step 1

Replace the temporary success message with a real payment instruction section.


Step 2

Generate a payment reference number using the transaction ID.

Example:

FLIP-000001

Step 3

Display the winning bid amount prominently.


Step 4

Display manual payment instructions.


Step 5

Add a buyer checklist before payment.


Step 6

Add an I’ve Completed Payment button.

Initially this button will not update the database.

It simply prepares the workflow for the next lesson.


Files We’ll Modify

Primary file:

includes/class-payment-page.php

Possible future updates:

includes/class-payment-manager.php

Skills You’ll Learn

  • Building multi-step payment workflows
  • Creating reusable payment interfaces
  • Improving user experience
  • Structuring payment pages
  • Preparing for payment verification
  • Designing scalable payment architecture

Expected Result

By the end of Lesson 74, buyers will experience a much more realistic payment process instead of a placeholder message. They’ll receive clear payment instructions, a unique transaction reference, the payment amount, and a confirmation button that prepares the marketplace for the payment verification workflow introduced in the next lesson.


Coming Next

Lesson 75: Recording Buyer Payment Confirmation and Updating Transaction Status

In the next lesson, clicking I’ve Completed Payment will begin updating the transaction status (for example, to Awaiting Verification) and lay the groundwork for seller/admin payment verification.

Lesson 73 Implementation: Processing Payment Gateway Selection Securely in Flipnzee

In the previous lesson, the payment page displayed multiple payment gateways dynamically. However, clicking Continue to Payment did not actually process the buyer’s selection.

In this lesson, the payment page was enhanced to securely process the selected payment gateway using WordPress security best practices. This establishes the routing architecture that future payment integrations such as Escrow.com, Stripe, PayPal, Razorpay, and USDT Cryptocurrency will use.


What Was Implemented

The payment page now:

  • Processes the submitted payment form
  • Verifies the WordPress nonce
  • Sanitizes user input
  • Validates the selected gateway
  • Routes requests using a switch statement
  • Displays gateway-specific responses
  • Prepares the plugin for future payment integrations

This completes the payment gateway routing layer.


Step 1: Detect Form Submission

The payment page first checks whether the buyer has submitted the payment form.

if ( isset( $_POST['flipnzee_continue_payment'] ) ) {

    // Process payment

}

This ensures the processing code only runs after the buyer clicks Continue to Payment.


Step 2: Verify the WordPress Nonce

Before processing any submitted data, the request is verified using a WordPress nonce.

if (
    ! isset( $_POST['flipnzee_payment_nonce'] ) ||
    ! wp_verify_nonce(
        sanitize_text_field(
            wp_unslash( $_POST['flipnzee_payment_nonce'] )
        ),
        'flipnzee_payment_action'
    )
) {
    return '<p>Security check failed.</p>';
}

Why?

This protects the payment page from:

  • CSRF attacks
  • Forged form submissions
  • External malicious requests

Using nonces is a standard WordPress security practice.


Step 3: Sanitize the Selected Gateway

The selected payment gateway is retrieved safely.

$selected_gateway = '';

if ( isset( $_POST['payment_gateway'] ) ) {

    $selected_gateway = sanitize_text_field(
        wp_unslash( $_POST['payment_gateway'] )
    );

}

This removes unsafe input before it reaches the application logic.


Step 4: Validate the Gateway

Before routing, the submitted gateway is checked against the list of available gateways.

if ( ! isset( $gateways[ $selected_gateway ] ) ) {

    return '<p>Invalid payment gateway selected.</p>';

}

This prevents invalid or manipulated gateway values from being processed.


Step 5: Route Using a Switch Statement

The payment gateway router directs each gateway to its own processing block.

switch ( $selected_gateway ) {

    case 'manual':
        ?>
        <div class="notice notice-success">
            <p>
                Manual Payment selected.
                Payment instructions will be displayed in the next lesson.
            </p>
        </div>
        <?php
        break;

    case 'escrow':
        ?>
        <div class="notice notice-info">
            <p>
                Escrow.com integration will be available in a future release.
            </p>
        </div>
        <?php
        break;

    case 'stripe':
    case 'paypal':
    case 'razorpay':
    case 'crypto':
        ?>
        <div class="notice notice-warning">
            <p>
                This payment gateway is not yet available.
            </p>
        </div>
        <?php
        break;

    default:
        ?>
        <div class="notice notice-error">
            <p>Unknown payment gateway.</p>
        </div>
        <?php
        break;
}

This routing structure keeps each payment provider isolated, making future integrations straightforward.


Testing the Implementation

After updating the payment page:

  1. Open the buyer payment page.
  2. Select Manual Payment.
  3. Click Continue to Payment.

The page now displays:

Manual Payment selected. Payment instructions will be displayed in the next lesson.

The transaction information remains visible, confirming that the form was processed successfully.


Why This Design Matters

Instead of embedding payment logic directly into the page, a routing layer has been introduced.

This provides several advantages:

  • Cleaner code organization
  • Easier maintenance
  • Independent gateway implementations
  • Better scalability
  • Simpler testing
  • Future extensibility

When additional gateways are implemented, each will simply receive its own case inside the existing router without affecting the others.


Lessons Learned

During implementation, several improvements were made:

  • Used WordPress nonces to secure form submissions.
  • Sanitized all user-submitted values before processing.
  • Validated gateway IDs against the registered gateway list.
  • Built a centralized gateway routing mechanism.
  • Kept the payment architecture flexible for future integrations.
  • Successfully tested Manual Payment routing without affecting existing transaction data.

Current Payment Flow

Buyer Opens Payment Page
           │
           ▼
Select Payment Gateway
           │
           ▼
Continue to Payment
           │
           ▼
Verify WordPress Nonce
           │
           ▼
Sanitize User Input
           │
           ▼
Validate Gateway
           │
           ▼
Gateway Router (switch)
           │
 ┌─────────┼───────────────┐
 │         │               │
 ▼         ▼               ▼
Manual   Escrow        Future Gateways
Payment  (Coming Soon) (Stripe, PayPal,
                         Razorpay, USDT)

Download Source Code

Download the starting version of the plugin before the lesson:

Download the completed version after this lesson:


Conclusion

Lesson 73 transformed the payment page from a static gateway selector into a secure routing system capable of processing buyer selections. By combining nonce verification, input sanitization, gateway validation, and switch-based routing, Flipnzee now has a solid payment processing foundation. Future lessons can build upon this architecture to implement real payment instructions, proof-of-payment submission, and live integrations with services such as Escrow.com, Stripe, PayPal, Razorpay, and USDT Cryptocurrency.