=== Robina ===
Contributors: igor800
Tags: booking, appointments, calendar, scheduling, reservations
Requires at least: 6.0
Tested up to: 7.0
Requires PHP: 8.0
Stable tag: 1.3.1
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Free, open-source booking and appointments for WordPress: services, staff, locations, capacity-aware availability and optional payments.

== Description ==

Robina is a free, open-source booking and appointment plugin for WordPress, built for service businesses that want a capable booking system without subscription fees. It is service- and resource-centric: the bookable unit is a service with its own availability, while staff, locations and resources are optional layers you add only if you need them.

= Highlights =

* **Front-end booking widget (Vue 3).** A clean multi-step wizard — Service, Date & time, Details, Confirm — added to any page with the `[robina_booking_form]` shortcode, or as a popup button with `[robina_booking_button]`.
* **Capacity-aware availability.** Slots are computed from your business hours, slot step and buffers. Assign staff to a service and each one adds a parallel slot; a staff member booked anywhere counts as busy. With no staff, a service has a single capacity per location.
* **Group classes.** Give a service a capacity above 1 (say 20 or 40 — there is no upper limit) and several customers can book the same session until it fills up — ideal for classes, workshops and large group sessions.
* **Front-end class schedule.** Show a public timetable of upcoming classes with the `[robina_schedule]` shortcode — visitors switch between an **Agenda** list and a **Month** calendar grid, each session lists the seats left and links straight into booking. Give a service a weekly schedule (e.g. Monday 18:00) in its editor to put it on the timetable.
* **Staff (optional).** Tag the people who provide a service, pin them to one or more locations, and give them their own weekly hours. When a customer picks a location, only the staff who work there are offered.
* **Locations (optional).** Offices or branches with their own optional weekly hours; each service declares where it is available.
* **Native WordPress admin.** A branded Catalog (services, categories, resources), a Month/Week/Day Calendar with in-place booking creation, plus Bookings, Customers, Staff and Locations screens — all in plain WordPress UI.
* **Email notifications** to the owner and the customer on every new booking, plus optional **reminders** a set number of hours before the appointment.
* **Customer self-cancellation.** The confirmation email carries a personal cancel link, so a customer can free their seat themselves — instantly bookable again by someone else. Set a cancellation window (e.g. up to 12 hours before) or switch it off.
* **Days off and booking notice.** Mark single dates a service does not run (holidays, a break) and close booking a set number of minutes before the start time.
* **Optional online payments** — Pay on site, WooCommerce, Stripe or PayPal (see "External services" below). Leave them all off for free bookings.
* **Self-contained and private.** No external CDNs and no trackers; the phone-input flags and every front-end asset ship inside the plugin. Uninstalling removes Robina's tables and options.

= Service-centric by design =

Robina deliberately keeps availability on the *service*, not on a mandatory "employee". Staff, locations and resources are optional capacity and scope layers, so Robina also suits non-staff models such as equipment rental or table booking.

== External services ==

By default Robina works entirely on your own site and contacts no third party. It only talks to an external service when **you, the admin, enable and configure a payment gateway**, and only when a customer actually chooses to pay with it. No data is sent anywhere otherwise — Robina has no "home" server and sends no telemetry or analytics.

**Stripe** — used only when you enable "Stripe" and enter your API keys. When a customer pays by card, Robina creates a Stripe Checkout Session and redirects the customer to Stripe's hosted payment page, and it receives Stripe webhooks to confirm payment. Data sent to Stripe: the booking amount, currency, a short description and the customer's email. Card details are entered on Stripe's site, never on yours.
Terms: https://stripe.com/legal — Privacy: https://stripe.com/privacy

**PayPal** — used only when you enable "PayPal" and enter your client ID and secret. When a customer pays with PayPal, Robina creates a PayPal order, redirects the customer to PayPal to approve it, then captures it on return. Data sent to PayPal: the booking amount, currency and a reference id.
Terms: https://www.paypal.com/legalhub/home — Privacy: https://www.paypal.com/legalhub/privacy-full

