=== Squadeno - Club Sports Manager ===
Contributors: tschiffler
Tags: sports, club, calendar, courses, training
Requires at least: 6.7
Tested up to: 7.1
Requires PHP: 8.1
Stable tag: 1.10.2
License: GPLv2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Training times, people and events for sports clubs, with a calendar that keeps itself current and blocks school holidays automatically.

== Description ==

In most clubs the training schedule exists. Getting it onto the website and keeping it there is the work. The plan lives in a PDF that is two seasons old, the summer break is still not on the calendar, and the person who knows when the hall is free is away for three weeks.

Squadeno turns that around. You maintain the training schedule once, say Tuesday at 6 pm in the gym hall from September to June, and every single date is generated from it. Closures and school holidays block the affected sessions automatically. A cancelled session, a moved date or an extra session is handled on the date itself, and the change shows up everywhere that sport appears.

**Who it is for:** clubs with more than a handful of offerings that want every sport to have its own findable page, and that want trainers to keep their own dates current without being handed the keys to the whole site.

= What you get =

* **Sports** with their own SEO-friendly page; optional subgroups/disciplines (e.g. athletics → kids/youth).
* **Training times** per sport – season- and weather-aware; location as a venue or free text.
* **Automatic calendar**: dates are generated from the training schedule, holidays/closures block automatically, exceptions (cancelled/rescheduled/extra date) and events are added on top.
* **People** with their own profile page: one record per person, whatever they do for the club. An office says what that is (trainer, chair, treasurer), offices can sit in committees, and a person may hold several.
* **The board on the website**: an ordinary page with one block on it, filtered to the board offices and grouped by committee. Anyone who coaches and holds an office is entered once and appears in both places.
* **Venues** with address, GPS, photo and an automatic "what takes place here" list.
* **Events** via a simple builder (open/registration, costs, single- or multi-day).
* **Permissions in two layers**: five task packages ticked per person (own profile, trainer, club administration, dates, public relations), plus a permission level per sport for trainers. Only the club administration may delete, and nobody can pass on a package they do not hold. Plugins, themes, users and the settings stay with the administrator.
* **SEO**: clean URLs, internal linking and structured data (schema.org).
* **Performance**: computed dates are cached (transient) and refreshed automatically on changes.

The source language of the plugin is English; a complete German translation (de_DE) is bundled. Public URL slugs default to English and can be localized per site in the settings.

= Putting it on the page =

Shortcodes (blocks with the same output are also available):

* `[csmgr_sports]` – overview of all sports with filters (age group/section).
* `[csmgr_calendar view="month"]` – club-wide calendar (`view="month"`, `view="week"` or `view="list"` for the weekly training schedule).
* `[csmgr_upcoming sport="ID" limit="5"]` – upcoming dates of a sport.
* `[csmgr_people group="true"]` – the people of the club, optionally filtered to one office (`function="board"`) and grouped by committee.

= More about the plugin =

