Lesson 123: Displaying External Provider Information in the Transaction Details Screen


Overview

In the previous lesson, we introduced persistent storage for external provider transactions. Every completed payment now creates a provider record containing the provider name, escrow reference, timestamps, status, and notes.

However, this information is only available by directly inspecting the database.

In this lesson, we’ll integrate the External Provider Manager with the WordPress administration interface so administrators can view provider information directly from the Transaction Details page.

This represents an important shift from building backend infrastructure to exposing meaningful operational information through the plugin’s user interface.


Why this lesson?

At the moment, an administrator managing a website sale has no immediate visibility into the external provider handling the transaction.

To answer questions such as:

  • Which provider is managing this payment?
  • What is the escrow reference?
  • Has the provider transaction been created?
  • What status is the provider reporting?
  • Were any notes recorded?

the administrator must manually inspect the database.

The goal of this lesson is to eliminate that requirement.


Objectives

By the end of this lesson we will:

  • Retrieve provider information using Flipnzee_External_Provider_Manager
  • Associate provider records with auction transactions
  • Display provider details inside the Transaction Details page
  • Gracefully handle transactions without a provider record
  • Lay the foundation for future provider actions and status synchronization

Planned Interface

The Transaction Details page will gain a new section similar to:

──────────────────────────────────────────
External Provider
──────────────────────────────────────────

Provider
Escrow.com

Reference
ESCROW-20260724010512-34

Status
Created

Started
24 Jul 2026 06:35

Completed
—

Notes
Simulated escrow transaction created.

If no provider record exists, the interface will instead display:

External Provider

No provider information is available for this transaction.

This ensures the interface remains informative without producing errors for historical transactions.


Architectural Improvements

Rather than querying the database directly from the admin screen, the page will use:

Flipnzee_External_Provider_Manager::get_provider_by_transaction()

This maintains a clear separation of responsibilities:

  • External Provider Manager retrieves provider data.
  • Admin Transaction Details focuses solely on presentation.
  • Escrow Provider remains responsible for provider creation.
  • Transaction Lifecycle Manager continues orchestrating the workflow.

This follows the object-oriented architecture established throughout the project.


Benefits

After completing this lesson:

  • Administrators can inspect provider information without leaving WordPress.
  • Transaction debugging becomes significantly easier.
  • Escrow references become immediately accessible.
  • Provider status is visible during transaction processing.
  • The UI becomes ready for future actions such as “Open Escrow Transaction”, “Refresh Provider Status”, or “Retry Provider Synchronization”.

What We’ll Build

The implementation will involve three primary steps:

  1. Retrieve provider information for the current transaction.
  2. Add a dedicated External Provider panel to the Transaction Details page.
  3. Display provider fields using WordPress admin styling and proper escaping.

No database changes are required, as the persistence layer introduced in Lesson 122 already provides everything needed.


Looking Ahead

Displaying provider information is only the first step toward a fully integrated provider management system.

Future lessons will build on this interface by allowing administrators to:

  • Synchronize provider status with external services.
  • View provider history.
  • Launch provider-specific actions.
  • Integrate with the real Escrow.com API.
  • Support multiple external payment and escrow providers through the same abstraction layer.

With provider information now visible inside the administration interface, the Flipnzee Auctions plugin moves one step closer to providing a complete transaction management experience for buying and selling websites.

Lesson 118: Connecting Payment Verification to the Ownership Transfer Workflow

In the previous lesson, the Flipnzee Auctions plugin introduced a complete payment verification workflow. Buyers can upload payment proof, administrators can review the submission, and the payment progresses through a structured lifecycle from Pending to Submitted, Verified, and finally Completed.

Although this completes the payment process, a website sale does not end when payment is received. The actual ownership transfer still needs to take place.

This lesson focuses on bridging the gap between payment management and website transfer management.


Why a Transfer Workflow?

Unlike physical products, websites consist of multiple digital assets that must be transferred individually.

A successful website sale may include:

  • Website files
  • Database
  • Domain name
  • Hosting credentials
  • Administrator accounts
  • Email accounts
  • Documentation

