Bookings
Bookings
Shared across every PremiumPress product. 6 classes in inc/Bookings.
Bookings Bookings.php
PPT — booking system service. Owns the built-in "request-to-book" flow end to end: - a custom table {prefix}ppt_bookings (dbDelta, version-gated on init), - the front-end booking card + section rendered on single listings, - a logged-in-only AJAX endpoint to create a request, - a logged-in-only AJAX endpoint for the owner to confirm/decline/cancel, - a logged-in-only AJAX endpoint for the booker to cancel/reschedule, - a live-availability endpoint (per-listing capacity per time slot), - an hourly cron that emails tiered reminders (a day out, then an hour out) and auto-completes past bookings, - plain-text email notifications (the global from-name/address is applied by Ppt\Frontend\Integrations::mailFrom/Name). Availability model: a booking has a single start (req_date + req_time). A slot is "full" when the number of active (pending + confirmed) bookings at that exact listing/date/time reaches the listing's capacity (default 1 = no double-booking). req_time is stored as a naive wall-clock string; starts_utc holds the same moment resolved through the listing's timezone (site zone by default) so the reminder cron fires at the right absolute time regardless of server zone. External providers (cal.com / Google) are embed-only and need none of the above — renderSection() just embeds the owner's scheduling page. Provider selection is resolved by Ppt\Bookings\Providers. Patterns mirror Account\Messages (table + guard), Subscribers (AJAX + JS) and Directory\Expiry (daily cron + windowed reminders).
Calendar Calendar.php
PPT — booking calendar export: "Add to calendar" for one booking, and a private auto-updating calendar feed per member ("Sync to your calendar"). Everything calendar-shaped for the built-in booking engine (Ppt\Bookings\Bookings) lives here, so the engine itself only passes rows in: - links() Google / Outlook.com / Office 365 / .ics links for one booking — used by the booking success message, the hub cards and emails; - ?ppt_ics= the single-event .ics download, keyed on the booking's own random token column so it works from an email with no login (the owner view additionally needs &key=ownerKey(token); the token alone is always the guest view); - ?ppt_cal= the member's subscription feed, keyed on a per-member secret in user meta (created lazily, reset from the hub). Calendar apps cannot sign in, so the feed carries only what that member already sees in their hub: their own bookings, and on their own listings the customer's FIRST name, party size and notes — never an email/phone. - withIcs() attaches the .ics to one email send (confirmed / rescheduled). RFC 5545: CRLF line ends, TEXT escaping, 75-octet UTF-8-safe folding, UTC times, a stable UID per booking and a SEQUENCE that only ever goes up (see sequences()). Shared engine — no profile gate beyond the one Bookings itself uses.
Checkout Checkout.php
Booking checkout — a sibling to Ppt\Payments\CheckoutFlow, Ppt_sp\Checkout and Ppt_at\Checkout (not a modification of any). Handles ONE payment kind: the single charge that secures a booking. What that charge is comes from the listing's payment mode — a flat deposit, or the service's full price (see amountFor()). The order is always raised before the guest arrives here, never at pay time, because the amount is fixed by then. Which side raises it depends on the listing's flow: - request flow : Bookings::setStatus() raises it when the owner confirms, and the guest pays to secure a booking that is already confirmed. - instant flow : Bookings::create() raises it immediately, the booking holds its slot as pending, and clearing the payment is what confirms it. An unpaid hold is reclaimed by Bookings::releaseStaleHolds(). Either way this class re-validates ownership/status and hands off to the gateway. Reuses the same shared machinery the other checkouts do: the ppt_payment_gateways registry (Ppt\Admin\Payments), the exact ppt_gateway_start/ppt_gateway_verify filter contracts, the same ppt_orders CPT (Ppt\Admin\Orders), and the same /checkout/ + /callback/ virtual pages (Ppt\Frontend\Pages). Order refs are prefixed BOOK- (vs PP- / SHOP- / AUCT-) so Pages::content() can route /callback/ to whichever class owns that order. A deposit is a single-line digital charge — no shipping, no address — so this is deliberately much smaller than the auction/shop checkouts. It does price a coupon and tax, the same way _so/_ll/Credits do, and credits the business's share of the take to the Payouts ledger on completion.
DateSearch DateSearch.php
DateSearch — the search "When" filter for the shared booking engine. The booking designs' search bars send a date (when, date, or Compass's day) and often a time, and until this class nothing read them: the "When" box was decoration. Now a date narrows the listing search to services that can take a booking then: - free — built-in calendar with opening hours and at least one slot that is not full on a requested day (at or after the requested time, if one was sent). Listed FIRST; the visitor's sort still applies within. - unknown — availability can't be checked: no online booking, an external calendar (cal.com / Google) or no opening hours set. KEPT, after the free ones — a salon that takes phone bookings still exists on Tuesday. - none — checked and closed / blackout / fully booked. HIDDEN. Accepted dates: ISO Y-m-d; today / tonight / tomorrow; this weekend / next week / this week (ranges — free on ANY day matches); weekday names; a bare day number (Compass's month grid: this month, or next if already past); other readable dates ("12 Oct"). English words and the translated "Today"/"Tomorrow"/… labels both work. Unparseable input is ignored (no filter), never an empty result. Scope (user, 2026-09-28): the Booking Theme and the Directory, whenever bookings are switched on. The Hotel Theme has its own check-in/check-out filter (_ht\SearchPage::unavailableRoomIds()) and other forks never read these params.
Providers Providers.php
PPT — booking provider resolution. Bookings are configured per listing (see Ppt\Directory\ListingEditor booking meta). This resolves the effective provider for a listing: the owner's chosen provider, but only when the site admin still allows it (master switch + the per-provider allow toggle under Settings → Calendar) and, for the external providers, only when the owner actually supplied a link. Mirrors the Maps provider resolver (Ppt\Frontend\Integrations): a single, validated choke point, filterable via ppt_booking_provider.
Services Services.php
A booking listing's services menu (Booking Theme). On the Booking Theme a listing is a BUSINESS that offers several services, each with its own name, length, price, optional category and description (owner, 2026-10-01, after the competitor teardown: "multi-service listings"). They live in the listing's existing pricing_plans meta — the old "Pricing plans" became the services menu, so there is one list for the owner to keep, and no data to migrate: a plan saved before this simply has no length of its own and takes the listing's appointment length. A listing with NO plans still has exactly one service, built from the listing itself (its title, booking_duration, booking_price) under the key 'default'. So every listing has ≥1 service and the engine never has to special-case "no services". Other profiles: only the single implicit service — their pricing plans stay a display-only price table (see Ppt\Directory\ListingPricing). Every staff member can take every service (owner, 2026-10-01 — "Yes for now"). NOT a Service (no hooks) — a static helper.