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 113: Building the Payment Workflow Foundation

In the previous lessons, auctions could successfully determine a winner and create a transaction. However, there was still no mechanism for the buyer to complete payment or for the marketplace to track payment progress.

This lesson introduces the payment workflow foundation for Flipnzee Auctions.

Rather than integrating directly with a payment provider immediately, the plugin now establishes a flexible payment architecture capable of supporting multiple providers in future releases while already allowing manual payment submissions.


Objectives

This lesson aimed to:

  • Create a buyer payment page
  • Support multiple payment providers
  • Introduce an External Provider architecture
  • Allow manual payment submissions
  • Upload payment proof
  • Prepare the plugin for Escrow.com integration
  • Preserve compatibility with future gateways

External Provider Architecture

Instead of embedding payment provider logic directly inside the transaction manager, the plugin now introduces an independent provider layer.

Auction
    │
    ▼
Transaction
    │
    ▼
External Provider
    │
    ▼
Transfer

This separation keeps responsibilities clear.

Transactions continue to represent marketplace events, while external providers maintain information about third-party payment services.


Database Changes

Lesson 113 introduces a dedicated table for provider-specific information.

wp_flipnzee_external_providers

The table stores:

  • Transaction ID
  • Provider name
  • External reference
  • External URL
  • Provider status
  • Notes
  • Timestamps

This allows each transaction to maintain its own provider lifecycle independently of the payment record itself.


Buyer Payment Page

A new frontend payment page was implemented.

The page now:

  • Displays transaction information
  • Shows the winning bid
  • Displays payment status
  • Displays the selected payment gateway

The payment page retrieves transactions securely using the transaction ID passed through the URL.


Supported Payment Providers

The gateway selector was designed from the beginning to support multiple providers.

Current options include:

  • Escrow.com (recommended)
  • Manual Payment
  • Stripe
  • PayPal
  • Razorpay
  • Cryptocurrency (USDT)

Only Manual Payment is currently active.

The remaining gateways are intentionally displayed as “Coming Soon,” allowing the interface to remain stable while future integrations are developed.


Manual Payment Workflow

The first complete payment workflow now exists.

After selecting Manual Payment, buyers receive:

  • Payment instructions
  • Reference number
  • Amount due
  • Payment status
  • Important reminders

The workflow is intentionally simple while providing a complete end-to-end payment process.


Uploading Payment Proof

Buyers can upload payment evidence directly from the payment page.

Supported formats include:

  • JPG
  • JPEG
  • PNG
  • PDF

Uploads are handled using the standard WordPress Media Library APIs rather than creating a custom upload system.

Once uploaded, the attachment ID is stored against the transaction for later verification.


Transaction Improvements

Several improvements were made to transaction handling.

The payment page now:

  • Retrieves transactions using the correct transaction ID
  • Reloads transactions after updates
  • Displays current payment information
  • Handles missing transactions gracefully

During development, a bug caused older transactions to appear because of confusion between multiple transaction records. This was resolved by ensuring that payment pages always retrieve the exact transaction referenced in the URL.


Debugging Improvements

Lesson 113 also included several reliability improvements.

These included fixing:

  • Object versus array access errors
  • Transaction retrieval bugs
  • Payment page rendering issues
  • Upload state refresh
  • Gateway display consistency

Additional logging was temporarily introduced during development to validate the payment workflow before being cleaned up.


Why This Architecture Matters

Although only Manual Payment is currently operational, the underlying architecture was designed for long-term extensibility.

Future payment providers can now plug into the same workflow without redesigning the payment page.

This makes it possible to introduce services such as Escrow.com, Stripe, PayPal, or cryptocurrency while keeping a consistent buyer experience.


Files Added

  • includes/class-external-provider-manager.php

Major Files Updated

  • includes/class-payment-page.php
  • includes/class-payment-manager.php
  • includes/class-transaction-manager.php
  • includes/class-database.php
  • includes/class-database-migration.php
  • flipnzee-auctions.php

What Comes Next

With the payment foundation complete, the next lesson will shift from adding functionality to improving architecture.

Lesson 114 will refactor the payment page into a state-driven workflow, allowing each payment stage—Pending, Submitted, Verified, and Completed—to present only the actions relevant to that stage. This will simplify future integrations with Escrow.com, admin verification, and automated ownership transfers.


Git Tag Recommendation

lesson-113-stable

I recommend tagging this release as lesson-113-stable. It represents the first complete payment workflow in Flipnzee Auctions and establishes the architecture that future payment providers and transfer features will build upon.

Building Flipnzee Auctions – Lesson 113 (Planning) – Implementing Escrow.com Support (Part 1)


Objective

In this lesson we’ll build the foundation for external transaction management.

