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

In the previous lesson, the Flipnzee Auctions plugin introduced persistent storage for external provider transactions. Whenever a payment reached the completed stage, the Escrow provider generated a provider reference and stored important information such as provider status, timestamps, and notes within a dedicated database table.

Although this information was now permanently stored, it was only accessible by inspecting the database directly.

In this lesson, that changes.

The Transaction Details page is enhanced to display external provider information directly within the WordPress administration area, giving administrators immediate visibility into the provider responsible for processing a transaction.


Why Display Provider Information?

Once a website sale enters the payment stage, the auction transaction is no longer the only entity involved.

An external provider—such as Escrow.com in our simulated implementation—maintains its own transaction lifecycle.

Administrators frequently need answers to questions such as:

  • Which provider is handling this transaction?
  • What is the provider reference number?
  • Has the provider transaction been created?
  • What is the current provider status?
  • Are there any provider notes?

Without displaying this information inside WordPress, administrators must inspect database records manually, making day-to-day transaction management unnecessarily difficult.


Bringing the Provider Layer into the User Interface

The Transaction Details screen now retrieves provider information using the External Provider Manager rather than performing direct database queries.

The page requests the provider record associated with the current transaction and displays the information in a dedicated section beneath Payment Management.

Conceptually, the flow now looks like this:

Transaction Details
        │
        ▼
External Provider Manager
        │
        ▼
Latest Provider Record
        │
        ▼
Display Provider Information

This preserves the plugin’s object-oriented architecture by separating presentation logic from data access.


Information Displayed

The new External Provider section includes:

  • Provider name
  • Provider reference
  • Current provider status
  • Started timestamp
  • Completed timestamp
  • Provider notes

A typical provider record appears as follows:

FieldExample
ProviderEscrow.com
ReferenceESCROW-20260724010512-34
StatusCreated
Started2026-07-24 06:35:12
Completed—
NotesSimulated escrow transaction created.

This allows administrators to monitor provider activity without leaving the WordPress dashboard.


Graceful Handling of Missing Provider Records

Not every transaction will necessarily have an associated provider.

For example:

  • Historical transactions created before provider persistence was introduced.
  • Transactions that have not yet reached the payment completion stage.
  • Future transactions using alternative payment methods.

Instead of generating errors or displaying incomplete information, the page now detects the absence of a provider record and displays a clear message indicating that no provider information is available.

This improves both usability and robustness.


Maintaining Separation of Responsibilities

One of the primary objectives of the refactoring effort has been reducing coupling between components.

The Transaction Details page now communicates exclusively with the Flipnzee_External_Provider_Manager.

Responsibilities are clearly divided:

  • Escrow Provider creates provider records.
  • External Provider Manager retrieves provider information.
  • Transaction Details presents the information.
  • Transaction Lifecycle Manager coordinates the overall workflow.

Each component remains responsible for a single concern, making the codebase easier to understand, maintain, and extend.


Improving Administrative Visibility

The addition of provider information significantly improves the administrative workflow.

An administrator reviewing a completed transaction can now immediately determine:

  • Which provider created the transaction.
  • The external provider reference.
  • The provider’s current status.
  • When the provider transaction started.
  • Whether additional provider information has been recorded.

This reduces reliance on database inspection while providing a clearer operational overview of website sales.


Preparing for Future Integrations

Although the current provider implementation continues to simulate Escrow.com, the user interface has now been designed with future integrations in mind.

When a live Escrow.com API is introduced, the same section can display:

  • Live provider status.
  • Escrow milestones.
  • Buyer and seller verification.
  • Payment confirmation.
  • Domain transfer progress.
  • Provider synchronization timestamps.

Because the display layer is already connected to the provider abstraction rather than the provider implementation, future integrations can be introduced with minimal changes to the administration interface.


Benefits of This Lesson

The improvements introduced in this lesson provide several practical advantages:

  • External provider information is available directly within WordPress.
  • Administrators no longer need to inspect the database for provider details.
  • The transaction management interface becomes more informative.
  • Presentation logic remains independent from database operations.
  • The architecture remains fully extensible for future payment and escrow providers.

Most importantly, the Transaction Details page now serves as a unified view of the complete website sale process, combining auction information, payment management, ownership transfer, and external provider details in a single location.


Looking Ahead

Displaying provider information is only the first step toward comprehensive provider management.

Future lessons will continue building upon this foundation by introducing:

  • Improved transaction navigation.
  • Enhanced provider user interface components.
  • Provider status synchronization.
  • External API communication.
  • Webhook processing.
  • Live Escrow.com integration.

With external provider information now visible alongside payment and ownership transfer details, the Flipnzee Auctions plugin takes another significant step toward becoming a complete transaction management platform for buying and selling websites.

https://github.com/SplendidDigital/flipnzee-auctions/releases/tag/lesson-123-stable

Lesson 122: Persisting External Provider Transactions for Future Escrow Integration

One of the goals of the Flipnzee Auctions project is to build a transaction system that can eventually integrate with multiple payment and escrow providers without requiring major architectural changes. While previous lessons introduced a simulated Escrow.com provider and an event-driven transaction lifecycle, provider information existed only temporarily during execution.

