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:
- Buyer selects Manual Payment.
- Payment instructions are displayed.
- Buyer uploads proof of payment.
- The proof is stored.
- Payment status changes to Submitted.
- 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
