{"id":350981,"date":"2026-08-26T07:33:48","date_gmt":"2026-08-26T07:33:48","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/swim-club-manager\/"},"modified":"2026-08-26T07:33:39","modified_gmt":"2026-08-26T07:33:39","slug":"swim-club-manager","status":"publish","type":"plugin","link":"https:\/\/wordpress.org\/plugins\/swim-club-manager\/","author":8328200,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.2.0","stable_tag":"1.2.0","tested":"7.1","requires":"6.4","requires_php":"8.1","requires_plugins":null,"header_name":"Swim Club Manager","header_author":"melbos","header_description":"Member management, training attendance, groups & schedules, competition calendar, and club equipment catalog for swimming clubs.","assets_banners_color":"4cbaa1","last_updated":"2026-08-26 07:33:39","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/github.com\/melbos\/sc-plugin","header_author_uri":"https:\/\/github.com\/melbos","rating":0,"author_block_rating":0,"active_installs":0,"downloads":37,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","changelog"],"tags":{"1.2.0":{"tag":"1.2.0","author":"mebo","date":"2026-08-26 07:33:39"}},"upgrade_notice":[],"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3666437,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3666437,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3666437,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3666437,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.2.0"],"block_files":[],"assets_screenshots":[],"screenshots":[]},"plugin_section":[],"plugin_tags":[5877,14241,1919,4776,127701],"plugin_category":[37,58],"plugin_contributors":[277529],"plugin_business_model":[],"class_list":["post-350981","plugin","type-plugin","status-publish","hentry","plugin_tags-attendance","plugin_tags-club","plugin_tags-members","plugin_tags-sports","plugin_tags-swimming","plugin_category-arts-and-entertainment","plugin_category-user-management","plugin_contributors-mebo","plugin_committers-mebo"],"banners":{"banner":"https:\/\/ps.w.org\/swim-club-manager\/assets\/banner-772x250.png?rev=3666437","banner_2x":"https:\/\/ps.w.org\/swim-club-manager\/assets\/banner-1544x500.png?rev=3666437","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/swim-club-manager\/assets\/icon-128x128.png?rev=3666437","icon_2x":"https:\/\/ps.w.org\/swim-club-manager\/assets\/icon-256x256.png?rev=3666437","generated":false},"screenshots":[],"raw_content":"<!--section=description-->\n<p>Swim Club Manager is a WordPress plugin for managing all aspects of a swimming club:<\/p>\n\n<ul>\n<li><strong>Members<\/strong> \u2014 full profiles (personal info, club details, membership fees, equipment orders, competition entries, results) organized into tabs on a single edit screen<\/li>\n<li><strong>Attendance<\/strong> \u2014 per-session log with present \/ absent \/ excused status<\/li>\n<li><strong>Groups &amp; Schedules<\/strong> \u2014 training groups with weekly schedule management<\/li>\n<li><strong>Competition Calendar<\/strong> \u2014 upcoming meets with participant tracking<\/li>\n<li><strong>Competition Entries &amp; Results<\/strong> \u2014 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<\/li>\n<li><strong>Club Equipment Catalog<\/strong> \u2014 club gear with stock and pricing info<\/li>\n<\/ul>\n\n<p>All data is managed through the WordPress admin. Shortcodes are available for frontend display \u2014 see <strong>Shortcodes<\/strong> below, or the full list with a copy-paste-ready syntax on the plugin's <strong>Dashboard<\/strong> page in wp-admin.<\/p>\n\n<h3>Shortcodes<\/h3>\n\n<ul>\n<li><code>[swimclma_groups_schedule program=\"competitive\" season=\"2025-26\"]<\/code> \u2014 training groups &amp; weekly schedule (both attributes optional)<\/li>\n<li><code>[swimclma_competition_calendar season=\"2025-26\"]<\/code> \u2014 upcoming competitions for a season<\/li>\n<li><code>[swimclma_equipment_catalog in_stock=\"1\"]<\/code> \u2014 club equipment catalog with an \"order via email\" form<\/li>\n<li><code>[swimclma_member_list program=\"competitive\"]<\/code> \u2014 member list (visible to logged-in staff only)<\/li>\n<li><code>[swimclma_attendance_stats member_id=\"123\"]<\/code> \u2014 one member's attendance rate<\/li>\n<li><code>[swimclma_member_results member_id=\"123\"]<\/code> \u2014 one member's personal-best times, grouped by pool length, year and discipline<\/li>\n<\/ul>\n\n<h3>Developer Notes<\/h3>\n\n<p><strong>Autoloading<\/strong><\/p>\n\n<p>Classes are loaded via Composer's PSR-4 autoloader (<code>vendor\/autoload.php<\/code>), required once at the top of <code>swim-club-manager.php<\/code>.<\/p>\n\n<pre><code>composer.json maps the `SwimClub` namespace to three base directories:\n<\/code><\/pre>\n\n<ul>\n<li><code>SwimClub\\<\/code>        \u2192 <code>includes\/<\/code><\/li>\n<li><code>SwimClub\\Admin\\<\/code>  \u2192 <code>admin\/<\/code><\/li>\n<li><code>SwimClub\\Public\\<\/code> \u2192 <code>public\/<\/code><\/li>\n<\/ul>\n\n<p>Sub-namespaces map to subdirectories one-to-one, and the filename must match the class name exactly (PSR-4):<\/p>\n\n<ul>\n<li><code>SwimClub\\PostTypes\\Member<\/code>        \u2192 <code>includes\/PostTypes\/Member.php<\/code><\/li>\n<li><code>SwimClub\\Taxonomies\\Age_Category<\/code> \u2192 <code>includes\/Taxonomies\/Age_Category.php<\/code><\/li>\n<li><code>SwimClub\\DB\\EquipmentOrders<\/code>      \u2192 <code>includes\/DB\/EquipmentOrders.php<\/code><\/li>\n<li><p><code>SwimClub\\Admin\\Admin<\/code>             \u2192 <code>admin\/Admin.php<\/code><\/p>\n\n<p>includes\/Plugin.php (<code>SwimClub\\Plugin<\/code>, the bootstrap singleton returned by <code>swim_club_manager()<\/code>) wires up admin\/public hooks, post types, taxonomies, shortcodes, and REST routes \u2014 each referenced class is autoloaded lazily when first instantiated, not eagerly required.<\/p><\/li>\n<\/ul>\n\n<p><strong>Admin controllers<\/strong><\/p>\n\n<pre><code>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\\`) \u2014 `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()`).\n<\/code><\/pre>\n\n<p><strong>Working with the code<\/strong><\/p>\n\n<ul>\n<li>After pulling changes that add\/rename\/move a class, run <code>composer dump-autoload -o<\/code> to regenerate the optimized classmap in <code>vendor\/<\/code>.<\/li>\n<li><code>vendor\/<\/code> is committed and ships with the plugin \u2014 WordPress installs don't run a Composer build step, so it must be present in the deployed copy.<\/li>\n<li>Non-class files (admin partials, public partials, JS\/CSS) are <code>include<\/code>d directly by the components that render them and are unaffected by autoloading.<\/li>\n<li>Public-facing shortcode styles are written as Sass (<code>public\/scss\/<\/code>) \u2014 one BEM component per shortcode under <code>public\/scss\/components\/<\/code>, shared tokens\/mixins under <code>public\/scss\/abstracts\/<\/code>, compiled to <code>public\/css\/public.css<\/code> via <code>npm install &amp;&amp; npm run build:css<\/code> (or <code>npm run watch:css<\/code> while editing). Like <code>vendor\/<\/code>, <code>public\/css\/public.css<\/code> is committed and ships with the plugin \u2014 regenerate it after any <code>.scss<\/code> change, since WordPress installs don't run this build step either. It's enqueued by <code>SwimClub\\Public\\PublicAssets::enqueue_styles()<\/code> (wired in <code>Plugin::define_public_hooks()<\/code>), which only loads it on pages whose content contains one of the plugin's shortcodes.<\/li>\n<li><code>includes\/Activator.php<\/code> and <code>includes\/Deactivator.php<\/code> are autoloaded like everything else; they don't need to be required manually before <code>plugins_loaded<\/code> since <code>register_activation_hook()<\/code>\/<code>register_deactivation_hook()<\/code> only invoke their callback once WordPress actually fires the (de)activation event, by which point the autoloader is already registered.<\/li>\n<\/ul>\n\n<!--section=installation-->\n<ol>\n<li>Upload the <code>swim-club-manager<\/code> folder to <code>\/wp-content\/plugins\/<\/code><\/li>\n<li>Activate through the Plugins menu<\/li>\n<li>Configure under <strong>Swim Club \u2192 Settings<\/strong><\/li>\n<\/ol>\n\n<!--section=changelog-->\n<h4>1.2.0<\/h4>\n\n<ul>\n<li>Members list: removed the City column and adjusted the Name, Group, and Membership Fee column widths<\/li>\n<li>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<\/li>\n<li>Admin controllers refactored to share common save\/delete logic via the base Controller class (internal, no behavior change)<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>Members admin page reorganized into tabs: Personal Information, Club Details, Membership Fee Payments, Club Equipment Orders, Competition Entries, and Results<\/li>\n<li>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)<\/li>\n<li>Competition disciplines: added 4x50m and 4x100m Freestyle Relay; the existing 4x50m\/4x100m (medley) Relay disciplines now record which leg (1st\u20134th) and stroke a member swam<\/li>\n<li>New: personal-bests results matrix per member \u2014 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 <code>[swimclma_member_results]<\/code> shortcode on the frontend<\/li>\n<li>New: Shortcodes list on the Dashboard page for quick copy-paste reference<\/li>\n<li>Admin CSS and the Members admin template refactored into smaller per-component files for maintainability<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>Initial release<\/li>\n<\/ul>","raw_excerpt":"Member management, training attendance, groups, schedules, competition calendar, club equipment catalog, and competition results for swimming clubs.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/350981","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=350981"}],"author":[{"embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/mebo"}],"wp:attachment":[{"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=350981"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=350981"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=350981"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=350981"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=350981"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=350981"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}