Instead of trying to duplicate Escrow.com’s workflow, Flipnzee Auctions will simply track that an auction has entered an external transaction process.

This makes the plugin simpler, easier to maintain, and ready for future providers.


Philosophy

The plugin is responsible for:

✅ Auction

✅ Winner

✅ Transaction Record

✅ External Provider

✅ Completion Status

The plugin is not responsible for:

❌ collecting payment

❌ holding funds

❌ inspection

❌ disputes

❌ fee calculation

❌ releasing payment

Those remain the responsibility of the external transaction provider.


New Workflow

Auction Ends
        │
        ▼
Winner Selected
        │
        ▼
Create External Transaction
        │
        ▼
Transaction In Progress
        │
        ▼
Seller Receives Confirmation
        │
        ▼
Mark Transaction Completed
        │
        ▼
Auction Completed

Notice how much cleaner this is.


Database Changes

We’ll extend the existing transaction table.

New columns:

ColumnPurpose
providerEscrow.com
external_transaction_idTransaction reference
external_transaction_urlOptional link
statusIn Progress / Completed
started_atStarted date
completed_atCompletion date
notesInternal notes

No provider-specific columns.


Statuses

Instead of many workflow states we’ll begin with four.

Pending

↓

Initiated

↓

In Progress

↓

Completed

Simple.

Reliable.

Expandable.


Provider Architecture

Instead of

Escrow Manager

we’ll build

External Transaction

↓

Provider

↓

Escrow.com

Later we can support

Escrow.com

Escrow Europe

Sedo

Afternic

Dan.com

Manual Transfer

without changing the architecture.


Administration Screen

Each transaction will eventually contain something similar to:

Auction

Website.com

Winner

[email protected]

Provider

Escrow.com

External Transaction ID

E48329844

Started

21 July 2026

Status

In Progress

Notes

Buyer funded transaction.
Waiting for completion.

[Mark Completed]

Nothing more is needed.


Why We Aren’t Tracking Every Step

A common temptation is to mirror every stage of the escrow process.

For example:

Buyer Paid

↓

Funds Verified

↓

Seller Transfers

↓

Buyer Inspection

↓

Funds Released

Although these stages are useful within Escrow.com, they are not controlled by Flipnzee Auctions.

Attempting to reproduce them inside the plugin would require manual updates, duplicate information already maintained by the escrow provider, and increase the risk of inconsistencies.

Instead, Flipnzee Auctions records only what it can reliably know:

  • when an external transaction begins
  • which provider is being used
  • the provider’s transaction reference
  • whether the transaction is still in progress or has been completed

This keeps responsibilities clearly separated between the marketplace and the external escrow service.


Future API Integration

When we eventually integrate with the Escrow.com API, this design will remain unchanged.

Instead of an administrator manually updating the transaction status, the plugin will retrieve the latest information from the provider automatically.

Because the underlying architecture is provider-independent, future integrations with additional services will require minimal changes.


What We’ll Build in This Lesson

Rather than making isolated edits throughout the plugin, we’ll implement the feature as a cohesive unit.

The implementation will include:

  • Extending the transaction database schema with provider-independent fields.
  • Enhancing the Transaction Manager to create and manage external transaction records.
  • Updating the Payment Manager to recognise external providers.
  • Adding administrator controls for recording provider information, transaction references, and notes.
  • Displaying transaction progress within the existing administration interface.
  • Preparing the codebase for future API integration without introducing provider-specific dependencies.

Expected Result

After completing this lesson, a finished auction will be able to move into an external transaction workflow.

Administrators will be able to record the transaction provider, store the provider’s reference number, monitor whether the transaction is still in progress, and mark it as completed once the provider confirms that the sale has successfully concluded.

Although the financial transaction itself remains under the supervision of the external provider, Flipnzee Auctions will maintain an accurate record of every completed marketplace sale.


Git Commit

Lesson 113

Implement external transaction tracking

• extend transaction schema
• support external transaction providers
• add transaction references
• add transaction tracking
• prepare for Escrow.com integration

Before we write the code

I also want to make one additional architectural improvement, and I believe you’ll appreciate it.

At the moment, your plugin has Payment Manager and Transaction Manager. Once we introduce external transaction tracking, those responsibilities become distinct:

  • Payment Manager → Responsible for available payment methods (Escrow.com, Stripe, Manual, etc.).
  • Transaction Manager → Responsible for recording and managing the lifecycle of a completed auction transaction.

This separation follows the Single Responsibility Principle and will make future enhancements—such as API integrations or support for multiple providers—much easier to implement. Since we’re moving quickly toward a production-ready plugin, I recommend making this distinction now rather than after additional features have been added.