**WooCommerce** (optional, local) — if you enable WooCommerce checkout and WooCommerce is installed, Robina creates a pending WooCommerce order and hands payment off to WooCommerce. Robina makes no external call itself; any outbound requests are made by WooCommerce and its own gateways under their policies.

**Map link** — a location's address is turned into a plain "view on map" link to Google Maps (https://www.google.com/maps/search/...). It is only a link: nothing is transmitted and no map is loaded unless a visitor clicks it.

== Source code ==

Robina is fully open source (GPLv2+). The front-end widget is compiled with Vite from the Vue source that ships inside the plugin under `/resources`. The build files (`package.json`, `package-lock.json`, `vite.config.js`) are bundled too, so the compiled assets in `/assets/dist` can be regenerated from source with:

`npm install && npm run build`

Bundled third-party libraries (installed via npm, both MIT-licensed):

* Vue 3 (^3.4) — https://github.com/vuejs/core
* intl-tel-input (^29.0) — https://github.com/jackocnr/intl-tel-input

== Installation ==

1. Install the ZIP via Plugins → Add New → Upload Plugin, or upload the `robina` folder to `/wp-content/plugins/`.
2. Activate Robina through the Plugins screen.
3. Open **Robina → Settings** to set your business hours, timezone, currency, slot step and (optionally) payment methods.
4. Add services under **Robina → Catalog**. Add Locations and Staff too if you need them.
5. Put `[robina_booking_form]` on any page, or use `[robina_booking_button]` for a popup button. To show a public class timetable, add `[robina_schedule]`.

== Frequently Asked Questions ==

= I activated Robina — why is nothing on my site? =
Because a booking form only appears where you put its shortcode. Open **Robina → Dashboard**: the Getting started panel walks through the four setup steps and lets you copy `[robina_booking_form]` (the full form), `[robina_booking_button]` (a popup button) or `[robina_schedule]` (a class timetable) straight onto a page. The same list is always in the **Help** tab at the top of any Robina screen.

= Do I have to add staff or locations? =
No. A service works on its own with a single capacity and your global business hours. Staff, locations and resources are optional.

= How does availability with several staff work? =
Each staff member assigned to a service adds one parallel slot. A staff member booked on any service at that time is treated as busy. When a customer picks a location, only the staff who work at that location are offered.

= Is payment required? =
No. With no payment method enabled, bookings are free. You can turn on Pay on site, WooCommerce, Stripe and/or PayPal at any time.

= Does Robina send my data anywhere? =
No telemetry, ever. The only outbound calls are to the payment gateway you choose to enable, at checkout — see "External services".

= Will it match my theme? =
Yes. The admin uses native WordPress UI, and the front-end widget inherits your theme font by default; colours and fonts are configurable.

= Can customers cancel by themselves? =
Yes, if you leave "Customer cancellation" enabled in **Robina → Settings**. Every confirmation email contains a personal cancellation link; opening it shows a confirmation page, and only pressing the button cancels. The seat is freed immediately and both you and the customer get an email. Set "Up to (hours before the start)" to stop late cancellations — with 0 it stays possible until the start time.

= How do reminder emails work? =
Set "Reminder email (hours before)" in **Robina → Settings** — for example 24. WordPress checks hourly and emails each customer once, that many hours before their confirmed booking. 0 turns reminders off. Someone who books inside the window (say, two hours before the class) is not sent a reminder minutes after booking. Reminders rely on WP-Cron, so a site with almost no traffic may want a real system cron.

= A class is cancelled for one day — how do I skip it? =
Open the service and add the date under **Days off**. The weekly schedule stays untouched; that date disappears from the timetable and the server refuses bookings for it. It works for on-request services too.

= Can visitors see a schedule of classes? =
Yes. Give a service a weekly **Class schedule** (e.g. Monday and Wednesday at 18:00) in its editor, then add the `[robina_schedule]` shortcode to any page. Visitors see the upcoming sessions by day and time with the seats left, and can book straight from the timetable.

== Screenshots ==

