5.2 KiB
5.2 KiB
Coding Conventions
Analysis Date: 2026-05-05
PHP Style
Standard: WordPress Coding Standards (not PSR-12).
- 1 tab indentation
array()long-form always — never[]short syntax in plugin code- Spaces inside control structure parens:
if ( $condition ),foreach ( $items as $item ) - No spaces inside function call parens:
get_post_meta( $id, '_key', true ) - Every PHP file starts with direct-access guard:
if ( ! defined( 'ABSPATH' ) ) { exit; } - File-level docblock with
@package YachtBooking
Naming
| Thing | Convention | Example |
|---|---|---|
| Classes | PascalCase (underscore for multi-word) | Rest_Controller, Yacht_Booking |
| Methods | snake_case | get_yacht_id(), mark_as_booked() |
| Variables | snake_case | $booking_id, $start_date |
| Constants | SCREAMING_SNAKE_CASE | YACHT_BOOKING_VERSION |
| Post meta keys | underscore-prefixed, namespaced | _booking_start_date, _yacht_capacity |
| WP option keys | yacht_booking_ prefix |
yacht_booking_version |
| Boolean getters | is_ / has_ prefix |
is_available(), has_yacht_calendar_widget() |
| Static getters | get_{thing}($id) |
Booking::get_customer_name($id) |
| Static updaters | update_{thing}($id, $value) |
Yacht::update_capacity($id, $v) |
Class Patterns
Singleton — for hook-registering classes (must only run once):
private static $instance = null;
public static function get_instance() {
if ( null === self::$instance ) { self::$instance = new self(); }
return self::$instance;
}
private function __construct() { /* register hooks here */ }
Used by: Yacht_Booking, Admin, Shortcode, Sync_Controller
Static utility — for pure data accessors with no instance state:
public static function get_customer_name( $booking_id ) {
return get_post_meta( $booking_id, '_booking_customer_name', true );
}
Used by: Booking, Yacht, Availability, Settings, Email_Templates
All WP hook registration goes in constructor or init_hooks() method.
Security Patterns
- Nonces in admin forms:
wp_nonce_field()on output,check_admin_referer()on submit - Nonces in REST endpoints:
X-WP-Nonceheader verified withwp_verify_nonce($header, 'wp_rest') - iCal feed: per-yacht token in
_yacht_ical_tokenmeta, compared withhash_equals() - Admin REST endpoints:
current_user_can('yacht_booking_manage_bookings') - Sanitization on input:
sanitize_text_field(),sanitize_email(),absint(),wp_kses_post() - Escaping on output:
esc_html(),esc_attr(),esc_url(),wp_kses_post() - All
$wpdbqueries: use$wpdb->prepare()— no raw SQL
WordPress Integration Patterns
- CPT registration via static
register()method called by orchestrator - Options:
add_option()(idempotent) on activation,get_option()/update_option()for runtime - Capability checks use custom caps (
yacht_booking_manage_bookings), notmanage_options - Admin form submissions: POST →
admin_inithandler →wp_safe_redirect()(PRG pattern) - Error feedback:
?error=messagequery string +admin_noticeshook display
JavaScript Style
- Pattern: IIFE
(function($) { 'use strict'; ... })(jQuery)in both JS files - Variable naming: camelCase; jQuery-wrapped objects prefixed with
$($form,$submitBtn) calendar.js: Named inner functions (initYachtCalendar,formatDate,escapeHtml); usesconst/letadmin.js: Object-literal module pattern (const YachtBookingAdmin = { init, bindEvents, handleManualSync })- Data bridge:
wp_localize_script()injectsyachtBookingData(apiUrl, nonce, bookingEnabled, i18n) andyachtBookingAdmin - Error display: Inline HTML into
.yacht-booking-response/.yacht-inquiry-responsedivs; messages fromyachtBookingData.i18n
CSS / Markup
- BEM-like kebab-case with
yacht-prefix:.yacht-calendar-wrapper,.yacht-booking-form-container - Modifier suffixes:
.yacht-calendar-view-only,.yacht-legend-swatch-past - JS state classes:
.is-active,.yacht-day-available,.yacht-day-booked - Mobile-first approach
Internationalisation
- All user-visible strings:
__(),esc_html__(),esc_attr_e()with domain'yacht-booking' - Strings with variables:
printf( esc_html__( 'Text %s', 'yacht-booking' ), esc_html( $var ) )— never concatenation - Translators hint:
/* translators: %s: yacht name */beforeprintf
Documentation
- Public/protected methods always get docblocks; private helpers sometimes omitted
- Inline block comments label logical sections:
// Get yacht title,// Save booking meta - HTML comments label template sections in Polish:
<!-- Nazwa jachtu --> - JS functions get JSDoc blocks:
/** Format date to YYYY-MM-DD */ - PHPDoc generics notation for complex types:
@return array<int, array<string, mixed>>
Error Handling
- PHP: return
falseorWP_Erroron failure - REST: return
new \WP_Error( 'code', message, array( 'status' => 4xx ) ) - No exceptions used anywhere in the plugin
- GCal API:
is_wp_error()check only — HTTP error codes are NOT checked (known gap) - Logging:
error_log()with prefixes only whenWP_DEBUG === true; nothing in production