Completing payment simply authorizes the beginning of this process.


Current Workflow

After Lesson 117, the payment lifecycle looks like this:

Auction Won
      │
      ▼
Pending
      │
      ▼
Payment Submitted
      │
      ▼
Payment Verified
      │
      ▼
Payment Completed

While technically correct, this skips one of the most important business processes.


Introducing Ownership Transfer

Instead of ending the transaction after payment, we’ll introduce a dedicated transfer phase.

The revised workflow becomes:

Auction Won
      │
      ▼
Payment Submitted
      │
      ▼
Payment Verified
      │
      ▼
Ownership Transfer
      │
      ▼
Transaction Completed

This separates financial completion from operational completion.


The Transfer Dashboard

The Flipnzee Auctions plugin already includes a Transfer Management page.

Rather than creating another administration interface, this page will evolve into the central dashboard for tracking every ownership transfer.

Each transfer will contain multiple independent tasks.


Transfer Components

Instead of a single “Transferred” flag, the workflow will track individual stages.

For example:

Files
───────────────
Pending
In Progress
Completed
Database
────────────────
Pending
In Progress
Completed
Domain
───────────────
Pending
In Progress
Completed
Buyer Confirmation
──────────────────────
Pending
Completed

Tracking each component independently provides administrators with much greater visibility into the progress of a transaction.


Why Separate Payment and Transfer?

Although payment and ownership transfer are related, they represent different business processes.

Payment answers one question:

Has the buyer paid?

Transfer answers another:

Has the buyer actually received ownership of the website?

Separating these workflows reduces ambiguity and more accurately reflects how website acquisitions are managed.


Triggering a Transfer

Once an administrator verifies a payment, the plugin can automatically prepare the transfer process.

The simplified workflow becomes:

Payment Verified
        │
        ▼
Transfer Record Ready
        │
        ▼
Files
Database
Domain
Buyer Confirmation

Administrators no longer need to manually create transfer records.


Administrative Workflow

The administrator’s responsibilities now expand beyond payment approval.

A typical transaction becomes:

Review Payment Proof
        │
        ▼
Verify Payment
        │
        ▼
Transfer Website Files
        │
        ▼
Transfer Database
        │
        ▼
Transfer Domain
        │
        ▼
Buyer Confirms Receipt
        │
        ▼
Complete Transaction

This mirrors the practical workflow followed by agencies and marketplace operators when transferring ownership of digital assets.


Buyer Experience

The buyer also benefits from a more transparent process.

Instead of seeing only:

Payment Completed

they can eventually follow the transfer itself.

Example:

Payment Verified

Website Transfer

✓ Files

✓ Database

✓ Domain

Waiting for Buyer Confirmation

This reduces uncertainty and provides confidence that the transaction is progressing.


Foundation for Future Automation

Designing transfer management as its own workflow opens the door to future enhancements.

Potential additions include:

  • Automatic transfer record creation
  • Progress tracking
  • Email notifications
  • Buyer acknowledgements
  • Transfer checklists
  • Internal notes
  • Document uploads
  • Completion certificates

Because the transfer system is independent of payment processing, these features can be added without changing the payment workflow.


Lessons Learned

Real-world business processes often consist of multiple related workflows rather than a single sequence of events.

By separating payment verification from ownership transfer, the Flipnzee Auctions plugin becomes easier to maintain while better representing the lifecycle of a website sale.

This modular approach also keeps the codebase extensible as additional transfer features are introduced.


Conclusion

Lesson 118 marks the transition from payment management to operational ownership transfer. Instead of treating payment as the end of the transaction, the plugin now recognizes it as the beginning of the website handover process.

With a dedicated Transfer Management workflow already in place, the next lessons will focus on automating transfer creation, tracking progress across multiple transfer stages, and providing administrators and buyers with a clearer view of each transaction from payment verification through final ownership transfer.

Lesson 114 – Refactoring the Buyer Payment Page with a State-Driven Interface

