TSML for Unity WP Registry grade A. No security issues foundWP RegistryNo security issues foundOpen the reportA
12 Step Meeting List (TSML) with the Unity plugin.
Install
Upload it under Plugins → Add New Plugin → Upload Plugin, then activate.
Install straight from GitHub with WP-CLI:
wp plugin install https://github.com/bleedingdeacons/tsml-for-unity/releases/download/v2.0.5/tsml-for-unity-production-2.0.5.zipA companion WordPress plugin that bridges 12 Step Meeting List (TSML) with the Unity intergroup management framework — providing concrete implementations of every Unity interface backed by TSML data.
Table of Contents
- Overview
- Features
- Requirements
- Installation
- How It Works
- Architecture
- TSML Data Mapping
- Custom Database Tables
- Development
- Troubleshooting
- Contributing
- License
Overview
Unity defines interfaces for groups, meetings, members, positions, locations, contacts, and intergroup meetings — but ships no concrete implementations. TSML for Unity fills that gap by implementing every interface using data from the TSML plugin's custom post types and meta fields.
Once both plugins are active the integration is automatic: TSML for Unity hooks into unity/register_services, registers all factories, repositories, change trackers, and view factories, then stores its field-constant configuration in Unity's Configuration service. No additional setup code is required.
Features
Full Unity Interface Coverage
TsmlGroup/TsmlGroupFactory/TsmlGroupRepository— groups from TSML'stsml_grouppost typeTsmlMeeting/TsmlMeetingFactory/TsmlMeetingRepository— meetings fromtsml_meeting, with day-of-week mapping and a comprehensive meeting-type code lookupTsmlLocation/TsmlLocationFactory/TsmlLocationRepository— locations fromtsml_location, including geocoordinates and timezoneTsmlMember/TsmlMemberFactory/TsmlMemberRepository— members fromintergroup-member, with anonymous-name support and profile visibilityTsmlPosition/TsmlPositionFactory/TsmlPositionRepository— positions fromintergroup-position, with sobriety requirements and term lengthTsmlContact/TsmlContactFactory— contacts extracted from group/meeting meta fieldsTsmlIntergroupMeeting/TsmlIntergroupMeetingFactory/TsmlIntergroupMeetingRepository— intergroup meetings fromintergroup-meeting- Intergroup meeting group attendance and officer attendance (factories, repositories, and custom database tables)
Change Tracking
TsmlGroupChangeTracker— firesunity/group_changingwhen ACF group fields are modifiedTsmlMemberChangeTracker— tracks member field changesTsmlPositionChangeTracker— tracks position field changes
View Layer
TsmlGroupView/TsmlGroupViewFactory— group view combining meetings, contacts, and membersTsmlMeetingView/TsmlMeetingViewFactory— meeting view with associated membersTsmlPositionView/TsmlPositionViewFactory— position view joining position and member data with rotation datesTsmlPositionViewCollection— filterable, sortable collection with helpers for filled/vacant positions
Field Constants
- Every domain module includes a
Fieldsclass (TsmlGroupFields,TsmlMeetingFields,TsmlLocationFields,TsmlMemberFields,TsmlPositionFields,TsmlIntergroupMeetingFields) that maps ACF/meta field names to constants, stored in Unity'sConfigurationservice at boot time.
Requirements
- PHP 8.0 or higher (8.1+ recommended)
- WordPress 6.0 or higher
- Unity plugin — installed and activated
- 12 Step Meeting List (TSML) plugin — installed and activated
- Advanced Custom Fields (recommended for member, position, and intergroup meeting fields)
Installation
Manual
- Ensure both Unity and TSML are installed and active.
- Download the TSML for Unity archive.
- Extract it into
wp-content/plugins/tsml-for-unity/. - Activate TSML for Unity in the WordPress admin under Plugins.
Composer
composer require bleeding-deacons/tsml-for-unity
On activation the plugin creates two custom database tables for intergroup meeting attendance (see Custom Database Tables).
How It Works
Boot Sequence
- Unity loads on
plugins_loaded(priority 10) and firesunity/register_services. - TSML for Unity listens on
unity/register_servicesand callsPlugin::registerWithUnity($container). registerWithUnitychecks which Unity interfaces are available (graceful degradation if a module is missing), then registers every concrete factory, repository, change tracker, and view factory into Unity's container.- Field constants are stored in Unity's
Configurationservice so other code can look up field names by interface class. - Unity resolves its core tracker services, which now resolve to the TSML implementations.
- Unity fires
unity/loaded; TSML for Unity confirms availability and firestsml_for_unity/loaded.
Graceful Degradation
Each domain module is registered only if its Unity interfaces exist. If Unity ships a release that adds or removes an interface, TSML for Unity will silently skip the unavailable module rather than crashing. This is controlled by availability checks such as Plugin::unityGroupsAvailable(), Plugin::unityMeetingsAvailable(), and so on.
Architecture
Directory Structure
tsml-for-unity/
├── tsml-for-unity.php # Main plugin bootstrap
├── src/
│ ├── Plugin.php # Service registration & availability checks
│ ├── Contacts/
│ │ ├── TsmlContact.php
│ │ └── TsmlContactFactory.php
│ ├── Groups/
│ │ ├── TsmlGroup.php
│ │ ├── TsmlGroupChangeTracker.php
│ │ ├── TsmlGroupFactory.php
│ │ ├── TsmlGroupFields.php
│ │ ├── TsmlGroupRepository.php
│ │ ├── TsmlGroupView.php
│ │ └── TsmlGroupViewFactory.php
│ ├── IntergroupMeetings/
│ │ ├── TsmlIntergroupMeeting.php
│ │ ├── TsmlIntergroupMeetingFactory.php
│ │ ├── TsmlIntergroupMeetingFields.php
│ │ ├── TsmlIntergroupMeetingGroupAttendance.php
│ │ ├── TsmlIntergroupMeetingGroupAttendanceFactory.php
│ │ ├── TsmlIntergroupMeetingGroupAttendanceRepository.php
│ │ ├── TsmlIntergroupMeetingGroupAttendanceTable.php
│ │ ├── TsmlIntergroupMeetingOfficerAttendance.php
│ │ ├── TsmlIntergroupMeetingOfficerAttendanceFactory.php
│ │ ├── TsmlIntergroupMeetingOfficerAttendanceRepository.php
│ │ ├── TsmlIntergroupMeetingOfficerAttendanceTable.php
│ │ └── TsmlIntergroupMeetingRepository.php
│ ├── Locations/
│ │ ├── TsmlLocation.php
│ │ ├── TsmlLocationFactory.php
│ │ ├── TsmlLocationFields.php
│ │ └── TsmlLocationRepository.php
│ ├── Meetings/
│ │ ├── TsmlMeeting.php
│ │ ├── TsmlMeetingFactory.php
│ │ ├── TsmlMeetingFields.php
│ │ ├── TsmlMeetingRepository.php
│ │ ├── TsmlMeetingView.php
│ │ └── TsmlMeetingViewFactory.php
│ ├── Members/
│ │ ├── TsmlMember.php
│ │ ├── TsmlMemberChangeTracker.php
│ │ ├── TsmlMemberFactory.php
│ │ ├── TsmlMemberFields.php
│ │ └── TsmlMemberRepository.php
│ └── Positions/
│ ├── TsmlPosition.php
│ ├── TsmlPositionChangeTracker.php
│ ├── TsmlPositionFactory.php
│ ├── TsmlPositionFields.php
│ ├── TsmlPositionRepository.php
│ ├── TsmlPositionView.php
│ ├── TsmlPositionViewCollection.php
│ └── TsmlPositionViewFactory.php
├── tests/ # PHPUnit test suite
├── build.php # Cross-platform build script
├── composer.json
└── phpunit.xml
Hooks
| Hook | Timing | Purpose |
|---|---|---|
unity/register_services |
Listened — registers all TSML services into Unity's container | Core integration point |
unity/loaded |
Listened — confirms Unity is available, fires own loaded hook | Post-boot verification |
tsml_for_unity/loaded |
Fired — after TSML for Unity is fully initialised | Safe to consume TSML for Unity services |
TSML Data Mapping
Post Types
| Unity Domain | TSML Post Type | Fields Class |
|---|---|---|
| Group | tsml_group |
TsmlGroupFields |
| Meeting | tsml_meeting |
TsmlMeetingFields |
| Location | tsml_location |
TsmlLocationFields |
| Member | intergroup-member |
TsmlMemberFields |
| Position | intergroup-position |
TsmlPositionFields |
| Intergroup Meeting | intergroup-meeting |
TsmlIntergroupMeetingFields |
Meeting Type Codes
The meeting factory includes a full lookup table mapping TSML type codes to human-readable names (e.g. C → Closed, O → Open, D → Discussion, B → Big Book, LGBTQ → LGBTQ, SP → Spanish, TC → Location Temporarily Closed, and many more).
Day-of-Week Mapping
TSML uses a 0–6 numeric day index (Sunday–Saturday). The factory converts this to human-readable day names.
Custom Database Tables
On activation TSML for Unity creates two custom tables for intergroup meeting attendance tracking. Schema upgrades are handled automatically via dbDelta on every page load when the stored version differs from the code version.
{prefix}_unity_ig_group_attendance_register (v1.2)
Tracks which groups attended each intergroup meeting, including GSR name and proxy status. Keyed with a unique constraint on (intergroup_meeting_id, group_id).
{prefix}_unity_ig_officer_attendance_register (v1.1)
Tracks officer attendance at intergroup meetings.
Development
Setup
git clone <repository-url>
cd tsml-for-unity
composer install
Commands
| Command | Description |
|---|---|
composer test |
Run the full PHPUnit test suite |
composer test:unit |
Run unit tests only |
composer test:coverage |
Generate an HTML coverage report |
composer phpstan |
Run PHPStan static analysis |
composer cs |
Check WordPress coding standards |
composer cs:fix |
Auto-fix coding standard violations |
composer check |
Run CS + PHPStan + tests in sequence |
Build
composer build:production # Package for distribution (excludes tests/dev files)
composer build:dev # Package with dev files included
composer build:clean # Remove build artifacts
Testing Stack
- PHPUnit 10.5 for unit tests
- bleedingdeacons/wp-mocks for the shared WordPress stand-ins and the base TestCase
- Brain Monkey for WordPress function and hook mocking, replacing WP_Mock —
whose own
requirepinned this suite to PHPUnit 9.6 - Mockery for general mocking
- PHPStan with the WordPress extension for static analysis
- PHP_CodeSniffer with the WordPress standard
The unit suite covers the domain value objects (group, location, meeting,
position, contact, intergroup meeting), the views and view factories, the
ACF-backed factories and AcfFieldKeyResolver, the member/group/position/
intergroup-meeting change trackers, and the location, meeting, intergroup-
meeting and privacy-policy repositories.
Line coverage is reported to Coveralls on every CI run — see the coverage badge at the top of this file.
Troubleshooting
"This plugin requires the Unity plugin to be installed and activated" TSML for Unity cannot find Unity's core classes. Ensure the Unity plugin is installed and activated before activating TSML for Unity.
Services not registering / factories returning null Verify that both TSML and Unity are active. TSML for Unity checks for each Unity interface before registering — if an interface is missing the corresponding service is silently skipped. Check the error log for registration errors.
Intergroup attendance tables not created
Tables are created on plugin activation. If you activated the plugin before Unity was available, deactivate and reactivate TSML for Unity. The maybeUpgrade check on plugins_loaded will also create tables if the stored DB version is outdated.
Change tracker not firing
The group, member, and position change trackers hook into acf/save_post. Ensure ACF is active and that the post type matches the expected TSML post type (e.g. tsml_group for groups). Enable WP_DEBUG and WP_DEBUG_LOG to see captured events.
Contributing
- Fork the repository and create a feature branch.
- Write tests for any new functionality.
- Ensure
composer checkpasses (coding standards, static analysis, and tests). - Submit a pull request with a clear description of the change.
All implementations must conform to the corresponding Unity interface. PHPStan compliance at the level set in phpstan.neon.dist is required.
License
MIT License (Modified) — Copyright © 2025 The Bleeding Deacons
You may use, modify, and distribute this software freely except that you may not sell it, alone or as part of an aggregate distribution. See LICENSE for full terms.
Support
- Email: thebleedingdeacons@gmail.com
- Issues: Use the repository issue tracker
- Plugin URI: github.com/bleeding-deacons/tsml-for-unity
Releases
24 releases. Each count is every asset in that release; expand a row for the breakdown.