In this lesson, that changes.

Instead of simply generating a simulated escrow reference and returning it to the caller, the plugin now persists provider information in a dedicated database table. This transforms the provider layer from a simple simulation into a permanent part of the transaction history and prepares the architecture for future integration with real external services.


Why Persist Provider Information?

During a real website sale, the auction transaction is only one part of the process. Once payment is initiated through an external provider such as Escrow.com, additional information must be tracked independently of the auction itself.

Examples include:

  • External provider name
  • Provider transaction reference
  • Provider status
  • Processing timestamps
  • Notes and audit information

Without persistent storage, all of this information would be lost once the request finishes.


Existing Provider Infrastructure

Earlier lessons already introduced a dedicated database table for external providers.

This lesson focuses on using that infrastructure rather than redesigning it.

Each provider record is linked to a Flipnzee transaction while maintaining its own independent lifecycle.

This separation keeps the auction system independent from the implementation details of any individual payment provider.


Enhancing the Escrow Provider

The simulated Escrow provider has been significantly expanded.

Instead of only generating an escrow reference, it now performs a complete provider workflow:

  1. Starts the provider transaction.
  2. Generates a unique simulated escrow reference.
  3. Creates a persistent provider record.
  4. Records timestamps and status.
  5. Returns the generated reference to the transaction lifecycle.

Conceptually, the workflow now looks like this:

Payment Completed
        │
        ▼
Transaction Lifecycle Manager
        │
        ▼
Escrow Provider
        │
        ├── Generate Escrow Reference
        ├── Create Provider Record
        ├── Store Status
        ├── Store Notes
        └── Return Reference

Persistent Provider Records

Every completed payment now creates a record similar to:

FieldExample
Transaction ID34
ProviderEscrow.com
Provider ReferenceESCROW-20260724010512-34
Statuscreated
Started At2026-07-24 06:35
Completed AtNULL
NotesSimulated escrow transaction created.

Unlike previous lessons, this information now survives beyond the lifetime of the PHP request and becomes part of the permanent transaction history.


The Role of the External Provider Manager

The Flipnzee_External_Provider_Manager acts as the persistence layer between business logic and the database.

Its responsibilities include:

  • Creating provider records
  • Retrieving provider information
  • Updating provider status
  • Looking up providers by transaction
  • Removing provider records if necessary

By centralizing these operations, the Escrow provider no longer communicates directly with the database.

This follows the same architectural principle used throughout the plugin, where managers coordinate data access while providers focus on provider-specific behaviour.


Improved Logging

The provider workflow now produces much more meaningful debug output.

Typical logs now include messages such as:

FLIPNZEE ESCROW: Starting escrow transaction for transaction #34

FLIPNZEE EXTERNAL PROVIDER: create_provider() called.

FLIPNZEE EXTERNAL PROVIDER INSERT SUCCEEDED

FLIPNZEE ESCROW: Provider record #14 created.

FLIPNZEE ESCROW: Escrow reference ESCROW-20260724010512-34 created.

These logs make it considerably easier to diagnose provider-related issues during development.


Benefits of the New Architecture

Persisting provider information provides several advantages:

  • Permanent audit trail of provider activity.
  • Separation between auction transactions and external services.
  • Easier debugging through structured provider records.
  • Foundation for future status synchronization.
  • Support for multiple providers without changing the auction model.
  • Cleaner object-oriented architecture.

Most importantly, the auction plugin no longer treats provider interactions as temporary events—they are now first-class entities within the transaction system.


Looking Ahead

Although the current implementation still simulates Escrow.com, the surrounding architecture is now remarkably close to supporting a real integration.

Future lessons will build upon this foundation by:

  • Displaying provider information within the Transaction Details screen.
  • Updating provider status as transactions progress.
  • Synchronizing with external provider APIs.
  • Supporting additional payment providers using the same abstraction layer.
  • Introducing webhook-based status updates.

With persistent provider records now in place, the Flipnzee Auctions plugin has taken another important step toward becoming a production-ready digital asset marketplace capable of handling complex website sale transactions in a clean, extensible, and maintainable manner.

Lesson 121: Building an Escrow Provider Engine for Flipnzee Auctions

As the Flipnzee Auctions plugin matures, the payment workflow is becoming more structured and event-driven. In previous lessons, payment completion triggered the transaction lifecycle, and ownership transfer records were automatically created.

In this lesson, the next major component is introduced: an Escrow Provider Engine.

Although this lesson uses a simulated provider instead of connecting to a real escrow service, it establishes the architecture required for integrating providers such as Escrow.com in the future.


Why an Escrow Provider?

High-value website and domain transactions require trust between buyers and sellers.

Rather than immediately transferring funds or ownership, an escrow service acts as a trusted intermediary by:

  • Holding buyer funds securely
  • Waiting until transfer conditions are satisfied
  • Releasing funds to the seller after successful delivery

Instead of hardcoding a specific provider throughout the plugin, Flipnzee Auctions now introduces an abstraction layer dedicated to escrow providers.


