Bundled services live inside the SignalPress or SignalPress Pro plugin under services/{service-id}/. SignalPress discovers them automatically — no bootstrap edit required.
Overview: Extending SignalPress. External plugins: Custom integrations.
Directory layout
Text
services/
my-service/
service.php ← entry file (required)
class-signalpress-my-service-service.php
logo.svg
README.md ← service Help tab (recommended)
Reference implementation: services/local/ in the free plugin.
Entry file
service.php must return an object implementing SignalPress_Provider (prefer SignalPress_Service):
PHP
Free plugin discovery
SignalPress_Service_Loaderglobs:Text
signalpress/services/*/service.phpEach valid object is registered with
register_internal()-- reserved for official SignalPress packages.Pro plugin discovery
Pro registers on
_signalpress/register_internal_services:
- Prefer class
SignalPress_{Service_Id}_Serviceif it exists (for exampleSignalPress_Posthog_Serviceforservices/posthog/).- Otherwise
requireservice.phpand use the returned instance.Pro services also use
register_internal().Implement SignalPress_Service
Minimum methods (see
services/local/class-signalpress-local-service.php):
Method Purpose get_id()Stable service ID (lowercase, underscores) -- used in Service Targeting get_name()Admin display name get_description()Integrations card copy is_premium()falsefor free-tier services;truewhen license gating appliesget_logo_url()Integrations card icon get_service_url()/get_account_url()External links (optional) get_settings_fields()Settings form schema is_configured()Whether delivery can run capture()Send the event; return trueorWP_ErrorOptional helpers
Method Purpose sanitize_settings()Normalize saved settings on Settings save can_test_connection()/test_connection()Connection test button on Settings tab get_required_license_feature()Hub feature flag when is_premium()is trueenqueue_browser_tracking()Load a browser SDK when enabled capture() contract
PHP
public function capture( SignalPress_Event $event, array $settings ) { $payload = [ 'event' => $event->get_name(), 'properties' => $event->get_properties(), 'context' => $event->get_context(), ]; $response = wp_remote_post( 'https://api.example.com/events', [ 'timeout' => 5, 'blocking' => false, 'headers' => [ 'Content-Type' => 'application/json' ], 'body' => wp_json_encode( $payload ), ] ); return is_wp_error( $response ) ? $response : true; }Use
wp_remote_post()with'blocking' => falsefor fire-and-forget delivery unless you need a synchronous test. Connection tests use blocking requests intest_connection().Expose a service-specific payload filter when integrators need last-mile shaping -- for example
signalpress/posthog/payload. Document it in the service README.Settings fields
Common field keys:
Key Type Notes label-- Field label typetext,password,url,checkbox,number,select,tagsRendered on Settings tab default-- Default value description-- Help text under the control advanced_grouproutingPlaces field on Routing tab (shared routing fields) premium_featurefeature id Locks field below required tier help_sectionslug In-plugin ? link to Help heading Shared routing fields are injected via
signalpress_routing_settings_fields()-- Advanced Event Routing.Service Help README
Add
services/{id}/README.mdwith setup, examples, limits, and troubleshooting. SignalPress renders it on SignalPress → {Service} → Help using the bundled Marked parser.Tier 2: extend discovery (custom distributions)
Official packages use fixed paths. Tier 2 sites can append entry files:
PHP
add_filter( 'signalpress/bundled_service_files', function ( $files ) { $files[] = WP_PLUGIN_DIR . '/my-agency-pack/services/acme/service.php'; return $files; } );Returned services still register through
register_internal()-- use this for private forks or agency packs, not third-party customer plugins. Customer-facing plugins should use Custom integrations.Do not use register_internal() in third-party code
register_internal()is the package boundary for SignalPress and Pro. Third-party WordPress plugins must call$registry->register()onsignalpress/register_services.What to read next