Adding a provider
Developer reference: This section is for PHP developers shipping a custom booking integration alongside Booking Engine Connector.
The plugin resolves integrations through ProviderInterface (includes/Providers/Contracts/ProviderInterface.php). The bundled KrossProvider is the reference implementation.
High-level checklist
- Implement
ProviderInterfacein your own PHP class (Composer autoload or manualrequireinside a small bootstrap plugin). - Register the admin label map via
bec_registered_providersso Booking Engine → Connection shows your slug. - Return your concrete instance from
bec_provider_instancewhen WordPress asks for your slug—ProviderRegistry::getProvider()invokes this filter before falling back to built-ins. - Store credential fields declaratively via
getCredentialSchema()— Connection saves options asbec_{slug}_{fieldKey}automatically. - Implement
fetchRemoteUnits(),extractCoreUnitFields(),getQuoteForUnit(),buildCheckoutUrl(), and optionallyBulkQuoteProviderInterface+getUnitInfoRenderers().
Admin registration
Dropdown labels
Filter bec_registered_providers receives [ slug => human label ]. Merge your slug:
add_filter('bec_registered_providers', function (array $map): array {
$map['myengine'] = __('My Engine', 'my-plugin');
return $map;
});
If the saved active slug is missing from this map after filtering, Connection resets selection to kross — always merge both keys during rollout migrations.
Concrete provider instance
Filter bec_provider_instance receives (null|ProviderInterface $maybe, string $slug):
add_filter('bec_provider_instance', function ($provider, string $slug) {
if ($slug === 'myengine') {
return new MyEngineProvider();
}
return $provider;
}, 10, 2);
Without this hook, unknown slugs currently fall back to KrossProvider inside ProviderRegistry::getProvider(), which would break unrelated integrations—always pair new slugs with this filter.
Credential schema
Implement getCredentialSchema(): array returning a list of CredentialField objects describing admin inputs (label, help, type, required, etc.). Validate connectivity inside validateCredentials() so Sync surfaces actionable errors early.
Core responsibilities
| Method | Responsibility |
|---|---|
getSlug() | Stable lowercase slug (myengine). Must match map/filter keys. |
fetchRemoteUnits() | Return normalised arrays consumed by sync (external_id, nested raw payload, …). Apply filters already documented in Sync hooks where relevant. |
extractCoreUnitFields() | Populate CoreUnitSemantic keys (bec_core_*). |
getUnitSyncFieldDefinitions() | Optional extra meta definitions (UnitSyncFieldDefinition). Return [] if unused. |
requiresChildrenAges() / getSearchGuestFieldMode() | Drive [bec_search] field wiring (SearchGuestFieldMode). |
getQuoteForUnit() | Return arrays/WP_Error consistent with quote consumers (QuoteService). |
buildCheckoutUrl() | Return ['url' => ..., 'label' => ...] or POST descriptor (method=post, post_fields). |
getUnitInfoRenderers() | Map shortcode keys → callables for [bec_unit_info] (may return []). |
Optional BulkQuoteProviderInterface batches availability once per SearchContext (see interface docblocks under includes/Providers/Contracts/BulkQuoteProviderInterface.php).
Units remember their provider slug
Each bec_unit stores bec_provider_slug. Quotes/checkout resolve via that slug even if the global active provider changes—keep slug constants backward compatible when renaming integrations.
Testing hooks
Use bec_test_connection from Connection page verify button for non-Kross adapters (return friendly strings/WP_Error). Kross wires token exchange automatically.
Related docs
- Architecture
- Unit info renderers
- Kross API — behavioural reference even when cloning patterns for another vendor.