1. The front-end booking wizard — choosing a service.
2. Picking a date and a specialist, with live available times.
3. The admin Catalog — services and categories.
4. The admin Calendar — month view of bookings.
5. Settings — business hours, payments and form appearance.
6. The front-end class schedule — upcoming classes by day and time, with seats left.
7. The class schedule in Month view — a colour-coded calendar grid.
8. The class info card — description, instructor, location and spots left, continuing into the booking wizard.

== Changelog ==

= 1.3.1 =
* New: a **Getting started** panel on the Robina dashboard — four steps from an empty install to a first booking, with one-click copying of the `[robina_booking_form]`, `[robina_booking_button]` and `[robina_schedule]` shortcodes. Dismissible per user.
* New: a short welcome notice after activation, and a **Robina quick start** entry under WordPress' own Help tab on every Robina screen.
* The service editor now says which shortcode publishes a class timetable, right where the weekly schedule is set.

= 1.3.0 =
* New: **customers can cancel their own booking.** Every confirmation email carries a personal cancellation link; the freed seat is bookable again immediately. Optional cancellation window (e.g. "up to 12 hours before"), and the whole feature can be switched off.
* New: **reminder emails** — send customers a reminder a set number of hours before their booking (0 = off). Someone who books inside the reminder window is not reminded minutes later.
* New: **days off per service** — mark single dates a class or service does not run (holidays, an ill instructor, a seasonal break). The weekly schedule stays as it is; those dates simply disappear from the timetable and cannot be booked.
* New: **minimum booking notice** — close online booking a set number of minutes before the start time.
* Redesigned front end: the booking wizard now has a step sidebar and a clearer date/time layout, the class timetable and info card were restyled, and both adapt to the width of the column they sit in. Colours still follow the button colour in Settings.
* Accessibility: visible keyboard focus everywhere, higher text contrast, and all animation respects "reduce motion".

= 1.2.0 =
* New: **front-end class schedule** — a public timetable of upcoming class sessions via the `[robina_schedule]` shortcode, with switchable **Agenda** and **Month** (calendar grid) views, per-class colours and seats-left. Clicking a session opens a class info card (description, duration, price, spots) that continues into the booking wizard preset to that class, date and time.
* New: a **Class schedule** field on each service — set the fixed weekly times it runs as a class, and the booking form then offers only those times.
* New public REST route `GET /robina/v1/schedule` (no personal data).

= 1.1.1 =
* Fix: the booking wizard now formats the chosen date using your site's language (English by default) instead of the visitor's browser locale.

= 1.1.0 =
* New: per-service **capacity** (seats per session). Set it above 1 to turn a service into a group/class where several customers can book the same time until it is full; 1 keeps the usual one-on-one appointment behaviour.

= 1.0.0 =
* First public release.
* Front-end Vue booking wizard (`[robina_booking_form]`) and popup button (`[robina_booking_button]`).
* Capacity-aware availability engine: business hours, slot step and buffers; staff as parallel capacity (a free one is auto-assigned); a single per-location capacity when no staff is configured.
* Optional Staff with location eligibility and optional per-staff weekly hours; optional Locations with their own weekly hours; the engine resolves hours as staff, then location, then global.
* Native admin: Dashboard, Catalog (services, categories, resources), Calendar (Month/Week/Day with create, edit and delete), Bookings, Customers, Staff, Locations and Settings.
* Optional payments: Pay on site, WooCommerce, Stripe (hosted Checkout + signed webhook) and PayPal (Orders v2).
* Email notifications on new bookings. Self-contained assets (no CDN). Clean uninstall.

== Upgrade Notice ==

= 1.3.1 =
Adds in-admin setup guidance: a Getting started panel with copyable shortcodes, a Help tab and a welcome notice.

= 1.3.0 =
Customer self-cancellation links, reminder emails, per-service days off, a minimum booking notice, and a redesigned front end.

= 1.2.0 =
Adds a public class schedule: the `[robina_schedule]` shortcode and a weekly Class schedule per service.

= 1.1.1 =
Booking-wizard dates now follow your site language (English by default).

= 1.1.0 =
Adds optional group/class capacity (seats per session) on each service.

= 1.0.0 =
First public release of Robina.
