5.6 KiB
External Integrations
Analysis Date: 2026-05-05
Google Calendar API v3
Purpose: Bidirectional sync — bookings push to Google Calendar as events; Google Calendar events pull back as availability blocks.
Implementation: Native PHP, no SDK. Uses WordPress HTTP API (wp_remote_post, wp_remote_get, wp_remote_request).
Files:
integrations/google-calendar/class-gcal-service.php— API callsintegrations/google-calendar/class-oauth-handler.php— OAuth 2.0 token managementintegrations/google-calendar/class-sync-controller.php— Cron orchestration (Singleton)
Authentication: OAuth 2.0 with offline access (refresh token).
- Auth endpoint:
https://accounts.google.com/o/oauth2/v2/auth - Token endpoint:
https://oauth2.googleapis.com/token - Scope:
https://www.googleapis.com/auth/calendar - Credentials stored in
wp_optionskeyyacht_booking_gcal_credentials - Tokens stored in
wp_optionskeyyacht_booking_gcal_tokens - Calendar ID stored in
yacht_booking_gcal_calendar_id(defaults to'primary') - OAuth redirect URI hardcoded:
https://jachty.pagedev.pl/wp-admin/admin.php?page=yacht-bookings-settings&tab=google-calendar&gcal_callback=1
Outbound API calls:
| Method | URL | Purpose |
|---|---|---|
| POST | .../calendars/{id}/events |
Create event |
| PATCH | .../calendars/{id}/events/{eventId} |
Update event |
| DELETE | .../calendars/{id}/events/{eventId} |
Delete event |
| GET | .../calendars/{id}/events |
List events (pull sync) |
| GET | .../users/me/calendarList |
List calendars |
| POST | https://oauth2.googleapis.com/token |
Token exchange/refresh |
| GET | https://www.googleapis.com/oauth2/v2/userinfo |
Get connected email |
Sync model: Pull-only for external → local (hourly WP Cron yacht_booking_pull_from_gcal). Push for local → GCal on yacht_booking_created / yacht_booking_status_changed (scheduled single cron events).
Limitations:
- Single shared calendar for all yachts — GCal events apply to every yacht, not per-yacht
- No incoming webhooks — polling model only
- No retry logic on API failure
iCal Integration
Export (Feed)
Purpose: Generate .ics file per yacht for subscription by external clients (other booking systems, personal calendars).
File: integrations/ical/class-ical-feed.php
URL pattern: {home_url}/yacht-ical/{yacht_id}/{token}.ics
- Token stored in
_yacht_ical_tokenpost meta (24-char alphanumeric, auto-generated) - Verified with
hash_equals()— timing-safe - Returns
text/calendarwith all non-cancelled bookings for that yacht - Regenerate token:
ICal_Feed::regenerate_token($yacht_id)
Import (Subscribe)
Purpose: Subscribe to external iCal URLs per yacht; import events as availability blocks (hourly cron).
File: integrations/ical/class-ical-import.php
Config: Per-yacht _yacht_ical_import_url post meta (set via ICal_Import::set_import_url())
Behavior: Fetches URL via wp_remote_get() (30-second timeout, SSL verification), parses VEVENT components, creates yacht_booking posts with _booking_source = 'ical_import', marks dates as blocked via Availability::mark_as_blocked().
Limitation: Does not check VEVENT STATUS property — cancelled events in the feed are imported as blocks.
jsDelivr CDN
Purpose: FullCalendar library loaded from CDN (no local copy).
| Asset | URL |
|---|---|
| FullCalendar JS | https://cdn.jsdelivr.net/npm/fullcalendar@6.1.10/index.global.min.js |
| FullCalendar CSS | https://cdn.jsdelivr.net/npm/fullcalendar@6.1.10/index.global.min.css |
| Polish locale | https://cdn.jsdelivr.net/npm/@fullcalendar/core@6.1.10/locales/pl.global.min.js |
Enqueued in Yacht_Booking::enqueue_frontend_assets(), conditional on page content.
Provider: WordPress wp_mail() only — no Mailgun, SendGrid, or other transactional service.
Templates: includes/class-email-templates.php — templates stored in wp_options as tagged strings, compiled with get_booking_template_data().
When sent:
- On booking creation: admin notification via
Rest_Controller::send_booking_notification()(hooked onyacht_booking_created) - On status change: customer notification via
Admin::send_customer_notification()(hooked onyacht_booking_status_changed) - On inquiry create: admin + customer emails via
Inquiry::send_emails()(built inline, not using Email_Templates)
Headers: From: pulled from yacht_booking_email_from option; Reply-To: set explicitly.
REST API (Internal)
Namespace: yacht-booking/v1 — base: /wp-json/yacht-booking/v1/
| Method | Endpoint | Auth | Handler |
|---|---|---|---|
| GET | /yachts |
Public | get_yachts() |
| GET | /yachts/{id} |
Public | get_yacht() |
| GET | /availability/{yacht_id}?start=Y-m-d&end=Y-m-d |
Public | get_availability() |
| POST | /bookings |
Public + X-WP-Nonce |
create_booking() |
| POST | /inquiries |
Public + X-WP-Nonce |
create_inquiry() |
| GET | /bookings |
Admin cap | get_bookings() |
| PUT | /bookings/{id}/status |
Admin cap | update_booking_status() |
All registered in api/class-rest-controller.php.
Monitoring & Observability
- No error tracking service (no Sentry, Bugsnag)
error_log()used with prefixes:[Yacht Booking - GCal],[Yacht Booking - GCal Sync],[Yacht Booking - iCal]- Logging only fires when
WP_DEBUG === true— silent in production
Deployment
- Method: FTP via VS Code ftp-kr extension (
.vscode/ftp-kr.json) - CI/CD: None — fully manual
- Production URL:
https://jachty.pagedev.pl(hardcoded in GCal OAuth redirect)