One of the goals of the Flipnzee Auctions project is to continuously improve the codebase while keeping the plugin functional at every stage. Rather than adding new features immediately, this lesson focuses on improving the buyer payment experience by making the interface respond to the current payment status.

Instead of always displaying payment options regardless of the transaction state, the payment page now renders different views depending on where the buyer is in the payment process.


Project Goals

In previous lessons, the payment workflow allowed buyers to:

  • View transaction details
  • Choose a payment gateway
  • View manual payment instructions
  • Upload payment proof

Although functional, the payment page continued to display payment controls even after payment proof had already been submitted. This could confuse buyers and encourage duplicate submissions.

The objective of this lesson was to make the payment page aware of the payment lifecycle.


Problems with the Previous Implementation

Previously, the payment page always rendered:

  • Transaction summary
  • Gateway selector
  • Payment buttons

regardless of whether the buyer had already submitted payment proof.

This produced an interface similar to:

Transaction Summary

↓

Payment Gateway Selection

↓

Manual Payment Instructions

↓

Upload Proof

↓

Payment Gateway Selection (still visible)

The buyer could continue interacting with payment controls that were no longer relevant.


Design Objective

The payment page should automatically display information that matches the transaction’s current state.

Instead of asking the buyer what to do next, the interface should guide them naturally through the workflow.


State-Driven Rendering

A new rendering controller was introduced:

self::render_payment_state(
    $transaction,
    $gateways
);

Instead of directly rendering the gateway selector, the payment page now delegates rendering to a state-aware method.


Payment States

The renderer evaluates the current payment status.

switch ( strtolower( $transaction->payment_status ) ) {

    case 'submitted':
        ...
        break;

    case 'verified':
        ...
        break;

    case 'completed':
        ...
        break;

    default:
        ...
}

Each payment status now has its own dedicated renderer.


Pending State

Pending transactions continue using the existing payment workflow.

private static function render_pending_state(
    $transaction,
    $gateways
) {

    self::render_gateway_selector(
        $gateways
    );

}

From the buyer’s perspective, nothing changes until payment has actually been submitted.


Submitted State

After payment proof is uploaded, the page now replaces the gateway selector with a confirmation message.

Example:

Payment Submitted

Your payment proof has been received.

Our team will verify your payment before ownership transfer begins.

This prevents unnecessary duplicate uploads while reassuring the buyer that their submission has been received.


Verified State

Future lessons will allow administrators to verify payments.

Once verification occurs, buyers will see a confirmation such as:

Payment Verified

Ownership transfer has started.

No additional payment actions are displayed.


Completed State

When ownership transfer has been completed, the payment page will display a completion message instead of payment controls.

Example:

Transaction Completed

Ownership has been transferred successfully.

This provides a natural end to the purchase workflow.


Transaction Summary

The transaction summary remains available throughout every stage.

Information displayed includes:

  • Transaction ID
  • Winning Bid
  • Transaction Status
  • Payment Status
  • Selected Payment Gateway

This allows buyers to monitor the progress of their purchase without losing important transaction details.


User Experience Improvements

Before this lesson:

Payment Summary

↓

Gateway Selection

↓

Manual Payment

↓

Upload Proof

↓

Gateway Selection still visible

After this lesson:

Payment Summary

↓

Pending

↓

Gateway Selection

↓

Upload Proof

↓

Submitted

↓

Waiting for Verification

↓

Verified

↓

Ownership Transfer

↓

Completed

The payment page now behaves more like a modern checkout portal, displaying only the actions that are appropriate for the buyer’s current stage.


Architectural Benefits

Although this lesson introduced only a small visible change, it significantly improved the overall design.

Benefits include:

  • State-driven rendering
  • Reduced UI clutter
  • Clear buyer guidance
  • Easier maintenance
  • Better separation between transaction information and payment workflow
  • Foundation for future payment gateways

Lessons Learned

One important lesson during development was recognizing the difference between refactoring and rewriting.

