8.0 KiB
8.0 KiB
Architecture
Analysis Date: 2026-05-05
Pattern Overview
WordPress plugin with layered architecture: CPT-backed data model, REST API surface, Singleton orchestrators, static utility classes.
- Entry point bootstraps a single Singleton (
Yacht_Booking) viaplugins_loaded - All public-facing state changes go through REST API (
/wp-json/yacht-booking/v1/) - Admin state changes use WordPress PRG pattern (form POST → redirect)
- External calendar sync handled by separate Integration namespaces
Class Inventory
| Class | File | Pattern | Responsibility |
|---|---|---|---|
Yacht_Booking |
includes/class-yacht-booking.php |
Singleton | Master orchestrator — wires all subsystems |
Yacht |
includes/class-yacht.php |
Static utility | yacht CPT registration + meta accessors |
Booking |
includes/class-booking.php |
Static utility | yacht_booking CPT + create() + status |
Inquiry |
includes/class-inquiry.php |
Static utility | yacht_inquiry CPT + send_emails() |
Availability |
includes/class-availability.php |
Static utility | All wp_yacht_availability table operations |
Rest_Controller |
api/class-rest-controller.php |
Extends WP_REST_Controller |
7 REST endpoints, booking orchestration |
Settings |
includes/class-settings.php |
Static utility | Typed wp_options accessors + formatting helpers |
Installer |
includes/class-installer.php |
Plain class | DB table creation + default options on activation |
Email_Templates |
includes/class-email-templates.php |
Static utility | Template storage, compilation, tag replacement |
Admin |
admin/class-admin.php |
Singleton (admin-only) | Menu, form processing, CSV export, customer emails |
Booking_List_Table |
admin/class-booking-list-table.php |
Extends WP_List_Table |
Bookings admin table |
Yacht_List_Table |
admin/class-yacht-list-table.php |
Extends WP_List_Table |
Yachts admin table |
Inquiry_List_Table |
admin/class-inquiry-list-table.php |
Extends WP_List_Table |
Inquiries admin table |
Sync_Controller |
integrations/google-calendar/class-sync-controller.php |
Singleton | GCal cron sync orchestration |
GCal_Service |
integrations/google-calendar/class-gcal-service.php |
Plain class | Google Calendar API calls |
OAuth_Handler |
integrations/google-calendar/class-oauth-handler.php |
Plain class | OAuth 2.0 token storage + refresh |
ICal_Feed |
integrations/ical/class-ical-feed.php |
Static/plain | iCal feed generation + rewrite rule |
ICal_Import |
integrations/ical/class-ical-import.php |
Static/plain | External iCal URL import + cron |
Shortcode |
frontend/class-shortcode.php |
Singleton | [yacht_calendar] shortcode |
Calendar_Widget |
frontend/class-calendar-widget.php |
Extends Elementor Widget_Base |
Elementor yacht-calendar widget |
Dependency Graph
yacht-booking-system.php
└── Yacht_Booking (Singleton)
├── Yacht (static)
├── Booking (static)
│ └── fires: yacht_booking_created
│ yacht_booking_status_changed
├── Availability (static)
├── Settings (static)
├── Email_Templates (static)
├── Rest_Controller
│ ├── Yacht, Booking, Availability, Settings, Inquiry
│ ├── Email_Templates
│ └── listens: yacht_booking_created → send_booking_notification (admin email)
├── Admin (Singleton, admin-only)
│ ├── Booking, Availability, Yacht, Settings, Email_Templates, Inquiry
│ ├── Booking_List_Table → Booking, Availability, Settings
│ ├── Yacht_List_Table, Inquiry_List_Table
│ └── listens: yacht_booking_status_changed → send_customer_notification
├── Sync_Controller (Singleton)
│ ├── GCal_Service → OAuth_Handler
│ └── writes: Availability::mark_as_blocked
├── ICal_Import → Availability::mark_as_blocked
└── ICal_Feed (feed output)
WP Hook Map
| Hook | Type | Registered by | Handler |
|---|---|---|---|
plugins_loaded (p10) |
action | bootstrap | yacht_booking_init() → Yacht_Booking::get_instance() |
init (p10) |
action | Yacht_Booking | register_post_types() |
init (p15) |
action | Yacht_Booking | register_shortcodes() |
init |
action | bootstrap | yacht_booking_load_textdomain() |
wp_enqueue_scripts |
action | Yacht_Booking | enqueue_frontend_assets() (conditional) |
admin_enqueue_scripts |
action | Yacht_Booking | enqueue_admin_assets() (conditional) |
rest_api_init |
action | Yacht_Booking | register_rest_routes() |
elementor/widgets/register |
action | Yacht_Booking | register_elementor_widgets() |
admin_init |
action | Yacht_Booking | add_custom_capabilities() |
admin_menu (p9) |
action | Admin | register_admin_menu() |
admin_init |
action | Admin | process_bulk_actions(), process_booking_actions(), process_yacht_save(), process_settings_save(), process_export_download() |
admin_notices |
action | Admin | display_admin_notices() |
yacht_booking_created |
custom action | Rest_Controller | send_booking_notification() (admin email) |
yacht_booking_status_changed |
custom action | Admin | send_customer_notification() |
before_delete_post |
action | Sync_Controller | on_booking_deleted() (GCal event delete) |
wp_ajax_yacht_booking_manual_sync |
action | Sync_Controller | ajax_manual_sync() |
yacht_booking_sync_to_gcal |
cron action | Sync_Controller | sync_booking_to_gcal() |
yacht_booking_pull_from_gcal |
cron action (hourly) | Sync_Controller | pull_from_gcal() |
yacht_booking_ical_import |
cron action (hourly) | ICal_Import | run_import() |
init |
action | ICal_Feed | add_rewrite_rules() |
template_redirect |
action | ICal_Feed | handle_feed_request() |
Key Data Flows
Booking Creation (Frontend → REST → DB)
- User picks dates on FullCalendar →
GET /availability/{yacht_id}→Availability::get_availability_calendar() - User submits form →
POST /bookingswithX-WP-Nonceheader Rest_Controller::create_booking(): nonce check →is_booking_enabled()→Availability::is_available()- Price:
count_days() × get_price_per_day() Booking::create()→ inserts CPT post + meta → firesyacht_booking_createdAvailability::mark_as_booked()→ inserts rows inwp_yacht_availability- Admin email sent via
Email_Templates; JSON response to frontend
Admin Booking Management
- Bookings list →
Booking_List_Table::prepare_items()(WP_Query) - Row action URLs: nonce-protected GET
?action=approve_booking_{id} Admin::process_booking_actions()→Booking::update_status()→ firesyacht_booking_status_changedAdmin::send_customer_notification()→ customer email- On cancel/delete:
Availability::clear_booking_availability($booking_id)deletes rows by booking_id - PRG redirect back to list
GCal Sync
- Hourly WP Cron:
pull_from_gcal()→GCal_Service→ Google API →Availability::mark_as_blocked() - On booking create: scheduled single cron
yacht_booking_sync_to_gcal→ push to GCal - OAuth token refresh:
OAuth_Handler::get_access_token()→ auto-refresh if expired
Error Handling Strategy
- REST endpoints return
WP_Errorwith HTTP status codes - Admin operations:
wp_die()on capability failure;?error=1redirect on soft errors Booking::create()returnsfalseon failure — caller checks- GCal API:
is_wp_error()check only; HTTP 4xx/5xx responses silently ignored - No exceptions used anywhere
Custom Capabilities
Added once to administrator role via Yacht_Booking::add_custom_capabilities():
yacht_booking_manage_yachtsyacht_booking_manage_bookingsyacht_booking_manage_settings