Objectives

By the end of this lesson the plugin will:

  • create an escrow transaction automatically after payment completion
  • generate a unique escrow reference
  • isolate escrow logic into its own provider class
  • keep transaction lifecycle independent from any specific provider
  • prepare the plugin for future Escrow.com API integration

Creating the Escrow Provider

A new provider class was introduced:

includes/
└── class-escrow-provider.php

The provider is intentionally lightweight.

Its responsibility is simply to manage escrow-related operations without affecting the transaction manager or ownership transfer logic.

Initialization is handled through:

Flipnzee_Escrow_Provider::init();

This keeps provider-specific functionality separated from the rest of the plugin.


Simulating Escrow Creation

Rather than connecting to a live API, the provider currently generates an internal escrow reference.

Example:

ESCROW-20260723144534-33

This combines:

  • current UTC timestamp
  • transaction ID

The resulting reference behaves similarly to what an external escrow provider would return after successfully opening an escrow transaction.


Connecting Escrow to the Transaction Lifecycle

Previously, payment completion created an ownership transfer record.

The workflow has now been extended.

Payment Completed
        │
        ▼
Transaction Lifecycle
        │
        ├────────► Create Ownership Transfer
        │
        ▼
Create Escrow Transaction
        │
        ▼
Generate Escrow Reference

This means escrow creation becomes an automatic consequence of payment completion.

No administrator intervention is required.


Event-Driven Architecture

One of the biggest improvements in this lesson is reinforcing an event-driven design.

Instead of directly calling escrow code from the payment page, the plugin continues using WordPress actions.

Payment Updated
        │
        ▼
flipnzee_payment_completed
        │
        ▼
Transaction Lifecycle Manager
        │
        ├────────► Transfer Manager
        │
        └────────► Escrow Provider

This approach offers several advantages:

  • lower coupling
  • easier testing
  • simpler future extensions
  • better maintainability

Why This Design Matters

Imagine replacing the simulated provider with:

  • Escrow.com
  • Stripe Escrow (if available)
  • custom enterprise escrow
  • another regional escrow service

The transaction lifecycle would remain unchanged.

Only the provider implementation would need to change.

That separation makes the architecture considerably more flexible.


Debugging the Workflow

During implementation, extensive logging was added to verify each stage of the lifecycle.

The logs confirmed:

Payment status updated

↓

Payment completed action fired

↓

Transaction lifecycle started

↓

Ownership transfer created

↓

Escrow provider invoked

↓

Escrow reference generated

This confirmed that the entire workflow executes exactly as intended.

After validation, temporary debugging hooks were removed while retaining useful lifecycle logging for development.


Current Escrow Flow

The payment pipeline now behaves as follows:

Buyer submits payment
        │
        ▼
Administrator verifies payment
        │
        ▼
Payment Completed
        │
        ▼
Transaction Lifecycle Manager
        │
        ├────────► Ownership Transfer
        │
        └────────► Escrow Provider
                        │
                        ▼
              Escrow Reference Created

This creates a clean foundation for integrating real external services.


What We Accomplished

In this lesson we successfully:

  • created the Escrow Provider class
  • initialized the provider during plugin bootstrap
  • integrated escrow creation into the transaction lifecycle
  • generated simulated escrow references
  • maintained loose coupling through WordPress actions
  • validated the complete workflow using event-driven architecture
  • prepared the plugin for real escrow provider integration

Looking Ahead

The current provider generates simulated escrow transactions.

In the next lessons, the plugin will evolve further by storing provider information in the database, tracking escrow status, and eventually communicating with real escrow APIs.

By introducing the provider abstraction now, future integrations can be added without restructuring the payment lifecycle.

This is one of the key architectural milestones in transforming Flipnzee Auctions from a simple auction plugin into a professional platform for buying and selling websites, domains, and digital assets.

https://github.com/SplendidDigital/flipnzee-auctions/releases/tag/lesson-121-stable

Lesson 120 Implementation: Building the Transaction State Machine

Series: Building Flipnzee Auctions – From Prototype to Production
Lesson: 120 (Implementation)


Overview

In the previous lesson, we introduced the concept of a transaction state machine and explained why representing a transaction’s current state is more scalable than relying solely on events.

This implementation focuses on laying the architectural foundation for persistent transaction states.


What We Built

This lesson introduces a new class:

Flipnzee_Transaction_State_Manager

Its responsibility is to define the lifecycle of every transaction within the plugin.

Instead of scattering state strings across multiple files, all transaction states are centralized in one location.


State Constants

The following constants were added:

PAYMENT_PENDING

PAYMENT_SUBMITTED

PAYMENT_COMPLETED

FILES_TRANSFER

DATABASE_TRANSFER

DOMAIN_TRANSFER

BUYER_VERIFICATION

COMPLETED

These constants eliminate duplicated string literals and provide a single source of truth throughout the plugin.


Human-Readable Labels

A helper method was added to convert internal state identifiers into administrator-friendly labels.

Examples include:

payment_pending

↓

Payment Pending

and

database_transfer

↓

Database Transfer

This keeps presentation logic separate from business logic.