Several attempts were made to extract large portions of the payment processing logic into separate methods. While architecturally appealing, making too many structural changes at once introduced unnecessary complexity during debugging.

The final implementation adopted a more conservative approach by refactoring only the rendering layer while preserving the existing payment processing logic. This resulted in a cleaner user interface without risking regressions in the working payment workflow.

This incremental strategy is often preferable in production software, where maintaining stability is just as important as improving code quality.


Conclusion

Lesson 114 transformed the Buyer Payment Page from a static form into a state-driven interface that responds intelligently to the payment lifecycle.

While the underlying payment processing remains unchanged, buyers now receive a clearer and more intuitive experience, and the architecture is better prepared for future enhancements such as administrator payment verification and automated ownership transfers.

In the next lesson, we will build the Admin Payment Verification Workflow, allowing administrators to approve submitted payments and advance transactions to the ownership transfer stage.

lesson-114-stable: Lesson 114: Refactor buyer payment page with state-driven rendering

Lesson 79: Auditing and Hardening the Transaction Creation Lifecycle in the Flipnzee Auctions Plugin

After successfully implementing the Payment Management system in the previous lessons, the next objective was to review the entire transaction creation workflow. During testing, some historical records revealed duplicate transactions for the same auction. Although these duplicates originated from earlier development versions of the plugin, this lesson focused on ensuring that such duplicates could never occur again.

Instead of simply assuming the issue had been resolved, the transaction creation logic was audited and strengthened by adding a final database validation before inserting a new transaction.


What We Wanted to Achieve

The transaction system should always follow these rules:

  • A listing can have multiple auctions over time.
  • Every auction should have only one winner.
  • Every auction should generate only one transaction.
  • Repeated callbacks or cron executions must never create duplicate transaction records.

Investigating the Transaction Lifecycle

The first step was to locate where transactions were actually inserted into the database.

Using Visual Studio Code’s global search, all $wpdb->insert() calls were reviewed.

Several insert operations were found:

  • Auction creation
  • Bid creation
  • Transaction creation

The transaction insertion code was located inside:

includes/class-transaction-manager.php

The original code directly inserted a new transaction without checking whether one already existed for the same auction.

$result = $wpdb->insert(
    $table,
    array(
        'auction_id'  => $data['auction_id'],
        'listing_id'  => $data['listing_id'],
        'seller_id'   => $data['seller_id'],
        'buyer_id'    => $data['buyer_id'],
        'winning_bid' => $data['winning_bid'],
        'status'      => 'pending',
    ),
    array(
        '%d',
        '%d',
        '%d',
        '%d',
        '%f',
        '%s',
    )
);

Although this worked correctly, it would create duplicate records if the function were accidentally executed more than once.


Adding Duplicate Transaction Protection

Before performing the insert operation, a database lookup was added.

The plugin now searches for an existing transaction belonging to the current auction.

$existing_transaction = $wpdb->get_var(
    $wpdb->prepare(
        "SELECT id
         FROM {$table}
         WHERE auction_id = %d
         LIMIT 1",
        absint( $data['auction_id'] )
    )
);

if ( $existing_transaction ) {
    return (int) $existing_transaction;
}

Only when no transaction exists does the plugin continue with the insert.

This small addition makes the transaction creation process significantly more reliable.


Why This Matters

Imagine the following sequence:

Auction Ends
        │
        ▼
Winner Determined
        │
        ▼
Create Transaction

If the creation function is accidentally triggered twice—for example by a scheduled task or callback—the previous implementation would create two database records.

With the new validation:

Auction Ends
        │
        ▼
Winner Determined
        │
        ▼
Check Existing Transaction
        │
   Exists?
    │     │
   Yes    No
    │      │
Return ID  Insert Transaction

Only one transaction can ever be created for the same auction.


Understanding Idempotent Operations

One of the most important concepts introduced in this lesson is idempotency.

An idempotent function produces the same result no matter how many times it is executed.

For example:

First execution
↓

Transaction Created

Second execution
↓

Existing transaction found

↓

No duplicate inserted