The project page at [squadeno.com](https://squadeno.com) covers the same ground in more detail, with larger screenshots and a German version of the text.

= Privacy by default =

Maps are optional and switched off by default: no map data is requested from any external server until an administrator selects the map provider "OpenStreetMap" in the settings. The Leaflet map library (BSD-2-Clause) is bundled with the plugin and served locally; it is not loaded from a CDN.

== External services ==

This plugin relies on the following third-party services. It does not send any data unless the corresponding feature is used.

**OpenStreetMap map tiles (optional, disabled by default)** – Maps are off out of the box: the setting "Map provider" (Club Sports → Settings → Calendar & maps) defaults to "none", and while it is set to "none" the plugin contacts no map server at all, neither on the public website nor in the WordPress admin area. Only after an administrator explicitly selects "OpenStreetMap" does the browser load map tiles directly from the OpenStreetMap tile servers (`tile.openstreetmap.org`), on venue pages with coordinates and on the venue editor screen in wp-admin. This transmits the IP address and the requested map section to OpenStreetMap. As a fallback for visitors without JavaScript, an embedded map from `openstreetmap.org` may be displayed. No tracking, analytics or usage data is collected by the plugin or sent anywhere.
Terms/attribution: https://www.openstreetmap.org/copyright – Privacy policy: https://wiki.osmfoundation.org/wiki/Privacy_Policy

**Nominatim geocoding (OpenStreetMap) (optional, disabled by default)** – Part of the same opt-in: only when the map provider "OpenStreetMap" is enabled, and only when an editor clicks the "Determine coordinates from address" button in the venue editor, the address typed into the form is sent to the Nominatim service (`nominatim.openstreetmap.org`) to look up coordinates. It is never called on the public website, and it is not called at all while maps are disabled.
Usage policy: https://operations.osmfoundation.org/policies/nominatim/ – Privacy policy: https://wiki.osmfoundation.org/wiki/Privacy_Policy

**Cloudflare Turnstile (optional, disabled by default)** – Only if an administrator enables Turnstile in the settings, the plugin loads the Turnstile widget script from Cloudflare (`challenges.cloudflare.com`) on pages that show a trainer contact form, and on submission sends the challenge token together with the visitor's IP address to Cloudflare for bot verification. When Turnstile is disabled, no data is sent to Cloudflare.
Terms of use: https://www.cloudflare.com/website-terms/ – Privacy policy: https://www.cloudflare.com/privacypolicy/

== Source code and build ==

The plugin ships with the complete, human-readable source of every generated file, plus the tooling needed to regenerate it. Nothing is obfuscated.

**Editor blocks** – `build/<block>/index.js` is generated and minified. The readable ES module source of each of these files is included in the plugin under `blocks/<block>/index.js` (same folder name, e.g. `blocks/kalender/index.js` → `build/kalender/index.js`).

Build tooling: [@wordpress/scripts](https://www.npmjs.com/package/@wordpress/scripts) (webpack + Babel), declared in the bundled `package.json` / `package-lock.json`. To regenerate the files from the shipped sources, run inside the plugin folder:

`npm ci`
`npm run build`

which executes `wp-scripts build --webpack-src-dir=blocks` and writes `build/`.

**PHP** – All PHP is plain, unminified source under `src/` (PSR-4, autoloaded via Composer; see the bundled `composer.json` / `composer.lock`). `assets/js/*.js` and `assets/css/*.css` are hand-written and unminified as well.

**Third-party libraries**

* Leaflet 1.9.4 – interactive maps, BSD-2-Clause. Bundled locally in `assets/vendor/leaflet/` (upstream distribution build, including `LICENSE`); it is never loaded from a CDN. Project and full source: https://github.com/Leaflet/Leaflet – release used: https://github.com/Leaflet/Leaflet/releases/tag/v1.9.4

== Installation ==

1. Copy the `squadeno-club-sports-manager` folder into `wp-content/plugins/` (or upload the plugin ZIP).
2. Activate it under "Plugins" in the WordPress admin. This creates the content types, roles and default seasons.
3. Maintain sports, trainers, venues and events under the new menu entries.
4. Create pages with the shortcodes or blocks (overview, calendar).
5. Optional: adjust the URL bases (slugs) in the plugin settings, then open Settings → Permalinks once to refresh the links.

== Frequently Asked Questions ==

= Can trainers maintain their own content? =
Yes. Trainers edit only the sports assigned to them as well as their own profile. Each assignment carries one of three levels: full editing of that sport, read-only (listed as a contact, no admin access), or dates only, which allows cancelling, moving and adding a single session and nothing else.

= Does it cover the board as well, not just the trainers? =
Yes. There is one record per person, and an office says what someone does: trainer, chair, treasurer, membership records. Offices can sit in committees, so an executive and an extended board come out in the maintained order rather than alphabetically. A board page is an ordinary page with the people block on it, filtered to the board offices.

= Who is allowed to maintain what? =
Permissions come in two layers. Club-wide there are five task packages, ticked in the person record: own profile, trainer, club administration, dates, and public relations. On top of that a trainer is tied to their assigned sports, with a level per assignment. Only the club administration may delete content, and nobody can pass on a package they do not hold themselves.

= How are holidays handled? =
Central closures automatically hide regular trainings within the period; events (e.g. holiday care) remain visible.

= Is the plugin compatible with caching plugins? =
Yes. Dates are cached internally and invalidated whenever something changes, so a page or object cache on top only makes it faster.

= In which languages is the plugin available? =
The interface is English by default and ships with a complete German translation (de_DE). Additional languages can be added via the bundled .pot file.

= Can the URLs be in another language? =
Yes. The URL bases (e.g. `sports`, `people`) default to English and can be changed per site in the plugin settings, for example to German (`sportarten`, `personen`). After changing them, open Settings → Permalinks once.

= I built my own overview page with a block. Can I use it instead of the plugin's list? =
Yes, and you should. The plugin creates a plain list of every entry at `/sports/`, `/people/` and so on. Most clubs would rather have their own page with the matching block, an introduction and their own wording. Pick that page under Settings → Overview pages, and the plain list redirects to it permanently, while links pointing at the list point to your page instead. Visitors then have one overview instead of two, and themes that build a breadcrumb follow along. Leave the setting empty and nothing changes.

== Screenshots ==

1. All sports at a glance on the website, with filters for age group and section.
2. A sport's own page: training times, contacts and the automatically generated upcoming dates – holidays are blocked automatically.
3. The club-wide calendar (month or week view) with trainings, events and closures. School holidays block the affected sessions, a cancelled one stays visible and struck through.
4. The admin overview introduces new users to the plugin and where to maintain content.
5. Maintaining a sport: the weekly training time, the dates computed from it with cancel and reschedule right there, fields for an extra or a moved session, and the trainers with their permission level.
6. All sports in the admin area, with their sub-groups, age groups and sections.
7. Permissions in two layers: five task packages ticked per person, and a permission level per sport for trainers.
8. The trainers as their own page, filtered to the office "Trainer".
9. The board as its own page, filtered to the board offices and grouped by committee. These are the same records as the trainers, so nobody is kept twice.

== Changelog ==

= 1.10.2 =
* Fixed: the calendar's age group filter now finds events. A holiday club with the age groups "children" and "youth" disappeared from the calendar as soon as the filter was set to exactly those age groups, because the filter only looked at the age group of the sport, and club-wide events were left out whenever a filter was set.
* The age group on an event now counts more than the one on its sport: a children's event at an adults' sport shows up under "children", and the parents' evening at the children's gymnastics does not. An event without an age group of its own keeps the one from its sport.
* Fixed: an event without times now shows up in the calendar as an all-day date. A holiday club that runs from Monday to Friday has no times, and until now such an event was missing from every calendar view. The week view, the training schedule and "Upcoming dates" label it "All day", the month grid shows the name without a time, and the calendar export makes it a date entry.

= 1.10.1 =
* In the People block, the photo leads to the person's page as well. Visitors click the picture, not the name below it.
* The editor shows the blocks the way the page does. Until now the plugin's stylesheet was missing in the editor, so a block of people stood there as a plain list and the settings for layout and columns had no visible effect.
* The People list now carries the plugin's spacing and colours on any page. On a page that holds nothing else from the plugin, the cards came without spacing, surface or frame.
* The People block explains its settings: "Columns" sets how wide a card is, not how many are shown, and "Layout" says what cards and list look like.

= 1.10.0 =
* New setting "Overview pages": pick the page that visitors should see as the overview of sports, people, events or venues. The plugin's own archive then redirects there, and links to the archive point to your page, so there is one overview instead of two. Leave it empty to keep the built-in archive.
* The URL base for people is "people" now. Sites that update keep their existing base, so no link breaks.
* The update fills in the offices: every existing person record gets the office "Trainer", because until now every record of this type was one.
* A starter set of offices comes with the plugin: trainer, executive board with chair, deputy chair and treasurer, extended board with secretary and board member. Rename or remove what does not fit.
* One record per person: the entry type is called People now, and it carries trainers, board members and anyone else with a role in the club.
* New base data: functions. The offices of the club, with committees as parent entries and a sort order, because alphabetically the treasurer comes before the chair.
* New block "People" and shortcode [csmgr_people]: shows the board or any other group, as cards or as a list, grouped by committee if you want.
* Permissions are assigned per person now: own profile, trainer, club administration, dates, and public relations.
* Permission changes now also reach sites that update the plugin, not only fresh installations.
* Closures and seasons come with their own permissions instead of borrowing those for blog posts.
* Trainers can assign sections and age groups to the sports they maintain.
* Editors no longer maintain closures, seasons, sections, age groups and event types. Administrators do, and site owners who need help there can grant the capabilities with a role plugin.
* Fixed: everyone with the right permission can add content again. Bundling the club data under one menu had blocked "Add new" for sports, people, events, venues, closures and seasons for everyone except administrators.
* Fixed: the seasons open from the base data tabs again instead of showing an error page.
* Fixed: trainers with the "cancel dates" level can no longer change the sections and age groups of a sport. The restriction only applied to the classic form, not to the editor's own save path.
* Fixed: adding content follows the task packages. Until now every package could publish sports and people it was not allowed to edit or remove afterwards. Adding people, sports, venues and seasons belongs to club administration, events and closures to the dates package.
* People without an office get their own heading in the People block instead of appearing under the last committee.
* The roles this plugin adds carry its name now: "Squadeno: Trainer" instead of "Trainer". In the user list they sat next to "Editor" with nothing saying where they came from.
* The default seasons are created in the language of the site. Seasons that already exist keep their names.
* The week view of the calendar is a list now, one day per row with its date, and today is highlighted. As a grid it only scrolled sideways on narrow screens.
* A note on a training time appears under the name of the sport, not next to the venue, where it read like a detail of the venue.
* The person page shows the offices directly under the name, each with its committee, and an office comes before the trainer role.
* "Roles & permissions" now also explains how permissions are assigned, in four steps with a diagram.

= 1.9.0 =
* New calendar view `view="list"`: the training schedule of the week, grouped by weekday.
* Sub-categories in the calendar now name their main category, for example Gymnastics > Kids gymnastics.
* Settings: pick which calendar views the site offers (month, week, list).
* Cancelled dates in the training schedule are struck through instead of carrying a label.
* Admin area: closures, seasons, sections, age groups and event types moved into one menu entry "Base data" with tabs.
* The plugin directory page now offers a live preview: try the plugin with demo data, right in the browser.

= 1.8.1 =
* Clearer wording on the plugin directory page, with a link to the project page.
* German translation of the directory page, in both the informal and the formal address.
* No changes to the plugin itself.

= 1.8.0 =
* First public release in the WordPress plugin directory.

== Upgrade Notice ==

= 1.10.2 =
Two fixes for the calendar: events with an age group of their own now appear when visitors filter by that age group, and an event without times shows up as an all-day date instead of being left out. Nothing to do after the update.

= 1.10.1 =
A fix for the People block: the photo leads to the person's page, the editor shows the block the way the page does, and the list gets the plugin's spacing and colours on every page. Nothing to do after the update.

= 1.10.0 =
Trainer records are people records now: they keep their URLs and each one gets the office "Trainer". Permissions move to task packages that you assign per person. Please note that editors no longer maintain closures, seasons, sections, age groups and event types — administrators do.

= 1.9.0 =
The calendar gains a training schedule view, and the admin menu has fewer entries. Existing pages, shortcodes and blocks keep working unchanged.

= 1.8.1 =
Text only: the directory page reads better and is now available in German. Nothing changes in the plugin, so there is no hurry.
