=== Swim Club Manager ===
Contributors:       mebo
Tags:               sports, swimming, club, members, attendance
Requires at least:  6.4
Tested up to:       7.1
Requires PHP:       8.1
Stable tag:         1.2.0
License:            GPL-2.0-or-later
License URI:        https://www.gnu.org/licenses/gpl-2.0.html

Member management, training attendance, groups, schedules, competition calendar, club equipment catalog, and competition results for swimming clubs.

== Description ==

Swim Club Manager is a WordPress plugin for managing all aspects of a swimming club:

* **Members** — full profiles (personal info, club details, membership fees, equipment orders, competition entries, results) organized into tabs on a single edit screen
* **Attendance** — per-session log with present / absent / excused status
* **Groups & Schedules** — training groups with weekly schedule management
* **Competition Calendar** — upcoming meets with participant tracking
* **Competition Entries & Results** — log which disciplines a member is entered in per meet (including relay leg/stroke and pool length), and see their personal-best times automatically summarized in a year-by-year, pool-length results matrix
* **Club Equipment Catalog** — club gear with stock and pricing info

All data is managed through the WordPress admin. Shortcodes are available for frontend display — see **Shortcodes** below, or the full list with a copy-paste-ready syntax on the plugin's **Dashboard** page in wp-admin.

== Shortcodes ==

* `[swimclma_groups_schedule program="competitive" season="2025-26"]` — training groups & weekly schedule (both attributes optional)
* `[swimclma_competition_calendar season="2025-26"]` — upcoming competitions for a season
* `[swimclma_equipment_catalog in_stock="1"]` — club equipment catalog with an "order via email" form
* `[swimclma_member_list program="competitive"]` — member list (visible to logged-in staff only)
* `[swimclma_attendance_stats member_id="123"]` — one member's attendance rate
* `[swimclma_member_results member_id="123"]` — one member's personal-best times, grouped by pool length, year and discipline

== Installation ==

1. Upload the `swim-club-manager` folder to `/wp-content/plugins/`
2. Activate through the Plugins menu
3. Configure under **Swim Club → Settings**

== Developer Notes ==

**Autoloading**

Classes are loaded via Composer's PSR-4 autoloader (`vendor/autoload.php`), required once at the top of `swim-club-manager.php`.

`composer.json` maps the `SwimClub` namespace to three base directories:

* `SwimClub\`        → `includes/`
* `SwimClub\Admin\`  → `admin/`
* `SwimClub\Public\` → `public/`

Sub-namespaces map to subdirectories one-to-one, and the filename must match the class name exactly (PSR-4):

* `SwimClub\PostTypes\Member`        → `includes/PostTypes/Member.php`
* `SwimClub\Taxonomies\Age_Category` → `includes/Taxonomies/Age_Category.php`
* `SwimClub\DB\EquipmentOrders`      → `includes/DB/EquipmentOrders.php`
* `SwimClub\Admin\Admin`             → `admin/Admin.php`

`includes/Plugin.php` (`SwimClub\Plugin`, the bootstrap singleton returned by `swim_club_manager()`) wires up admin/public hooks, post types, taxonomies, shortcodes, and REST routes — each referenced class is autoloaded lazily when first instantiated, not eagerly required.

**Admin controllers**

`admin/Admin.php` only handles enqueueing, menu registration, page-partial rendering, and meta boxes. Form/CRUD handling (the `admin_post_swimclma_*` actions) lives one-per-domain under `admin/Controllers/` (`SwimClub\Admin\Controllers\`) — `MemberController`, `GroupController`, `AttendanceController`, `CompetitionController`, `EquipmentController`, `EquipmentOrderController`, `MembershipFeeController`, `CompetitionEntryController`, `SettingsController`. Each exposes `save()` / `delete()` (and `update_status()` where relevant) and is wired directly to its `admin_post_*` hook in `Plugin::define_admin_hooks()`. They all extend the abstract `Controller` base class, which provides the shared nonce/capability guard helpers (`verify_nonce_or_die()`, `verify_request_nonce_or_die()`, `require_cap_or_die()`).

**Working with the code**

* After pulling changes that add/rename/move a class, run `composer dump-autoload -o` to regenerate the optimized classmap in `vendor/`.
* `vendor/` is committed and ships with the plugin — WordPress installs don't run a Composer build step, so it must be present in the deployed copy.
* Non-class files (admin partials, public partials, JS/CSS) are `include`d directly by the components that render them and are unaffected by autoloading.
* Public-facing shortcode styles are written as Sass (`public/scss/`) — one BEM component per shortcode under `public/scss/components/`, shared tokens/mixins under `public/scss/abstracts/`, compiled to `public/css/public.css` via `npm install && npm run build:css` (or `npm run watch:css` while editing). Like `vendor/`, `public/css/public.css` is committed and ships with the plugin — regenerate it after any `.scss` change, since WordPress installs don't run this build step either. It's enqueued by `SwimClub\Public\PublicAssets::enqueue_styles()` (wired in `Plugin::define_public_hooks()`), which only loads it on pages whose content contains one of the plugin's shortcodes.
* `includes/Activator.php` and `includes/Deactivator.php` are autoloaded like everything else; they don't need to be required manually before `plugins_loaded` since `register_activation_hook()`/`register_deactivation_hook()` only invoke their callback once WordPress actually fires the (de)activation event, by which point the autoloader is already registered.

== Changelog ==

= 1.2.0 =
* Members list: removed the City column and adjusted the Name, Group, and Membership Fee column widths
* Club Equipment list: the Size, Condition, Purchased, and Notes columns now hide below a 1500px viewport width for a cleaner view on smaller admin screens
* Admin controllers refactored to share common save/delete logic via the base Controller class (internal, no behavior change)

= 1.1.0 =
* Members admin page reorganized into tabs: Personal Information, Club Details, Membership Fee Payments, Club Equipment Orders, Competition Entries, and Results
* Competition entries: added an Edit action on the entries table, a wider result-time field, and a per-entry pool length (25m/50m, auto-filled from the competition)
* Competition disciplines: added 4x50m and 4x100m Freestyle Relay; the existing 4x50m/4x100m (medley) Relay disciplines now record which leg (1st–4th) and stroke a member swam
* New: personal-bests results matrix per member — best time per pool length / year / discipline, with an all-time-best row and a relay results table. Available as the "Results" tab in admin and via the new `[swimclma_member_results]` shortcode on the frontend
* New: Shortcodes list on the Dashboard page for quick copy-paste reference
* Admin CSS and the Members admin template refactored into smaller per-component files for maintainability

= 1.0.0 =
* Initial release