This principle is widely used in payment gateways, webhooks, APIs, and marketplace systems to prevent duplicate records.


Testing the Implementation

After updating the code:

  • The plugin was validated using PHP syntax checking.
  • A fresh auction was created.
  • The auction was allowed to end automatically.
  • A winning bidder was determined.
  • The transaction was created.
  • Payment status was updated.
  • The Transactions page was reviewed.
  • phpMyAdmin was used to verify the database.

The results confirmed:

  • Only one transaction was created.
  • Payment updates continued to function correctly.
  • No duplicate transaction records appeared.
  • The transaction lifecycle remained fully functional.

Final Transaction Lifecycle

After this improvement, the workflow became:

Create Auction
        │
        ▼
Place Bids
        │
        ▼
Auction Ends
        │
        ▼
Winner Determined
        │
        ▼
Check Existing Transaction
        │
        ▼
Create One Transaction
        │
        ▼
Payment Processing

This provides a much more robust and production-ready transaction system.


Lessons Learned

Several valuable software engineering concepts were reinforced during this implementation:

  • Always audit historical issues instead of assuming they are resolved.
  • Database validation is an effective safeguard against duplicate records.
  • Critical workflows should be idempotent whenever possible.
  • Defensive programming increases reliability in real-world applications.
  • Marketplace and escrow systems benefit greatly from multiple layers of validation.

Download Source Code

Download the starting version of the plugin before the lesson:

Download the completed version after this lesson:


Conclusion

Lesson 79 focused on strengthening the transaction creation process rather than introducing new functionality. By adding a simple database existence check before inserting a transaction, the plugin now guarantees that each auction can generate only one transaction, even if the creation routine is triggered multiple times.

This enhancement makes the Flipnzee Auctions plugin more resilient and establishes a solid foundation for the upcoming escrow and ownership transfer workflow in future lessons.

Lesson 79: Auditing and Fixing the Auction Transaction Creation Lifecycle

After successfully implementing manual payment status management in Lesson 78, we noticed an unexpected behavior during testing.

Although payment management was working perfectly, new transactions were being created before an auction had actually finished. This indicated a flaw in the auction workflow rather than in the payment management system.

Before integrating Escrow.com or any payment gateway, it is essential that every auction follows a predictable lifecycle and creates only one transaction, at the correct point in the auction process.

In this lesson, we will audit the entire transaction creation workflow and ensure that transactions are generated only after an auction closes and a winner has been determined.


What We Will Build

By the end of this lesson we will:

  • Trace where transactions are created.
  • Identify every function capable of creating a transaction.
  • Prevent duplicate transaction creation.
  • Ensure transactions are created only once.
  • Verify the transaction lifecycle from auction creation to payment.

The Problem We Discovered

During testing we observed several unexpected behaviors.

  • Transactions were sometimes created immediately after an auction was created.
  • Earlier testing produced duplicate transaction records.
  • Payment management worked correctly, but the transaction lifecycle itself was inconsistent.

Although these issues were corrected temporarily during testing, the underlying workflow still needs a proper audit.


Desired Auction Workflow

A professional auction platform should always follow this sequence.

Auction Created
        │
        ▼
Accept Bids
        │
        ▼
Auction Ends
        │
        ▼
Determine Winner
        │
        ▼
Create ONE Transaction
        │
        ▼
Pending Payment
        │
        ▼
Buyer Payment Submitted
        │
        ▼
Admin Verification
        │
        ▼
Payment Approved
        │
        ▼
Escrow Started
        │
        ▼
Ownership Transfer
        │
        ▼
Auction Completed

Every completed auction should generate exactly one transaction, and that transaction should remain the single source of truth throughout the payment and ownership transfer process.


Lesson Objectives

During this lesson we will:

Step 1

Search the entire plugin for every location that inserts records into:

wp_flipnzee_transactions

Step 2

Identify every function responsible for transaction creation.

Possible examples include:

  • winner determination
  • auction closing
  • bid completion
  • scheduled cron events
  • save handlers

Step 3