Ordered Transaction Lifecycle

The state manager now exposes the complete transaction lifecycle in a predictable order.

This makes future features—such as determining the next valid state—much easier to implement.

Rather than relying on complex conditional logic, the plugin can iterate over a centralized lifecycle definition.


Active and Terminal States

Two helper methods were introduced:

  • is_active()
  • is_terminal()

These methods allow other components to determine whether a transaction is still progressing or has reached its final destination.

This abstraction will become increasingly valuable as future terminal states (such as cancelled or refunded) are introduced.


Lifecycle Integration

The Transaction Lifecycle Manager was updated to work with the new state architecture.

When payment is completed, the lifecycle manager now:

  • recognizes the current transaction state
  • logs the state transition
  • continues creating the ownership transfer workflow

Although states are not yet fully persisted, the lifecycle manager now thinks in terms of transaction states rather than isolated events.


Database Preparation

The lesson also prepares the database for persistent transaction states through a new migration targeting version 1.4.0.

The migration introduces a dedicated state column within the transactions table.

Once applied, every transaction will permanently record its current position in the workflow.


Refactoring Existing Migrations

While extending the migration system, several improvements were made:

  • corrected logging messages
  • cleaned migration sequencing
  • prepared a dedicated migration for transaction states
  • continued following versioned database upgrades

These improvements make future schema changes easier to maintain.


Architectural Impact

Before this lesson, the transaction workflow looked like this:

Payment

↓

Transfer

↓

Completion

After Lesson 120, the architecture evolves into:

Payment

↓

Lifecycle Manager

↓

Transaction State

↓

Transfer Manager

↓

Completion

The transaction state now becomes the central reference point for every future workflow.


Why This Matters

This lesson may not introduce visible frontend changes, but it represents one of the most important architectural improvements in the project.

Upcoming features—including:

  • Escrow.com integration
  • multiple payment providers
  • automated notifications
  • buyer dashboards
  • transaction timelines
  • dispute handling

will all depend on a reliable transaction state machine.

By completing this refactoring now, future lessons can focus on business functionality instead of continually restructuring the underlying architecture.


Looking Ahead

With the state machine in place, the plugin is now ready to persist transaction states and allow external providers to react to state transitions.

The next lessons will leverage this foundation to integrate Escrow workflows, ensuring that every payment and ownership transfer follows a consistent, extensible lifecycle.

https://github.com/SplendidDigital/flipnzee-auctions/releases/tag/lesson-120-stable

Lesson 119 Implementation – Introducing Transaction Lifecycle Events in Flipnzee Auctions

In the previous lesson, the plugin gained a complete ownership transfer workflow. Although that feature worked well, the implementation revealed an architectural issue: the payment update screen was becoming responsible for triggering multiple business processes.

This lesson introduces a cleaner, more extensible architecture by adopting WordPress action hooks as lifecycle events.


Why This Change Was Needed

Originally, when an administrator marked a payment as Completed, the payment update method was expected to:

  • Update the payment status
  • Create an ownership transfer record
  • Record activity logs
  • Trigger notifications
  • Potentially communicate with Escrow.com
  • Perform any future post-payment tasks

As the plugin grows, this approach would lead to a large method that becomes increasingly difficult to maintain.

Instead, the payment module should simply announce that a payment has been completed and allow other parts of the system to respond independently.


Existing Flow

Previously, the workflow looked like this:

Admin Updates Payment
        │
        ▼
update_payment_status()
        │
        ├── Update database
        ├── Create transfer
        ├── Send notifications
        ├── Escrow processing
        └── More future code...

Every new feature would require modifying the payment update method.


New Event-Driven Flow

The payment screen now performs only its own responsibility.

Admin Updates Payment
        │
        ▼
update_payment_status()
        │
        ▼
do_action(
    'flipnzee_payment_completed'
)
        │
        ▼
Transaction Lifecycle Manager
        │
        ├── Create ownership transfer
        ├── Future email notifications
        ├── Future Escrow integration
        ├── Future analytics
        └── Future automation

This separates responsibilities while allowing the plugin to grow without constantly modifying the payment module.


Creating the Transaction Lifecycle Manager

A new class was introduced:

includes/
    class-transaction-lifecycle-manager.php

This class becomes responsible for listening to important transaction lifecycle events.

Its initial responsibilities include:

  • Registering lifecycle hooks
  • Responding to completed payments
  • Coordinating transfer creation
  • Serving as the central point for future transaction automation

Registering the Lifecycle Event

During plugin initialization, the lifecycle manager registers a listener for completed payments.

flipnzee_payment_completed

Whenever this event is fired, the lifecycle manager automatically begins the ownership transfer workflow.


Publishing the Event

Instead of directly creating transfer records, the payment update process now publishes an event:

do_action(
    'flipnzee_payment_completed',
    $transaction_id
);

The payment module no longer needs to know what happens next.

Its responsibility ends after announcing that the payment has been completed.


Responding to the Event

The lifecycle manager receives the transaction ID and performs the required business logic.

Currently, it automatically:

  • Creates an ownership transfer record (if one does not already exist)

