WooCommerce integration
Templates
Two templates draw the shop part. Copy one into your theme to change it (a child theme is looked
at first); the plugin’s own is used when there is no copy.
| Template | Theme path | Used for |
|---|---|---|
picker.php | yourtheme/baza-booking-calendar/woocommerce/picker.php | the date/time picker on a booking product’s page |
cart-summary.php | yourtheme/baza-booking-calendar/woocommerce/cart-summary.php | what is booked, under a line of the classic cart and checkout |
Each template receives its data as $args (documented at the top of the file). The path can also be
changed with apply_filters( 'baza_bc_woocommerce_template', $file, $name, $args ).
The picker’s skeleton
The script (modules/woocommerce/assets/woo-picker.js) looks up its places by data-bbc-role and
stops with a console error when one is missing. Required roles:
prev, next, title, grid, slots, extras, total, book, note
Tags, classes, order and anything you add around them are yours. The rows the script draws inside
the roles carry fixed classes you can style: bbc-woo-picker__day (with .is-picked),__slot (.is-picked), __time, __price, __extra, __extras-toggle, __qty, __step,__veil (the loading overlay, blockUI blockOverlay).
CSS variables on .bbc-woo-picker (the script sets the first four from the theme’s own
Add to cart button): --bbc-woo-accent, --bbc-woo-on-accent, --bbc-woo-radius,--bbc-woo-ink, --bbc-woo-gap.
The block cart
The Cart and Checkout blocks (and the mini cart) flatten a line’s details to plain text, so the
summary template is not used there: a line gets one row per day and per extra instead. Change those
rows with the baza_bc_woocommerce_item_rows filter.
Filters and actions
| Hook | Purpose |
|---|---|
baza_bc_woocommerce_template (filter) | Path of a template: ( $file, $name, $args ). |
baza_bc_woocommerce_summary_data (filter) | What the cart summary is made of: ( array $data { days, extras }, array $input ). |
baza_bc_woocommerce_item_rows (filter) | Plain rows of a line (block cart, mini cart, order line): ( array $rows { key, value }, array $input ). |
baza_bc_woocommerce_product_dates (action) | Fired on a booking product’s page where the picker is drawn; ( WC_Product $product ). Draw your own picker here instead (remove the plugin’s with remove_action( ..., [ 'BazaBookingCalendar\BBC_Woo_Cart', 'render_calendar' ] )). |
baza_bc_woocommerce_offline_methods (filter) | Gateway ids that mean “pays later”: default bacs, cheque, cod. |
baza_bc_woocommerce_paid_on_completion (filter) | Gateway ids whose order is paid only when completed (processing is not money): default cod. |
baza_bc_woocommerce_send_shop_emails (filter) | true to send the shop’s own customer emails for booking orders (off by default). |
baza_bc_price_journal_recorded (action) | A price change was written: ( $booking_id, array $entry ). |
baza_bc_internal_booking_meta_prefixes (filter) | Meta key prefixes hidden from the booking panel, letters and calendar events (default bbc_, woo_; keys starting with _ are always hidden). |
What happens, in code
- Product page.
BBC_Woo_Cart::render_calendar()enqueues the picker and printsviews/picker.php. The picker asks the server (publicadmin-ajax.phpactions, no nonce – read-only except the last, which is what a shop’s own add-to-cart link does):
bbc_woo_days(product,month=YYYY-MM) – days with something free;bbc_woo_slots(product,date) – that day’s free hours with prices;bbc_woo_extras(product) – the additional services of the service;bbc_woo_quote(product,slots[],extras[id]=qty) – the total;bbc_woo_add(same) – into the cart.
- Pricing. Always the server’s:
BBC_Booking_Create::create( $input, [ 'quote' => true ] )runs the checks andBBC_Booking_Calculate, and makes nothing. Only slot strings, extra ids and counts are read from the browser. - Cart line.
WC()->cart->add_to_cart()with line databbc_booking={ input, total }.woocommerce_before_calculate_totalssets the line’s price (regular price too, no sale; tax status none – the amount is final).woocommerce_check_cart_itemsasks again at the cart and checkout; a taken time is an error notice, a moved price updates the line. - Order.
woocommerce_checkout_create_orderkeeps the forms on the order (meta_bbc_inputs, not on the line).woocommerce_checkout_order_processed/woocommerce_store_api_checkout_order_processedcallBBC_Woo_Cart::create_bookings(): one booking per line throughBBC_Booking_Create::create( $form, [ 'woo_order' => true ] )(no gateway, no payment link), pending and holding its time. Order meta_bbc_booking_ids; booking metawoo_order_id. A line that cannot be made throws, which the checkout shows. - Following the order.
BBC_WooCommerce::order_status_changed(): paid -> booking booked (sourcewoocommerce_webhook); on-hold or an offline method still unpaid -> stays pending; cancelled/failed -> pending bookings rejected; refunded -> booked ones rejected. A booking rejected in the plugin cancels an unpaid order when none of its bookings is left.
Booking meta written by the shop part
All hidden from the panel by the woo_ prefix.
woo_order_id, woo_payment_method (gateway id), woo_payment_title, woo_payment_state (paid, waiting, cancelled, failed, refunded), woo_payment_offline (1 for an offline method), woo_waiting_payment (time it went on hold). A WooCommerce coupon also sets promo_sale and coupon_code.
Price journal
BBC_Price_Journal::record( $booking_id, $kind, $reason, $before, $after, $by = [] ) writes one entry (booking meta bbc_price_journal, and the activity log’s “Price changed” row). $by is [ 'type' => admin|client|shop|system, 'user' => id, 'label' => text ]; omitted, it is whoever is signed in, else the system. BBC_Price_Journal::entries( $id ) reads them.
Licence and compatibility
- Feature key
woocommerce(in every plan) opens the gateway, product type, cart and import. Order status sync is not behind it. - HPOS and the Cart/Checkout blocks are declared compatible.
- Import from WooCommerce Bookings:
BBC_Woo_Import(WooCommerce -> Import bookings). Idempotent through meta_bbc_imported_from_wc.
Internals (moved from the user article)
A booking is made by the plugin (slots, extras, discounts, taxes) and paid as a WooCommerce order.
In every plan. Settings > Payment gateway > WooCommerce (no keys: the payment methods are the shop’s).
How it runs
- The form makes the booking (pending, slot held).
baza_bc_woocommerce_pay()(includes/payments/woocommerce.php)
asksBBC_WooCommerce::create_payment()(modules/woocommerce/class-bbc-woocommerce.php) for an order. - The order has one fee line for the amount the booking decided (
baza_bc_gateway_charge()), no shop tax on it,
meta_bbc_booking_id/_bbc_order_id. The booking keepswoo_order_id. The client is sent to the order’s payment page. - The module follows the order:
| Order | Booking |
|---|---|
| processing, completed | booked, payment recorded (source woocommerce_webhook) |
| on-hold (bank transfer, cash) | stays pending, payment_url removed so the payment-window cron leaves it alone |
| cancelled, failed | pending -> rejected |
| refunded | booked -> rejected |
| booking rejected / expired | an unpaid order is cancelled |
After paying the client returns to the plugin’s own success page (merc_id), which asks the module whether the order
is paid (baza_bc_payment_verify_return) before it believes it.
Settings of the integration
- Shop currency must equal the plugin’s currency, or the gateway answers with an error.
- Balance top-ups cannot be paid this way (the gateway says so).
- The shop’s own letters to the client for these orders are off (
baza_bc_woocommerce_send_shop_emailsturns them on). - HPOS and the cart/checkout blocks are declared compatible.
The product type “Baza booking” (stage 1 of the direct integration)
A WooCommerce product of the type Baza booking sells one service of the plugin. In the product editor: type
“Baza booking”, tab Booking, field Service. The price (“From X” in the catalogue), the free times and the
extras come from the service. The catalogue button says “Select date” and opens the product page. On the page the
dates will be chosen (next stage: action baza_bc_woocommerce_product_dates); for now an editor sees a hint when
no service is chosen.
Files: modules/woocommerce/class-bbc-woo-product.php (the product class, read once WooCommerce has its own),class-bbc-woo-product-setup.php (selector, tab, field, price text, product page hook).
Next stages: the date picker on the product page and the cart line (stage 2), the cart/checkout and the booking made
from the order (stage 3), import from Woo Bookings (stage 4).
Not done yet (older notes)
- Import from Woo Bookings (products, resources, availability rules, bookings with their orders), preview and repeatable.
- Partial payment (deposit) as the order amount; money returned by a Woo refund into the plugin’s accounts.
- The booking panel showing the order and its link (the order screen already shows the booking).
- Run against a real WooCommerce: the flows were exercised against a minimal stand-in for
WC_Orderonly.
Stages 2-4 (done, needs a test on a real shop)
Product page. A product of type Baza booking shows its own compact picker
(modules/woocommerce/assets/woo-picker.*), not the plugin’s week calendar: a month to choose the
day in, that day’s free hours with their prices under it, the total, and Book now. The free days
and hours come from the same functions the client’s account uses (baza_bc_service_open_days(),baza_bc_service_free_slots(), baza_bc_service_slot_prices()), the total fromBBC_Booking_Create (context quote: asks whether the time is free and what it costs, makes
nothing). Book now adds one cart line carrying the form and the plugin’s price
(BBC_Woo_Cart::add_from_form()). Not in the picker yet: form-builder fields,
promo codes, whole-day services. Additional services are in it: the same list the plugin’s own form offers for the service, with quantities and the server pricing them.
Cart / checkout. The line’s price is the plugin’s (tax of the shop’s off: the amount is final),
no quantity box, dates shown under the name. The time is asked again at the cart and the checkout
(woocommerce_check_cart_items); a price that moved is updated and the client told. The checkout’s
empty billing fields are filled from the form.
Order. When the order is created, one booking per booking line is made (BBC_Booking_Create,
context woo_order: no gateway, no link), pending and holding its time, linked both ways
(_bbc_booking_ids on the order, woo_order_id on the booking). An order status moves all of its
bookings: processing/completed = booked; on-hold stays pending; cancelled/failed rejects pending
ones; refunded rejects booked ones. A booking rejected by the office cancels the order when none of
its bookings is left.
Import from Woo Bookings. WooCommerce -> Import bookings: preview, then import in batches.
Products -> services (name, text, picture, price), resources -> services under them, bookings ->
bookings (days, client, price, order link). Idempotent (_bbc_imported_from_wc), nothing of Woo
Bookings is changed. Optionally switches the imported products to the Baza booking type.
Not carried over: availability rules and person types (set the service’s hours in the plugin),
bookings in in-cart state. Imported bookings are linked to their order for reference only; the
order’s later status changes do not move them.
Paying later (transfer, cheque, cash)
Offline methods (bacs, cheque, cod; filter baza_bc_woocommerce_offline_methods) leave the
booking pending until the money is in. Bank transfer and cheque: on-hold, paid when the shop marks
the order processing/completed. Cash on delivery goes to processing at once, which is not money:
for methods in baza_bc_woocommerce_paid_on_completion (default cod) the booking is confirmed
only when the order is completed. The bookings list shows a badge with the method and the state
(“Pay later, Cash on delivery”, “Paid, Card”, …), kept in the booking’s meta
(woo_payment_method, woo_payment_title, woo_payment_state, woo_payment_offline).
Price journal and shop coupons
Every change of a booking’s price is written by BBC_Price_Journal::record() (booking metabbc_price_journal, and the activity log’s “Price changed” row with the reason in its text): what
sort of change, why, the price before and after, and who – an administrator, the client, the shop
or the system. Written today: the discounts given when a booking is made (volume, loyalty,
personal, coupon), a price edited by hand in the booking panel, and a WooCommerce coupon.
Shop coupons are allowed. The coupon takes the line below the plugin’s figure; when the order is
made the difference is written into the booking as a discount (promo_sale, coupon_code), the
amount expected becomes what the order really charges, and the journal says “WooCommerce coupon
CODE: 230.00 -> 207.00 (client, WooCommerce order #N)”. The journal is for the office; the client
is not shown it.
Licence
Feature key woocommerce (licence server lookup key woocommerce, in every plan). It opens the
gateway in the list, the product type, the cart and the import. Following the orders already made
(status sync) is not behind it, so a lapsed licence never leaves a paid order unconfirmed.
