WordPress Payment Implementation
1. Overview
This document describes the technical implementation of the event-payment-plugin-woocommerce plugin, which handles payment processing and order synchronisation with the admin-service.
2. Plugin Architecture
2.1. Trait-Based Composition
The plugin uses a trait-based architecture where EPAWooHandler is the main class that composes multiple traits:
class EPAWooHandler {
use EPAAdmin; // Settings page
use EPAConnTest; // API connectivity validation
use EPACustomEndpoint; // REST API registration
use EPAOnPaymentProcessed; // Post-purchase sync
use EPAOnStatusUpdate; // Order status changes
use EPAWooCustomTemplates; // Template overrides
use MBox_TribeEvent; // Event selector metabox
use EPAOnOrderCancel; // Cancellation handling
use EPAFallbackGuzzleConn; // HTTP fallback
}
2.2. Hook Registration
The plugin registers hooks for the complete WooCommerce order lifecycle:
| Hook | Priority | Handler |
|---|---|---|
|
99 |
|
|
10 |
|
|
10 |
|
|
10 |
|
|
10 |
|
|
10 |
|
|
10 |
|
|
10 |
|
|
10 |
|
3. REST Endpoint Implementation
3.1. Endpoint Registration
add_action('rest_api_init', function () {
register_rest_route('payment-api/v1', '/order/event/create/', [
'methods' => 'POST',
'callback' => [$this, 'handleOrderCreation'],
'permission_callback' => '__return_true'
]);
});
3.2. Payload Validation
The endpoint performs multi-layer validation:
-
API key validation - Checks payload contains valid API key
-
Payload type detection - Determines if standard event or membership
-
Required field validation - Verifies all required fields present
-
Product validation - Confirms products exist in WooCommerce
private function validatePayload($payload) {
if (empty($payload['apiKey']) ||
$payload['apiKey'] !== get_option('epa_callback_api_key')) {
return new WP_Error('unauthorized', 'Invalid API key', ['status' => 401]);
}
// Additional validation...
}
3.3. Order Creation Flow
function handleStandardEventData($payload) {
// 1. Create WooCommerce order
$order = wc_create_order(['status' => 'draft']);
// 2. Store admin order reference
$order->update_meta_data('epa_admin_portal_order_id', $payload['orderId']);
$order->update_meta_data('event_type', 'standard');
// 3. Add line items for each participant
foreach ($payload['participants'] as $participant) {
$product = wc_get_product($participant['productId']);
$itemId = $order->add_product($product, 1);
// Add participant metadata
wc_add_order_item_meta($itemId, 'Entrant ID', $participant['id']);
wc_add_order_item_meta($itemId, 'Entrant Name', $participant['name']);
// ...
}
// 4. Calculate totals
$order->set_total($payload['total'] - $payload['discount']);
$order->save();
return [
'redirectURL' => $order->get_checkout_payment_url(),
'orderNumber' => $order->get_id()
];
}
4. Status Synchronisation
4.1. API Client Integration
The plugin uses a generated PHP API client from the OpenAPI specification:
class AdminServiceClient {
private static $instance = null;
private $orderApi;
private $membershipApi;
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
public function getOrderResourceApi() {
if ($this->orderApi === null) {
$config = Configuration::getDefaultConfiguration()
->setApiKey('X-API-KEY', get_option('epa_admin_api_key'))
->setHost(get_option('epa_admin_api_url'));
$this->orderApi = new OrderResourceExApi(
new GuzzleHttp\Client(['timeout' => 15]),
$config
);
}
return $this->orderApi;
}
}
4.2. DTO Mapping
function createParticipantOrderDTO($order, $status) {
$dto = new ParticipantOrderDTO();
$dto->setId($order->get_meta('epa_admin_portal_order_id'));
$dto->setStatus($this->mapOrderStatus($order->get_status()));
$dto->setPaymentReference($order->get_id());
// Extract participant IDs from line items
$participantIds = [];
foreach ($order->get_items() as $item) {
$entrantId = wc_get_order_item_meta($item->get_id(), 'Entrant ID');
if ($entrantId) {
$participantIds[] = $entrantId;
}
}
$dto->setParticipantIds($participantIds);
return $dto;
}
5. Order Metadata Structure
5.1. Order Level
| Meta Key | Description |
|---|---|
|
Links to admin-service order |
|
Flag to prevent duplicate syncs |
|
Last API response (debugging) |
|
|
|
Event ID from admin-service |
|
Event name |
|
Event date |
6. Error Handling
6.1. Logging Strategy
if (defined('EPA_DEBUG') && EPA_DEBUG) {
$logger = wc_get_logger();
$logger->info('Order sync initiated', [
'source' => 'event-payment-api',
'order_id' => $order->get_id(),
'admin_order_id' => $adminOrderId
]);
}
Logs are written to:
-
WooCommerce logs:
wp-content/uploads/wc-logs/ -
Plugin debug log:
event-payment-plugin/debug.log
7. User Management
7.1. Auto-Creation
function createOrLinkUser($email, $order) {
$user = get_user_by('email', $email);
if (!$user) {
$userId = wp_create_user(
sanitize_email($email),
wp_generate_password(),
$email
);
$user = get_user_by('ID', $userId);
}
$order->set_customer_id($user->ID);
$order->save();
return $user;
}
8. Related Documentation
-
Payment Architecture - High-level design
-
Event Components Implementation - Shortcode details