Future versions will expand this handler to include:

  • Buyer notifications
  • Seller notifications
  • Escrow.com processing
  • CRM integrations
  • Analytics events
  • Audit logging
  • Additional automation

Benefits of Event-Driven Design

This approach offers several important advantages.

Single Responsibility

The payment module focuses exclusively on payment management.

Loose Coupling

The payment module no longer depends directly on the transfer manager.

Extensibility

New features can subscribe to lifecycle events without modifying existing code.

Easier Maintenance

Each component performs one clearly defined responsibility.

Better Testing

Lifecycle handlers can be tested independently of the payment interface.


Real-World Example

After this lesson, marking a payment as Completed automatically performs the following sequence:

Administrator
        │
        ▼
Payment Updated
        │
        ▼
Lifecycle Event Published
        │
        ▼
Transaction Lifecycle Manager
        │
        ▼
Ownership Transfer Created
        │
        ▼
Transfer appears in
Transfer Management

No additional code is required inside the payment update screen.


Result

After implementing this lesson:

  • Payment completion automatically creates ownership transfer records.
  • The payment module no longer contains transfer-specific logic.
  • A reusable lifecycle architecture is now available.
  • Future integrations can subscribe to lifecycle events without modifying existing functionality.

Looking Ahead

With lifecycle events in place, the next step is to formalize the overall transaction workflow.

Rather than treating transactions as isolated status updates, the plugin will begin managing them as a sequence of well-defined states—from auction completion through payment, ownership transfer, and final closure.

This state-based approach will provide a stronger foundation for Escrow.com integration and future automation while keeping the plugin organized as it continues to evolve.

https://github.com/SplendidDigital/flipnzee-auctions/releases/tag/lesson-119-stable

Lesson 118: Implementing an Ownership Transfer Workflow in the Flipnzee Auctions Plugin

In the previous lesson, payment verification marked the financial completion of an auction transaction. However, for website and domain sales, receiving payment is only part of the process. The actual ownership of the digital asset still needs to be transferred from the seller to the buyer.

In this lesson, we implement a dedicated ownership transfer workflow that tracks every stage of the handover process. Rather than relying on manual notes or external spreadsheets, the plugin now provides a structured transfer management system directly inside WordPress.


Why an Ownership Transfer Workflow?

Selling a website is very different from shipping a physical product. A successful transfer often involves multiple independent tasks:

  • Confirming payment
  • Delivering website files
  • Delivering the database
  • Transferring the domain
  • Receiving buyer confirmation

These steps rarely happen simultaneously, and each may require communication between both parties. A dedicated workflow makes the entire process transparent and auditable.


Designing the Transfer Lifecycle

The plugin now models ownership transfer as a sequence of stages.

Auction Ends
        │
        ▼
Payment Verified
        │
        ▼
Website Files Delivered
        │
        ▼
Database Delivered
        │
        ▼
Domain Transfer Completed
        │
        ▼
Buyer Verification
        │
        ▼
Transaction Completed

Each stage can be tracked independently, allowing administrators to immediately identify where a transfer currently stands.


Creating a Dedicated Transfer Manager

Instead of embedding transfer logic throughout the plugin, a dedicated Flipnzee_Transfer_Manager class is responsible for:

  • Creating transfer records
  • Retrieving transfer information
  • Updating transfer progress
  • Calculating completion percentage
  • Determining the overall transfer status
  • Automatically completing transactions

This keeps transfer-related responsibilities isolated from payment, auction, and transaction management.


Recording Individual Transfer Stages

Each transaction stores the status of every transfer stage independently.

Current fields include:

payment_status
files_status
database_status
domain_status
buyer_status
notes

Each stage can be:

  • Pending
  • Completed

This design also makes future status values such as In Progress, Rejected, or Awaiting Buyer straightforward to introduce.


Calculating Progress Automatically

The Transfer Manager now counts completed stages and calculates transfer progress.

For example:

Completed Stages: 3
Total Stages: 5

Progress:
60%

This calculation drives both the numerical progress indicator and the visual progress bar displayed within the administration interface.


Overall Transfer Status

Rather than requiring administrators to manually determine whether a transfer is complete, the plugin now derives an overall status automatically.

Possible values include:

Pending

In Progress

Completed

This status updates automatically as individual stages are completed.


Transaction Details Integration

The Transaction Details page has become the primary workspace for managing ownership transfers.

Administrators can now:

  • Review payment information
  • View payment proof
  • Update payment status
  • Track ownership transfer
  • Update every transfer stage
  • Record transfer notes

This centralises all post-auction management into a single interface.


Transfer Progress Dashboard

A visual progress section has been added to the Transaction Details screen displaying:

  • Progress counter
  • Progress percentage
  • Progress bar
  • Overall transfer status

This provides immediate insight into the current state of every website sale.


Saving Transfer Information

Administrators can update all ownership transfer fields using a dedicated form.

The plugin stores:

  • Website file delivery
  • Database delivery
  • Domain transfer
  • Buyer confirmation
  • Administrative notes

All information is saved into the transfer table for future reference.


