Workshop Listing
One listing, four views. This is the shared pattern behind Plan's Recent workshop agendas, Facilitate's Choose a Workshop and Synthesize's Ready to synthesize — the same workshop record seen from three points in the journey, so it renders from one component instead of three hand-cut card templates.
Component: app/includes/workshop-list.php · Styles: app/css/workshop-list.css · Behaviour: app/js/workshop-list-views.js + app/js/workshop-list-pages.js
The full pattern
Every view is server-rendered; the switcher toggles which one is visible, and the stage chips filter rows already in the page. Both are instant and cost no fetch. The chosen view is remembered per listing.
Workshop library
Recent workshops
8 workshops across 4 stages
Innovation Spark for Engineers
Igniting Innovation for Engineers
User Journey Mapping Essentials
Untitled Workshop
Retrospective: Q2 Product Sprint
Design Principles Alignment
Quarterly Goals Workshop
| Workshop | Duration | Items | Last updated | Stage | Action | |
|---|---|---|---|---|---|---|
| make a decision we keep postponing | — | 0 | Updated 2 weeks ago | Plan | ||
| Innovation Spark for Engineers | 2h | 6 | Updated 5/13/2026 | Facilitate | ||
| Igniting Innovation for Engineers | 2h | 8 | Updated 5/13/2026 | Facilitate | ||
| User Journey Mapping Essentials | 2h | 6 | Updated 4/27/2026 | Synthesize | ||
| Untitled Workshop | 1h 45m | 2 | Updated 5/11/2026 | Strategize | ||
| Retrospective: Q2 Product Sprint | 1h 30m | 10 | Updated 5/9/2026 | Synthesize | ||
| Design Principles Alignment | 3h | 12 | Updated 5/7/2026 | Facilitate | ||
| Quarterly Goals Workshop | — | 0 | Updated 5/3/2026 | Strategize |
Strategize
2Plan
1Facilitate
3Synthesize
2Scheduled
2make a decision we keep postponing
Design Principles Alignment
Recent workshops
4Innovation Spark for Engineers
Igniting Innovation for Engineers
User Journey Mapping Essentials
Retrospective: Q2 Product Sprint
Drafts
2Untitled Workshop
Quarterly Goals Workshop
No workshops at that stage.
How each page configures it
The three pages differ only in their copy, which workshops they pass, and where the action goes. Each is pinned to the grid view here to make the comparison readable; drop 'views' to offer the full switcher.
Plan — the Plan chip opens pressed
Recent workshop agendas
make a decision we keep postponing
Innovation Spark for Engineers
Igniting Innovation for Engineers
User Journey Mapping Essentials
Untitled Workshop
Retrospective: Q2 Product Sprint
Design Principles Alignment
Quarterly Goals Workshop
No workshops at that stage.
Facilitate — the Facilitate chip opens pressed
Choose a workshop
Select a saved workshop to start facilitating.
make a decision we keep postponing
Innovation Spark for Engineers
Igniting Innovation for Engineers
User Journey Mapping Essentials
Untitled Workshop
Retrospective: Q2 Product Sprint
Design Principles Alignment
Quarterly Goals Workshop
No workshops at that stage.
Synthesize — the Synthesize chip opens pressed
Ready to synthesize
make a decision we keep postponing
Innovation Spark for Engineers
Igniting Innovation for Engineers
User Journey Mapping Essentials
Untitled Workshop
Retrospective: Q2 Product Sprint
Design Principles Alignment
Quarterly Goals Workshop
No workshops at that stage.
Chips and pages together
With pageSize set, the pager windows the rows the active chip leaves visible — never the whole collection. Fourteen rows here, six to a page, opening on the Plan chip: nine plan rows page in two; switch to All and fourteen page in three; switch to Synthesize and its two rows show no pager at all. Changing the chip always re-pages from page one. On a paged listing, workshop-list-pages.js is the sole writer of row visibility and the chips report the active stage to it — that single ownership is what keeps a row from going missing between the two systems. Kanban and timeline are whole-collection layouts and never paginate.
Fourteen workshops, six to a page
Workshop 01 · agenda in progress
Workshop 02 · agenda in progress
Workshop 03 · agenda in progress
Workshop 04 · agenda in progress
Workshop 05 · agenda in progress
Workshop 06 · agenda in progress
Workshop 07 · agenda in progress
Workshop 08 · agenda in progress
Workshop 09 · agenda in progress
Workshop 10 · ready to run
Workshop 11 · ready to run
Workshop 12 · ready to run
Workshop 13 · awaiting recap
Workshop 14 · awaiting recap
| Workshop | Duration | Items | Last updated | Stage | Action | |
|---|---|---|---|---|---|---|
| Workshop 01 · agenda in progress | 2h | 1 | Updated May 2026 | Plan | ||
| Workshop 02 · agenda in progress | 2h | 2 | Updated May 2026 | Plan | ||
| Workshop 03 · agenda in progress | 2h | 3 | Updated May 2026 | Plan | ||
| Workshop 04 · agenda in progress | 2h | 4 | Updated May 2026 | Plan | ||
| Workshop 05 · agenda in progress | 2h | 5 | Updated May 2026 | Plan | ||
| Workshop 06 · agenda in progress | 2h | 6 | Updated May 2026 | Plan | ||
| Workshop 07 · agenda in progress | 2h | 7 | Updated May 2026 | Plan | ||
| Workshop 08 · agenda in progress | 2h | 8 | Updated May 2026 | Plan | ||
| Workshop 09 · agenda in progress | 2h | 9 | Updated May 2026 | Plan | ||
| Workshop 10 · ready to run | 2h | 10 | Updated May 2026 | Facilitate | ||
| Workshop 11 · ready to run | 2h | 11 | Updated May 2026 | Facilitate | ||
| Workshop 12 · ready to run | 2h | 12 | Updated May 2026 | Facilitate | ||
| Workshop 13 · awaiting recap | 2h | 13 | Updated May 2026 | Synthesize | ||
| Workshop 14 · awaiting recap | 2h | 14 | Updated May 2026 | Synthesize |
No workshops at that stage.
Empty state
Ready to synthesize
No workshops waiting on a recap.
Usage
require_once ws_path('app/includes/workshop-list.php');
echo ws_workshop_list([
'title' => 'Recent workshop agendas',
'workshops' => array_map('ws_workshop_list_normalize', $rows),
'cta' => ['label' => 'Continue', 'href' => '/app/?view=plan&step=build&plan={id}'],
'footer' => ['label' => 'All workshops', 'href' => '/app/?view=plan&step=saved'],
'views' => ['grid', 'list', 'kanban', 'timeline'], // omit for all four
'chips' => true, // draw the stage filter chips; default true
'filter' => 'plan', // the stage lens; default 'all'
'pageSize' => 12, // pages grid + list over the active chip's rows
]);
filter names the listing's stage lens: 'all' or a stage key, and a value outside the listing's own stages scope falls back to 'all'. With chips => true it is the chip that opens pressed, and first-paint row visibility matches it. With chips => false it is the listing's whole subject: the rows are cut to that stage server-side and nothing can widen them, which is what a phase page wants. Plan, Facilitate, Synthesize and Prove each list the work they are owed, head it with a count, and close with a link back to Home; Home keeps the chips and the whole collection. pageSize pages the grid and list views client-side over the rows the active chip leaves visible: changing the chip re-pages from page one, and a chip with pageSize rows or fewer shows no pager.
ws_workshop_list_normalize() accepts a /api/plans.php row merged with stage and stage_complete from /api/workshop-record.php. The stage is the phase a workshop currently owes work in, derived server-side by wrDeriveStage() from the agenda size, the Strategist handoff and the delivery and synthesis stamps — never stored. Rows may also carry tag (kanban chip) and group/date/time/location (timeline).
The retired three-value lifecycle_status (designed, delivered, synthesized) is still accepted as an input but is no longer emitted: it could not tell a pre-planned workshop from an untouched one, which is the distinction the four phases exist to draw.