Determine which function should have exclusive responsibility for creating transactions.


Step 4

Prevent duplicate transaction creation by checking whether a transaction already exists before inserting a new record.


Step 5

Verify that transaction creation occurs only after:

  • auction end time
  • winner determination
  • successful auction closure

Step 6

Perform end-to-end testing by:

  • creating a new auction
  • placing bids
  • waiting for auction completion
  • confirming exactly one transaction is created

Expected Outcome

After completing this lesson:

  • Every auction will produce only one transaction.
  • Duplicate transactions will be impossible.
  • Transactions will be created only after auction completion.
  • The plugin will have a reliable transaction lifecycle ready for payment gateway and Escrow.com integration.

Why This Matters

Payment gateways, escrow providers, and ownership transfer systems all depend on having a single, reliable transaction record.

Fixing the transaction lifecycle now will make future features significantly easier to implement and reduce the likelihood of data inconsistencies.

This lesson focuses on strengthening the core architecture of the Flipnzee Auctions plugin before moving on to advanced payment and escrow functionality.

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 72: Building the Payment Gateway Selection Interface

Objective

With the payment architecture now prepared, the next logical step is to give buyers the ability to choose how they would like to pay.

In this lesson, we will introduce a Payment Method Selection section on the Payment page. Although only a placeholder gateway exists today, the interface will be built so future gateways (Stripe, PayPal, Razorpay, Bank Transfer, Crypto, etc.) can be added with almost no changes to the frontend.

This lesson focuses entirely on UI architecture, not actual payment processing.


What We’ll Build

Instead of only showing:

Payment Gateway
Manual Payment (Coming Soon)

the payment page will display something like:

Select Payment Method

(•) Manual Payment (Coming Soon)
( ) Stripe
( ) PayPal
( ) Razorpay
( ) Cryptocurrency (USDT)

[Continue]

Only Manual Payment will be enabled.

The remaining gateways will appear disabled with a “Coming Soon” label.


Why This Lesson Matters

This is an important architectural step because:

  • separates payment UI from payment logic
  • allows new gateways without redesigning pages
  • provides a familiar checkout experience
  • keeps the plugin scalable
  • prepares for future gateway plugins

Files We’ll Modify

Existing

includes/class-payment-page.php

Existing

includes/class-payment-manager.php

(add helper function for available gateways)


New Features

1. Payment Gateway List

Create a helper such as:

Flipnzee_Payment_Manager::get_available_gateways()

which returns an array like

array(
    'manual' => array(
        'label' => 'Manual Payment',
        'enabled' => true,
    ),
    'stripe' => array(
        'label' => 'Stripe',
        'enabled' => false,
    ),
    'paypal' => array(
        'label' => 'PayPal',
        'enabled' => false,
    ),
    'razorpay' => array(
        'label' => 'Razorpay',
        'enabled' => false,
    ),
    'crypto' => array(
        'label' => 'USDT Cryptocurrency',
        'enabled' => false,
    ),
);

2. Display Gateway Choices

Show all gateways as radio buttons.

Only enabled gateways are selectable.

Disabled gateways display:

Coming Soon

3. Continue Button

Display

Continue to Payment

No payment processing yet.


4. Clean HTML Structure

Wrap the section in

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

for future styling.


User Experience

Current page:

Transaction Details

Gateway:
Manual Payment

New page:

Transaction Details

Select Payment Method

○ Stripe
○ PayPal
● Manual Payment
○ Razorpay
○ Crypto

Continue

Benefits

After this lesson the plugin will have:

  • scalable payment architecture
  • configurable gateway list
  • reusable gateway rendering
  • future-ready checkout interface
  • no dependency on a specific payment provider

What We Won’t Build Yet

To keep the project stable, we are not implementing:

  • Stripe API
  • PayPal API
  • Razorpay API
  • Crypto payments
  • Order confirmation
  • Payment verification

Those will come in later lessons.


Expected Outcome