Automatic Transaction Completion

One of the most useful improvements introduced in this lesson is automatic transaction completion.

Once all transfer stages have been marked as completed:

Payment
✓

Website Files
✓

Database
✓

Domain
✓

Buyer Confirmation
✓

the plugin automatically updates the associated transaction status to:

Completed

This removes repetitive administrative work while ensuring transactions accurately reflect the real-world ownership transfer process.


Transfer Management Dashboard

A dedicated Transfer Management page now provides an overview of all ownership transfers.

Administrators can quickly see:

  • Transaction ID
  • Overall status
  • Progress
  • Individual stage status
  • Administrative notes
  • Direct link to transaction details

This creates a central dashboard for monitoring every website handover.


Improving Plugin Architecture

This lesson also involved refactoring several areas of the codebase.

Responsibilities are now better separated:

  • Auction Manager manages auctions.
  • Payment Manager manages payments.
  • Transaction Manager manages transactions.
  • Transfer Manager manages ownership transfer.

This clearer separation improves maintainability while making future enhancements easier to implement.


Preparing for External Providers

Although ownership transfers are currently managed manually, the new workflow establishes the foundation for integrating external providers such as Escrow.com.

Future versions can automatically update transfer progress based on provider events while continuing to use the same internal workflow.


What We Achieved

By the end of this lesson, the Flipnzee Auctions plugin now supports:

  • Dedicated ownership transfer records
  • Multi-stage transfer workflow
  • Progress calculation
  • Overall transfer status
  • Progress indicators
  • Transfer notes
  • Transaction Details integration
  • Transfer Management dashboard
  • Automatic transaction completion
  • Cleaner separation of responsibilities

Conclusion

Ownership transfer is a critical part of selling websites, domains, and other digital assets. By introducing a structured transfer workflow, the Flipnzee Auctions plugin now manages not only the auction itself but also the operational process that follows payment.

The result is a more complete marketplace solution that provides better visibility, improved administration, and a stronger foundation for future automation through external escrow and payment providers.

In the next lesson, we will begin connecting this workflow with external providers, allowing payment, escrow, and ownership transfer to operate as a unified transaction lifecycle.

https://github.com/SplendidDigital/flipnzee-auctions/releases/tag/lesson-118-stable

Lesson 117: Building the Admin Payment Verification Workflow

In the previous lesson, the buyer payment page was refactored into a clean, state-driven architecture. Buyers can now submit payment proof, and the interface automatically reflects the payment status.

However, one important piece of the workflow is still missing.

Once a buyer uploads proof of payment, an administrator needs a way to verify it before ownership transfer can begin.

In this lesson, we’ll implement the Payment Verification Workflow in the WordPress admin panel.


Where We Left Off

Our payment lifecycle currently looks like this:

Auction Won
        │
        ▼
Pending
        │
        ▼
Manual Payment
        │
        ▼
Upload Payment Proof
        │
        ▼
Submitted

At this point, the buyer has completed everything required.

The next step belongs to the administrator.


Current Problem

Although payment proofs are stored successfully, administrators cannot yet:

  • verify the payment
  • reject incorrect payment proofs
  • begin ownership transfer
  • update the buyer’s payment status

The transaction simply remains in the Submitted state.


Goal of This Lesson

We’ll extend the Admin Payments screen so administrators can manage submitted payments directly.

Each submitted transaction should display actions such as:

Verify Payment

Later lessons will add:

Reject Payment

Mark Transfer Started

Complete Transfer

New Payment Workflow

The buyer and administrator will now share responsibility for the payment lifecycle.

Buyer
──────────────

Win Auction
↓

Choose Payment Method
↓

Upload Payment Proof
↓

Submitted



Administrator
────────────────────────

Review Payment Proof
↓

Verify Payment
↓

Ownership Transfer
↓

Completed

Why Verify Instead of Mark Paid?

Payment verification represents a business decision rather than simply changing a status.

The administrator confirms that:

  • payment amount is correct
  • payment reference matches
  • uploaded proof is valid
  • payment has actually been received

Only after these checks should ownership transfer begin.


State Transition

We’ll introduce our first administrator-driven state transition.

Submitted
      │
      ▼
Verified

Later:

Verified
      │
      ▼
Completed

Because the buyer page is already state-driven, changing a single database value automatically changes the buyer experience.


Updating the Admin Payments Table

For submitted payments, we’ll add a new action button.

Example:

Transaction #27

Status:
Submitted

[ Verify Payment ]

Once clicked, the plugin will:

  • validate the request
  • verify the nonce
  • update payment status
  • refresh the admin screen

Database Changes

The database already stores the payment status.

No schema changes are required.

We’ll simply update:

payment_status

from

submitted

to

verified

This is one advantage of designing the payment system around discrete states.


Buyer Experience

The buyer does not need to perform any additional action.

Once the administrator verifies the payment, the payment page will automatically switch from:

Payment Submitted

to

Payment Verified

Ownership transfer has started.

No additional templates or pages are required.


Security Considerations

Administrative actions should always include:

  • capability checks
  • nonce verification
  • transaction validation
  • status validation

