=== ReservePro Booking Widgets ===
Contributors: reservepro
Tags: booking, reservations, classes, schedule, events
Requires at least: 6.3
Tested up to: 7.1
Requires PHP: 7.4
Stable tag: 1.5.1
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Take bookings on your WordPress site: offer cards, schedules, court availability and sign-up buttons from your ReservePro account.

== Description ==

**ReservePro is an online booking and payment system for dance and fitness schools, sports clubs and courts, camp and course organisers, shooting ranges and driving schools.** You run your offer, sign-ups and payments in the ReservePro panel; your customers book online and pay by card, BLIK or Przelewy24 (through Stripe).

This plugin puts that offer on your WordPress site. Visitors see your classes, dates, prices and free places on your own pages, click "Sign up" and finish the booking and the payment on your ReservePro booking site.

= First: a ReservePro account =

The plugin is free, but it has nothing of its own to show — it displays widgets from **your ReservePro account**.

* Create the account yourself, online, at [reservepro.app](https://reservepro.app).
* You can start for free. What is free and what is paid is described in the [price list](https://reservepro.pl/pricing).
* Add your first offer in the ReservePro panel — a class, a court, a course or an event. Only then is there something to show in WordPress.

Without a ReservePro account the plugin shows nothing.

= The widgets you get =

* **Offer cards** — a photo, the place, the dates, the level, the instructor, the price and a sign-up button. One card or a grid of cards you choose. (Screenshot 1)
* **Schedule with filters** — all your weekly classes, courses or drop-in sessions as cards, with filters by location, instructor and level. (Screenshot 2)
* **Weekly calendar** — the same classes as a Monday-to-Sunday timetable of days and hours.
* **Court and station availability** — a strip of days and a grid of free and taken hours for every court, lane or station; a click on a free hour opens the booking with that hour chosen. (Screenshot 3)
* **Sign-up button with free places** — a button for any place on a page, with a line such as "last places" under it; it turns into "Notify me" when the offer sells out. The number of free places is also available as plain text.
* **Offer hero** — a large presentation of one course, camp, trip or event with a photo, the date, the price and a choice of group or date.
* **Instructors with free hours** — instructor cards with a week of free and taken hours for individual lessons.
* **Cabin calendar** — a monthly availability calendar for a cabin or an apartment.
* **"Looking for a gift?" banner and gift vouchers** — a strip in your colours that leads to your gift vouchers, and voucher cards in the card grid. (Screenshot 4)
* **QR code** — a code with the link to an offer, for a poster or a leaflet.
* **AI assistant (beta)** — a chat bubble that answers visitors' questions about your offers, dates, prices and free places. We are testing it with selected organisers. It is not part of the standard plans yet; terms and pricing will be announced after the tests. Want to join? Write to support@reservepro.app.

= Start in 3 steps =

1. **Create a ReservePro account and add an offer** at [reservepro.app](https://reservepro.app).
2. **Install the plugin and click "Connect with ReservePro"** in Settings → ReservePro. You confirm in your ReservePro panel and come back to WordPress with "Connected to …". (Screenshot 6)
3. **Add the "ReservePro widget" block** to a page, choose the widget and pick the offer from a list. The editor shows a live preview. (Screenshot 5)

= Why it works this way =

* **Part of your page, not an iframe.** Your WordPress server fetches the widget and prints it in the page HTML. Search engines see your real offer, nothing pops in after the page has loaded, and the widgets work without JavaScript in the visitor's browser.
* **It keeps itself up to date.** Free places, "sold out" and waiting-list states and court availability refresh while the page is open. You never edit the page after a booking.
* **No API keys.** Connecting takes one click and nothing secret is stored in WordPress — the widgets show only what is already public on your booking site.
* **Your theme stays as it is.** Widget styles ship with the plugin and apply only to the widgets, in the colours you set in ReservePro.

= Block =

Add the "ReservePro widget" block in the block editor (search for "ReservePro"), choose the widget, then pick the offer and the group or date (or the gift voucher) from the lists in the block settings — no codes to copy. The editor shows a live preview, and the published page shows exactly the same widget.

= Shortcode =

Prefer shortcodes, or use a page builder? Every widget is also available as a shortcode:

`[reservepro widget="course-card" offer="offer-slug"]`

The ready-made shortcode for every widget and offer, with all options, can be copied from your ReservePro panel (Widgets → "WordPress" tab). A `[reservepro]` shortcode in a Shortcode block can be turned into the block with the block toolbar (Transform).

Widget names: sign-up button (`cta`), offer card (`course-card`), card grid (`grid`), "Looking for a gift?" banner (`gift-banner`), schedule with filters (`schedule`), weekly calendar (`calendar`), offer hero (`jambo`), free places label (`remaining`), court availability (`resources-availability`), cabin calendar (`stay-calendar`), instructors with hours (`instructor-hours`), QR code (`qrcode`), AI assistant (beta) (`assistant`).

Examples:

`[reservepro widget="cta" offer="offer-slug" cta="Sign up"]`
`[reservepro widget="schedule" preset="classes"]`
`[reservepro widget="jambo" offer="offer-slug"]`
`[reservepro widget="grid" offers="offer-a,offer-b"]`
`[reservepro widget="grid" offers="offer-a,voucher-slug"]`
`[reservepro widget="gift-banner"]`
`[reservepro widget="gift-banner" voucher="voucher-slug"]`
`[reservepro widget="qrcode" offer="offer-slug"]`
`[reservepro widget="assistant" offer="offer-slug"]`

Questions? Write to support@reservepro.app.

== External services ==

This plugin connects to ReservePro (https://reservepro.app), the booking service that provides the widgets. Without it the plugin has nothing to show. No request is made until an administrator clicks "Connect with ReservePro" or enters the booking site address in Settings → ReservePro.

What is sent, when and where:

* **Connect with ReservePro** — when the administrator clicks this button, their browser is sent to the ReservePro panel (`https://reservepro.app/admin/connect/wordpress`, or the panel of the booking site already entered) with the address of the plugin settings screen and a random one-time code. After the administrator logs in and confirms, the browser comes back with the public organiser identifier and booking site address, which the plugin then verifies with the connection check below. No password, key or token is exchanged or stored.
* **Connection check** — when the administrator saves the settings, clicks "Test connection", comes back from "Connect with ReservePro", or (once) when settings saved by version 1.0 are upgraded: a request from your WordPress server to `<your booking site>/api/tenant` (for example `https://yourname.reservepro.app/api/tenant`). It returns the public name and identifier of the organiser.
* **Widget content** — when a page with the `[reservepro]` shortcode or the ReservePro block is displayed (or previewed in the block editor) and the cached copy is older than the cache lifetime: a request from your WordPress server to `https://widgets.reservepro.app/api/<organiser identifier>/widgets/<widget>` with the shortcode parameters (offer, group, date and display options) in the query string.
* **Widget refresh** — while a page with a widget that changes (sign-up button, free places, court availability, calendars, cards) is open and the browser tab is visible, the plugin's script in the visitor's browser asks your WordPress site (REST route `/wp-json/reservepro/v1/widget`) for the current widget; your WordPress server answers from its cache or, when the cached copy is older than the cache lifetime, makes the "Widget content" request above. The visitor's browser does not contact ReservePro for this.
* **Offer list in the block editor** — when an editor opens the settings of the ReservePro block and the cached list is older than the cache lifetime: a request from your WordPress server to `https://widgets.reservepro.app/api/offers?tenant=<organiser identifier>`. It returns the public list of offers (names, booking types, groups and dates) shown in the block settings. Together with it: a request to `<your booking site>/api/voucher-offers`, which returns the public list of your published gift vouchers (the plugin keeps only their names and addresses) for the "Looking for a gift?" banner and the card grid. The lists are available only to logged-in users who can edit posts.
* All server requests carry the IP address of your WordPress server and a User-Agent header with the plugin version and your site address. No data about your visitors is sent by these requests.
* **QR code widget and images** — the visitor's browser loads the QR code image from `https://widgets.reservepro.app` and the offer photos shown in widgets from your ReservePro booking site, which shares the visitor's IP address and browser information with ReservePro as with any web resource. Links in widgets lead visitors to your ReservePro booking site.
* **AI assistant widget** (only when you add `[reservepro widget="assistant"]` or the block with "AI assistant") — the visitor's browser loads the script `<your booking site>/widgets/assistant.js` and, when the visitor opens the bubble and asks a question, sends the question, the address of the current page and the optional offer context to `<your booking site>/api/assistant/messages`; the answer is streamed back. ReservePro processes the question with an AI model to answer it (see the ReservePro privacy policy) and keeps only statistics of the conversation (no message texts). Nothing is sent until the visitor types a question.

ReservePro terms of use: https://reservepro.pl/terms-of-use
ReservePro privacy policy: https://reservepro.pl/privacy-policy

== Installation ==

1. Install the plugin from the Plugins screen (Add New → search for "ReservePro"), or upload the ZIP file from your ReservePro panel, and activate it.
2. Go to Settings → ReservePro and click "Connect with ReservePro". Log in to your ReservePro panel if asked and confirm — you come back to WordPress with "Connected to …".
3. Alternatively enter the address of your ReservePro booking site (for example `yourname.reservepro.app`, or your own connected domain), click "Test connection", then "Save Changes".
4. In the block editor add the "ReservePro widget" block, choose the widget and pick the offer from the list in the block settings.
5. Or use the shortcode: in the ReservePro panel open Widgets, choose a widget and an offer, switch to the "WordPress" tab, copy the shortcode and paste it into a page, a post or a Shortcode block.

== Frequently Asked Questions ==

= Do I need a ReservePro account? =

Yes. The plugin shows widgets of your ReservePro booking site; offers, schedules and bookings are managed in the ReservePro panel.

= Is ReservePro free? =

The plugin is free. ReservePro itself can be started for free; what is free and what is paid is described in the price list: https://reservepro.pl/pricing

= Is the AI assistant included? =

Not yet. The AI assistant is in beta: a chat bubble that answers visitors' questions about your offers, dates, prices and free places, which we are testing with selected organisers. It is not part of the standard plans yet; terms and pricing will be announced after the tests. If you would like to join the tests, write to support@reservepro.app.

= Does it need an API key? =

No. Widgets show only public offer information that is already visible on your booking site, so nothing secret is stored in WordPress.

= How do I disconnect the site? =

Settings → ReservePro → "Disconnect". It clears the organiser, the address and the widget cache in WordPress; nothing changes in ReservePro.

= Does it need JavaScript on the visitor's side? =

No. The widget HTML is fetched by your WordPress server and printed in the page. Filters and tabs inside widgets work with CSS only. With JavaScript, a small script of the plugin keeps the widgets up to date while the page is open and switches the day of the court availability widget without reloading the page.

= Will it slow down my site? =

No. Your WordPress server fetches a widget once and keeps it for a few minutes, so your pages do not wait for ReservePro on every visit. You can change how long widgets are kept in Settings → ReservePro (5 minutes by default).

= How quickly do changes show on my page? =

While a page is open, the widgets refresh by themselves: court availability every minute, sign-up buttons and free places every two minutes. A visitor who opens the page sees a copy that is at most a few minutes old.

= Will the widget styles change my theme? =

No. All widget styles are limited to the widget containers.

= What happens if ReservePro is unreachable? =

The plugin shows the last copy of the widget it fetched successfully, or a plain "View offer" link if no copy exists yet, and it waits a minute before asking ReservePro again, so an outage does not slow down your pages.

= Is there a block for the block editor? =

Yes — "ReservePro widget". It lists your widgets, offers and groups, shows a preview in the editor and renders the same HTML as the shortcode on the page.

= Does it work with page builders? =

Yes, wherever shortcodes are supported — the Elementor "Shortcode" widget, the classic editor and text widgets. In the block editor use the "ReservePro widget" block.

= How do I show widgets in another language? =

Widget texts come from your ReservePro booking site. The settings screen of the plugin is translatable.

== Screenshots ==

1. Offer cards on a page: photo, place, dates, level, instructor, price and a "Sign up" button.
2. A schedule with filters by instructor and level, embedded in a page.
3. Court availability: a strip of days, playing time and free hours with prices.
4. The "Looking for a gift?" banner and gift voucher cards.
5. The "ReservePro widget" block in the editor: widget, offer and group chosen from lists, with a live preview.
6. Settings → ReservePro after one click on "Connect with ReservePro": "Connected to …", booking site address and cache lifetime.

== Changelog ==

= 1.5.1 =
* "Looking for a gift?" banner: on wide screens the button keeps its natural width on the right and no longer squeezes the text; on phones it stays full width under the text.
* New plugin description and screenshots in the plugin directory.

= 1.5.0 =
* New `gift-banner` widget: the "Looking for a gift?" banner — a strip in your colours with a button that leads to your gift vouchers on your booking site. Shortcode `[reservepro widget="gift-banner"]` opens the list of all your gift vouchers; add `voucher="voucher-slug"` to open the purchase page of one voucher. Optional `title`, `description` and `cta` replace the heading, the text and the button text. The banner shows only when you have a published gift voucher in ReservePro.
* Card grid: gift vouchers are added to the grid by their address, the same way as offers — `[reservepro widget="grid" offers="offer-a,voucher-slug"]`. A voucher gets a card like an offer card, with a button that leads to its purchase page.
* Block: "Looking for a gift?" banner on the widget list, with the banner target chosen from a list of your published gift vouchers; in the card grid, published gift vouchers are on the same list as the offers, marked "(voucher)".
* Offer cards show an "Available as a gift voucher" label when a published gift voucher covers the offer.

= 1.4.3 =
* Widget CSS (organiser colours and font, filter rules of the schedule and court availability widgets) is rebuilt from an allowlist before it is added with wp_add_inline_style() or returned to the refresh script: only rules scoped to ReservePro widget elements, plain values and a short list of CSS functions — no at-rules, url(), escapes or comments.
* Cached widget HTML is filtered with wp_kses() again each time it is printed.

= 1.4.2 =
* Live widgets: sign-up buttons, free places, court availability, calendars and cards refresh themselves while the page is open and the tab is visible (court availability every minute), keeping the visitor's choices. The plugin's own script (assets/js/widgets.js, loaded with wp_enqueue_script() only on pages with such a widget) asks your WordPress site for the current widget; no remote JavaScript.
* One script and one stylesheet: assets/js/widgets.js is built from the same source as the ReservePro widget script (one code path for refreshing, keeping choices and the court day strip), and the plugin's own rules are now part of assets/css/widgets.css — a single `reservepro-widgets` style handle instead of two.
* Court availability: a day in the day strip opens on the same page (`?rp_date=`), or switches in place with JavaScript, instead of opening the raw widget address.
* Widgets that refresh themselves are cached no longer than their refresh interval.

= 1.4.1 =
* Widget styles in the block editor preview and the AI assistant script are now loaded only through the WordPress enqueue API (wp_enqueue_style(), wp_add_inline_style(), wp_enqueue_script() with the async strategy) — the plugin no longer prints `<style>` or `<script>` elements itself.

= 1.4.0 =
* New `assistant` widget: the ReservePro AI assistant bubble on your pages (shortcode `[reservepro widget="assistant"]` and the block), with an optional course context. Available to organisers who have the assistant enabled in ReservePro.

= 1.3.0 =
* New "ReservePro widget" block: choose the widget, the offer and the group from lists, set the widget options in the block settings and see a preview in the editor. The page gets the same server-rendered HTML as the shortcode.
* `[reservepro]` shortcodes in a Shortcode block can be transformed into the block.
* The block shows a link to the plugin settings when the site is not connected to ReservePro yet.

= 1.2.0 =
* "Connect with ReservePro": connect the site from the settings screen by logging in to the ReservePro panel — no keys or tokens; the returned data is verified with ReservePro before it is saved.
* "Disconnect" button that clears the connection and the widget cache.

= 1.1.0 =
* Widgets are fetched from the ReservePro widget host using the organiser identifier; settings from 1.0 are upgraded automatically.
* Widget styles ship with the plugin and are scoped to the widgets (no remote CSS, no changes to the theme).
* Widget HTML is filtered with wp_kses() using a list of the tags the widgets use.
* The last successfully fetched copy of a widget is shown when ReservePro is unreachable.
* Widget list generated from the ReservePro widget catalogue: court availability, cabin calendar and instructors with hours added.
* English source texts with a Polish translation; settings script loaded with wp_enqueue_script().
* Requires WordPress 6.3 and PHP 7.4.

= 1.0.0 =
* Initial release: settings screen with connection test, `[reservepro]` shortcode, transient caching, fallback link.

== Upgrade Notice ==

= 1.5.1 =
Fixes the layout of the "Looking for a gift?" banner on wide screens. Nothing to change on your side.

= 1.5.0 =
Adds the "Looking for a gift?" banner widget and gift voucher cards in the card grid. Existing widgets and shortcodes keep working.

= 1.4.3 =
Stricter filtering of widget CSS and HTML. Nothing to change on your side.

= 1.4.2 =
Widgets now stay up to date while the page is open, and the court availability day strip stays on your page. Nothing to change on your side.

= 1.4.1 =
Styles and the assistant script are now loaded through the WordPress enqueue API; nothing to change on your side.

= 1.4.0 =
Adds the AI assistant bubble widget. Existing widgets and shortcodes keep working.

= 1.3.0 =
Adds the "ReservePro widget" block for the block editor. Shortcodes keep working.

= 1.2.0 =
Adds one-click "Connect with ReservePro". Existing settings keep working.

= 1.1.0 =
Widget styles are now bundled with the plugin and no longer change your theme. Settings are upgraded automatically.
