Extending Flowcrafter
Add a section to the Workflows admin page without coupling it to a specific integration.
PHP owns section IDs, labels, ordering, and capabilities. The toolbar and the localized flowcrafterAdmin.sections list use the same capability-filtered registry. IDs are unique lowercase slugs and stay in the URL hash, so existing bookmarks keep working.
add_action( 'flowcrafter_register_admin_sections', static function ( string $registry ): void { $registry::register( 'my-inventory', __( 'My Inventory', 'my-plugin' ), 25, 'gravityforms_edit_forms' );} );Built-in orders are Workflows 0, Pending Tasks 10, Activity 20, and Schedules 30. Gravity Forms capabilities (gravityforms_*) honor GF’s gform_full_access permission, matching the host page and REST controller. Other capabilities use WordPress’s direct check and are not bypassed by GF full access. Register through the action, not before it. A capability controls navigation, not endpoint authorization: protect every REST route and ability independently.
Use flowcrafter_admin_scripts to enqueue a separate admin bundle with flowcrafter-admin as a script dependency. This runs after the host’s localization callback on the inventory page, not on the global editor route. Do not depend on or load the editor bundle. Externalize React through WordPress’s dependency-extraction plugin so extension hooks use the same React runtime as the host.
const admin = window.flowcrafterAdminAPI;admin.registerAdminSection('my-inventory', MyInventory);registerAdminSection(id, component) supplies content only; it cannot add PHP navigation or bypass capabilities. Duplicate registrations throw instead of replacing another owner. Registration is reactive: bundles can register before or after the app mounts. If PHP advertised a section but its bundle is absent, the selected section shows an explicit load error. Late registration replaces that error without navigation or a reload. Unrecognized or unauthorized hashes fall back to the first allowed section.
window.flowcrafterAdminAPI exposes:
| Member | Contract |
|---|---|
registerAdminSection(id, component) |
Register a React component for a PHP section ID. |
ListTable<Row> |
Host list-table component, including search chrome, sort headers, loading skeletons, empty/no-match rows, pagination, row actions, selection, bulk actions, and mobile row toggles. |
useListTableState<Row>(options) |
Client-side search, filter tabs, sorting, pagination, and selection. Pass the full fetched row set, stable row IDs, columns, optional search values/filter predicates, initial sort, and per-page count. |
formatDateTime(date) |
The same timestamp formatting as built-in inventories. |
The canonical TypeScript contract is exported from js/src/admin/api.ts, including AdminAPI, AdminSection, list-table types, and UseListTableStateOptions. An independently built peer may mirror the part it consumes, but must keep its declarations aligned. Runtime imports from a sibling plugin’s source are not supported.
An extension owns fetching, REST errors/retry UI, copy failures, and other product-specific interactions. Pass isLoading and an emptyState to the shared table; do not recreate a simplified table that loses search, sorting, pagination, or responsive behavior.
Extensions may subclass Flowcrafter\Inventory_Controller and reuse these protected helpers:
workflows_with_node_type(string $contract): array: indexed lookup of workflows whose registered node handlers implement an interface or extend a class.get_last_node_log_at(int $workflow_id, string $node_id): ?string: latest recorded node execution timestamp across runs (UTC). Requests rejected before execution are not recorded.build_editor_url(...), register_route(...), and check_admin_permission() from Abstract_Workflow_Controller.The extension registers its routes on rest_api_init, formats its own rows, and registers abilities on wp_abilities_api_init. It may reuse Ability_Schemas and Ability_Permissions; load these only when Flowcrafter is present. No product-specific registry is required in core.
API Alchemist owns the Webhooks section and its inventory route, ability, row types, and styles. These administrative APIs use API Alchemist’s namespace, not Flowcrafter’s; core does not carry provider-specific route typings, query keys, or mock endpoints. The public delivery URLs and saved graph shapes remain unchanged so existing senders keep working. Without API Alchemist there is no Webhooks inventory section or ability; core’s advertised Webhook Trigger offer remains available in the editor.