For example, only payments currently marked as Submitted should be eligible for verification.

Attempting to verify an already completed transaction should simply be ignored.


Benefits of This Design

Separating buyer actions from administrator actions keeps responsibilities clear.

Buyers can:

  • choose payment methods
  • upload payment proof
  • monitor progress

Administrators can:

  • verify payment
  • initiate ownership transfer
  • complete transactions

This separation also makes future integrations with automated gateways much easier.


What We’ll Build

By the end of this lesson, administrators will be able to:

  • view submitted payments
  • verify payments with one click
  • update the payment status
  • immediately update the buyer-facing payment page

Next Steps

Once payment verification is complete, the plugin will be ready for the next major milestone:

  • Ownership Transfer Workflow
  • Transaction Completion
  • Email Notifications
  • Additional Payment Gateways
  • Escrow.com Integration
  • Audit Logging

The payment system is gradually evolving from a simple upload form into a complete transaction management workflow that mirrors how real-world website sales are handled.

Lesson 116: Refactoring the Buyer Payment Page into a State-Driven Workflow

As the Flipnzee Auctions plugin continues to mature, the buyer payment page has evolved beyond a simple form. It now manages multiple stages of a transaction—from selecting a payment method to uploading payment proof and tracking verification status. As additional payment gateways and workflows are planned, maintaining everything inside a single method would quickly become difficult.

In this lesson, the payment page is refactored into a cleaner, state-driven architecture while preserving the existing functionality.


Why Refactor?

The original implementation mixed several responsibilities inside one method:

  • Validating the transaction
  • Handling payment gateway selection
  • Uploading payment proof
  • Displaying transaction details
  • Rendering different payment states
  • Showing payment instructions

Although functional, this structure made future enhancements increasingly difficult.

The objective was to separate these responsibilities into focused methods that each perform one task.


Design Goals

The refactoring focused on four principles:

  • Smaller, easier-to-read methods
  • Separation of business logic and presentation
  • State-driven rendering
  • A scalable foundation for future payment gateways

This approach aligns more closely with object-oriented design and WordPress coding standards.


Simplifying render()

The render() method now serves primarily as the controller for the page.

Its responsibilities are limited to:

  • Validating the request
  • Loading the transaction
  • Processing payment proof uploads
  • Delegating payment actions
  • Rendering the appropriate payment state

Instead of containing hundreds of lines of mixed logic, it now orchestrates the workflow through dedicated helper methods.


Extracting Payment Submission Logic

Payment gateway processing was moved into its own method:

private static function handle_payment_submission()

This method now handles:

  • nonce validation
  • selected gateway validation
  • gateway routing
  • unsupported gateway messaging

The result is a much cleaner entry point that will make future integrations significantly easier.


Introducing a State Machine

Rather than scattering conditional statements throughout the page, the buyer interface now behaves like a simple state machine.

Current payment states include:

  • Pending
  • Submitted
  • Verified
  • Completed

A single controller determines which section should be displayed.

render_payment_state()

Internally it delegates to dedicated rendering methods for each state.


Dedicated Rendering Methods

Instead of one large template, each payment state now has its own renderer.

Examples include:

  • render_pending_state()
  • render_submitted_state()
  • render_verified_state()
  • render_completed_state()

Each method focuses on presenting one stage of the payment lifecycle.

This improves readability while making future UI enhancements much safer.


Payment Proof Upload

The payment proof upload process remains fully functional after the refactor.

The workflow now becomes:

  1. Buyer selects Manual Payment.
  2. Payment instructions are displayed.
  3. Buyer uploads proof of payment.
  4. The proof is stored.
  5. Payment status changes to Submitted.
  6. The buyer now sees a confirmation message instead of the upload form.

This creates a much clearer user experience while preventing duplicate uploads.


Transaction Summary

The transaction summary has also been isolated into its own renderer.

It displays:

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

Keeping this component separate makes future additions—such as payment timestamps or invoice numbers—straightforward.


Benefits of the Refactor

Compared to the previous implementation, the payment page is now:

  • Easier to read
  • Easier to debug
  • Easier to test
  • Easier to extend
  • Better aligned with object-oriented design

Future payment gateways such as Escrow.com, Stripe, PayPal, Wise, and cryptocurrency integrations can now be added with minimal impact on the rest of the codebase.


Lessons Learned

One important takeaway from this refactor is that working code is not always well-structured code.

As software grows, periodically revisiting earlier implementations helps improve maintainability without changing the user-facing behaviour.

By separating responsibilities into focused methods, the payment page becomes easier to understand today while reducing technical debt for future development.


Current Payment Lifecycle

The buyer payment workflow now follows a clear sequence:

Auction Won
        │
        ▼
Pending Payment
        │
        ▼
Select Payment Gateway
        │
        ▼
View Payment Instructions
        │
        ▼
Upload Payment Proof
        │
        ▼
Submitted
        │
        ▼
Verified (Admin)
        │
        ▼
Ownership Transfer
        │
        ▼
Completed

Conclusion

