Files
jachty.pkmp.com.pl/.paul/codebase/conventions.md
2026-05-06 00:18:37 +02:00

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-Nonce header verified with wp_verify_nonce($header, 'wp_rest')
  • iCal feed: per-yacht token in _yacht_ical_token meta, compared with hash_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 $wpdb queries: 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), not manage_options
  • Admin form submissions: POST → admin_init handler → wp_safe_redirect() (PRG pattern)
  • Error feedback: ?error=message query string + admin_notices hook 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); uses const/let
  • admin.js: Object-literal module pattern (const YachtBookingAdmin = { init, bindEvents, handleManualSync })
  • Data bridge: wp_localize_script() injects yachtBookingData (apiUrl, nonce, bookingEnabled, i18n) and yachtBookingAdmin
  • Error display: Inline HTML into .yacht-booking-response / .yacht-inquiry-response divs; messages from yachtBookingData.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 */ before printf

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 false or WP_Error on 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 when WP_DEBUG === true; nothing in production