By the end of Lesson 72, buyers will see a professional payment method selection interface with a working placeholder for Manual Payment and clearly marked future payment options, laying the foundation for integrating real payment gateways in the upcoming lessons.

Lesson 73: Capturing and Validating the Buyer’s Selected Payment Method

Objective

In the previous lesson, we introduced a dynamic payment gateway selection interface. Buyers can now see the available payment methods, but their selection is not yet processed.

In this lesson, we’ll begin building the actual checkout workflow by wrapping the gateway list inside a form, capturing the selected payment method, validating it on submission, and preparing the plugin for gateway-specific payment processing.

Although real payment gateways are still not connected, this lesson establishes the core workflow that every future payment provider will use.


Why This Lesson Matters

A payment page is only useful if it can process the buyer’s choice.

Instead of immediately integrating Stripe, PayPal, or Escrow.com APIs, we first need a common checkout workflow that:

  • accepts the selected gateway
  • validates user input
  • prevents invalid gateway selections
  • prepares the transaction for payment
  • redirects to the appropriate payment handler

Once this workflow exists, every new payment provider can plug into it.


What We’ll Build

The payment page will evolve from:

○ Escrow.com
● Manual Payment
○ Stripe
○ PayPal

[Continue (Disabled)]

into:

○ Escrow.com
● Manual Payment
○ Stripe
○ PayPal

[Continue to Payment]

When the buyer clicks the button:

  1. The selected gateway is submitted.
  2. The selection is validated.
  3. Disabled gateways cannot be submitted.
  4. Manual Payment continues to the next step.
  5. Future gateways display an informative placeholder message.

Files We’ll Modify

Existing

includes/class-payment-page.php

Existing

includes/class-payment-manager.php

Features to Implement

1. Wrap Gateway Selection Inside a Form

Convert the payment gateway section into a proper HTML form.

The form will submit the selected gateway using the POST method.


2. Enable the Continue Button

Replace the disabled placeholder button with an active submit button.

Example:

Continue to Payment

3. Capture Buyer Selection

Read the submitted gateway using:

$_POST['payment_gateway']

Sanitize the value before processing.


4. Validate the Selected Gateway

Verify that:

  • the gateway exists
  • the gateway is currently enabled

If validation fails, display a user-friendly error message.


5. Prepare Gateway Routing

Rather than processing payments directly, create routing logic similar to:

if Manual Payment
    continue to manual payment workflow

if Escrow
    placeholder

if Stripe
    placeholder

if PayPal
    placeholder

This architecture allows future lessons to implement each gateway independently.


User Experience

Current:

Choose Gateway

Manual Payment

Continue (disabled)

After Lesson 73:

Choose Gateway

Manual Payment

Continue to Payment

Upon submission:

Selected Gateway:
Manual Payment

or

Escrow.com integration is coming soon.

depending on the selected gateway.


Architecture Improvement

Before Lesson 73:

Payment Page

↓

Display Gateways

After Lesson 73:

Payment Page

↓

Capture Form

↓

Validate Gateway

↓

Route to Selected Payment Method

↓

Future Gateway Handler

This creates a reusable payment flow that every payment provider will follow.


Benefits

By the end of this lesson, Flipnzee Auctions will have:

  • Functional payment selection form
  • Gateway validation
  • Secure handling of buyer input
  • Centralized routing logic
  • Foundation for integrating Escrow.com, Stripe, PayPal, Razorpay, and cryptocurrency payments

What We Won’t Build Yet

To keep the implementation stable, we are not implementing:

  • Escrow.com API
  • Stripe Checkout
  • PayPal Checkout
  • Razorpay API
  • Cryptocurrency payments
  • Payment confirmation
  • Webhooks
  • Automatic transaction updates

Those will be introduced in future lessons after the payment workflow has been completed.


Expected Outcome

By the end of Lesson 73, the Payment page will evolve from a static gateway selection interface into the first stage of a real checkout process. Buyers will be able to submit their chosen payment method, the plugin will validate the selection securely, and the architecture will be ready to hand control to the appropriate payment gateway implementation in future lessons.

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.