Although this lesson introduces very few visible changes to the buyer interface, it represents an important architectural milestone for the Flipnzee Auctions plugin. The payment page has been transformed from a monolithic implementation into a modular, state-driven workflow that is easier to maintain and extend.

With this foundation in place, the next lessons can focus on the administrative side of the payment lifecycle, including payment verification, ownership transfer, transaction completion, and integration with additional payment gateways, all without requiring major structural changes to the buyer-facing code.

https://github.com/SplendidDigital/flipnzee-auctions/releases/tag/lesson-116-payment-page-refactor

Lesson 115 – Implementation: Implementing the Buy Now Auction Completion Workflow


Introduction

In the previous lesson, we outlined how the Buy Now feature should behave from a business perspective. In this implementation lesson, we transform that design into working code.

Rather than introducing a separate purchase engine, the implementation builds upon the auction infrastructure already developed throughout the project. The result is a cleaner architecture where a Buy Now purchase is simply a special case of a successful bid that immediately concludes the auction.


Step 1 – Detect Buy Now Bids

A new helper method was introduced:

Flipnzee_Bid_Manager::is_buy_now_bid()

This method retrieves the configured Buy Now price for the auction and compares it against the submitted bid amount.

If the bid is equal to or greater than the Buy Now price, the method returns true.

Keeping this logic separate makes the bid placement code easier to understand and allows future enhancements without modifying the core bidding workflow.


Step 2 – Update the Bid Handler

After a successful bid is recorded, the bid handler now performs an additional check:

$is_buy_now = Flipnzee_Bid_Manager::is_buy_now_bid(
    $auction_id,
    $bid_amount
);

For ordinary bids, execution continues exactly as before.

For Buy Now bids, the workflow branches into an immediate auction completion sequence.


Step 3 – Close the Auction

A new method was added to the Auction Manager:

Flipnzee_Auction_Manager::close_auction(
    $auction_id
);

This method:

  • updates the auction status to closed,
  • records the closing timestamp,
  • returns whether the update succeeded.

Centralising this behaviour inside the Auction Manager keeps auction state management in a single location.


Step 4 – Determine the Winner Immediately

Once the auction is closed, the existing winner determination logic is reused:

Flipnzee_Bid_Manager::determine_winner(
    $auction_id
);

No duplicate winner-selection logic is required.

The plugin simply performs the same process that would normally occur after the scheduled auction expiry.


Step 5 – Reuse Existing Hooks

Because winner determination already fires the existing action hook:

do_action(
    'flipnzee_auction_winner_determined',
    $auction_id,
    $winner
);

the following systems continue working automatically:

  • Buyer notification
  • Seller notification
  • Administrator notification
  • Transaction creation

This demonstrates one of the benefits of designing around WordPress actions rather than tightly coupled method calls.


Step 6 – Automatically Create the Transaction

The existing Transaction Manager now creates the purchase transaction immediately after the winner is determined.

This removes the delay that previously existed between auction completion and payment.

The buyer is now ready to proceed directly to the payment stage.


Step 7 – Integrate the External Provider Workflow

During implementation, the transaction workflow also creates an associated external provider record for future integrations such as Escrow.com.

This lays the foundation for supporting external payment and escrow services without altering the auction workflow itself.


Debugging the Workflow

This lesson involved significantly more debugging than implementation.

Extensive logging was added throughout the Buy Now workflow to verify each stage executed correctly.

Typical log entries included:

  • Buy Now detection
  • Auction closure
  • Winner determination
  • Notification dispatch
  • Transaction creation
  • External provider creation

These logs made it possible to isolate failures quickly and verify that each subsystem executed in the expected order.


Issues Encountered

Several issues surfaced while implementing this workflow:

  • Buy Now bids behaved like normal bids.
  • Auctions remained active after reaching the Buy Now price.
  • Winner determination was not triggered immediately.
  • Transaction creation exposed a missing class loading issue for the External Provider Manager.
  • Front-end auction state required refreshing after administrative changes because the database status remained closed until explicitly reopened.

Resolving these issues reinforced the importance of validating the complete workflow rather than assuming each individual component behaved correctly in isolation.


Final Workflow

After completing Lesson 115, the Buy Now process now follows this sequence:

Buyer submits Buy Now bid
        │
        ▼
Bid accepted
        │
        ▼
Buy Now detected
        │
        ▼
Auction closed
        │
        ▼
Winner determined
        │
        ▼
Notifications sent
        │
        ▼
Transaction created
        │
        ▼
External provider record created
        │
        ▼
Buyer proceeds to payment

Conclusion

With this lesson complete, the Flipnzee Auctions plugin now supports an end-to-end Buy Now workflow. A qualifying bid no longer waits for the auction timer to expire; instead, it immediately concludes the auction, determines the winner, creates the transaction, and launches the payment process.

This represents a major architectural milestone. The plugin has evolved from handling bids and scheduled auction endings to supporting immediate purchases through a unified auction lifecycle, providing a solid foundation for future enhancements such as escrow integrations, automated transfers, and richer post-sale workflows.

https://github.com/SplendidDigital/flipnzee-auctions/releases/tag/lesson-115-stable

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