Handler Registration Trait
Standardized handler registration trait introduced in v0.2.2 that eliminates ~70% of boilerplate code across all handlers.
Overview
HandlerRegistrationTrait (/inc/Core/Steps/HandlerRegistrationTrait.php) provides a single registerHandler() method that automatically registers handlers with all required WordPress filters.
Architecture
- Location:
/inc/Core/Steps/HandlerRegistrationTrait.php - Purpose: Centralize handler registration logic
- Benefits:
- Reduces code duplication by ~70%
- Ensures consistent registration patterns
- Centralizes filter registration logic
- Auto-handles conditional registration
Method Signature
protected static function registerHandler(
string $handler_slug,
string $handler_type,
string $handler_class,
string $label,
string $description,
bool $requires_auth = false,
?string $auth_class = null,
?string $settings_class = null,
?callable $tools_callback = null,
?string $authProviderKey = null
): void
Parameters
- $handler_slug: Unique identifier for the handler (e.g., ‘twitter’, ‘rss’)
- $handler_type: Handler type (‘fetch’, ‘publish’, ‘update’)
- $handler_class: Fully qualified class name for the handler
- $label: Display name for admin interface (translatable)
- $description: Handler description for admin interface (translatable)
- $requires_auth: Whether handler requires OAuth authentication
- $auth_class: Fully qualified auth class name (required if requires_auth=true)
- $settings_class: Fully qualified settings class name
- $tools_callback: Callback for AI tool registration
- $authProviderKey: Optional auth provider key override for shared authentication. When set, the handler metadata includes
auth_provider_key, and the auth provider is registered under this key.
Filters Registered
The trait automatically registers handlers with the following WordPress filters:
1. datamachine_handlers
Handler metadata registration (always registered).
add_filter('datamachine_handlers', function($handlers) {
$handlers[$handler_slug] = [
'type' => $handler_type,
'class' => $handler_class,
'label' => $label,
'description' => $description,
'requires_auth' => $requires_auth
];
return $handlers;
});
2. datamachine_auth_providers
Authentication provider registration (conditional on requires_auth=true).
Auth providers are keyed by provider key, not necessarily the handler slug.
- Default:
provider_key === handler_slug - Shared auth: pass
$authProviderKeytoregisterHandler()and use that as the provider key
// Only registered if requires_auth is true
add_filter('datamachine_auth_providers', function($providers) use ($provider_key) {
$providers[$provider_key] = new $auth_class();
return $providers;
});
3. datamachine_handler_settings
Settings class registration (always registered if settings_class provided).
add_filter('datamachine_handler_settings', function($settings, $handler_slug_param) {
if ($handler_slug_param === $handler_slug) {
return $settings_class;
}
return $settings;
}, 10, 2);
4. chubes_ai_tools
AI tool registration via callback (conditional on tools_callback provided).
// Only registered if tools_callback is provided
add_filter('chubes_ai_tools', $tools_callback, 10, 3);
Usage Example
Basic Usage (Publish Handler)
use DataMachineCoreStepsHandlerRegistrationTrait;
class TwitterFilters {
use HandlerRegistrationTrait;
public static function register(): void {
self::registerHandler(
'twitter',
'publish',
Twitter::class,
__('Twitter', 'datamachine'),
__('Post content to Twitter with media support', 'datamachine'),
true, // Requires OAuth
TwitterAuth::class,
TwitterSettings::class,
function($tools, $handler_slug, $handler_config) {
if ($handler_slug === 'twitter') {
$tools['twitter_publish'] = datamachine_get_twitter_tool($handler_config);
}
return $tools;
}
);
}
}
// Auto-execute at file load
function datamachine_register_twitter_filters() {
TwitterFilters::register();
}
datamachine_register_twitter_filters();
Fetch Handler Example
use DataMachineCoreStepsHandlerRegistrationTrait;
class RSSFilters {
use HandlerRegistrationTrait;
public static function register(): void {
self::registerHandler(
'rss',
'fetch',
RSS::class,
__('RSS Feed', 'datamachine'),
__('Fetch content from RSS/Atom feeds', 'datamachine'),
false, // No auth required
null,
RSSSettings::class,
null // No AI tools for fetch handlers
);
}
}
function datamachine_register_rss_filters() {
RSSFilters::register();
}
datamachine_register_rss_filters();
Update Handler Example
use DataMachineCoreStepsHandlerRegistrationTrait;
class WordPressUpdateFilters {
use HandlerRegistrationTrait;
public static function register(): void {
self::registerHandler(
'wordpress_update',
'update',
WordPressUpdate::class,
__('WordPress Update', 'datamachine'),
__('Update existing WordPress content', 'datamachine'),
false,
null,
WordPressUpdateSettings::class,
function($tools, $handler_slug, $handler_config) {
if ($handler_slug === 'wordpress_update') {
$tools['wordpress_update'] = datamachine_get_wordpress_update_tool($handler_config);
}
return $tools;
}
);
}
}
function datamachine_register_wordpress_update_filters() {
WordPressUpdateFilters::register();
}
datamachine_register_wordpress_update_filters();
Migration Guide
Custom handlers should adopt this pattern by:
-
*Add trait to Filters class:
use DataMachineCoreStepsHandlerRegistrationTrait; class MyHandlerFilters { use HandlerRegistrationTrait; } -
Replace manual filter calls with single
registerHandler()call:// Before (manual registration) add_filter('datamachine_handlers', function($handlers) { /* ... */ }); add_filter('datamachine_auth_providers', function($providers) { /* ... */ }); add_filter('datamachine_handler_settings', function($settings) { /* ... */ }); add_filter('chubes_ai_tools', function($tools) { /* ... */ }); // After (trait registration) self::registerHandler( 'my_handler', 'publish', MyHandler::class, __('My Handler', 'textdomain'), __('Handler description', 'textdomain'), true, MyHandlerAuth::class, MyHandlerSettings::class, $tools_callback ); -
Move tool registration to callback parameter:
function($tools, $handler_slug, $handler_config) { if ($handler_slug === 'my_handler') { $tools['my_tool'] = [ 'class' => MyHandler::class, 'method' => 'handle_tool_call', 'handler' => 'my_handler', 'description' => 'Tool description', 'parameters' => [/* ... */] ]; } return $tools; } -
Remove redundant filter registration code from *Filters.php file.
File Organization
Handler registration files follow this structure:
/inc/Core/Steps/
├── Fetch/Handlers/
│ ├── RSS/
│ │ ├── RSS.php (handler class)
│ │ ├── RSSSettings.php (settings class)
│ │ └── RSSFilters.php (registration using trait)
│ └── ...
├── Publish/Handlers/
│ ├── Twitter/
│ │ ├── Twitter.php (handler class)
│ │ ├── TwitterAuth.php (auth class)
│ │ ├── TwitterSettings.php (settings class)
│ │ └── TwitterFilters.php (registration using trait)
│ └── ...
└── HandlerRegistrationTrait.php (shared trait)
Benefits
Code Reduction
Before trait (typical handler registration):
// ~40 lines of repetitive filter registration code
add_filter('datamachine_handlers', function($handlers) {
$handlers['my_handler'] = [
'type' => 'publish',
'class' => MyHandler::class,
'label' => __('My Handler', 'textdomain'),
'description' => __('Description', 'textdomain'),
'requires_auth' => true
];
return $handlers;
});
add_filter('datamachine_auth_providers', function($providers) {
$providers['my_handler'] = MyHandlerAuth::class;
return $providers;
});
add_filter('datamachine_handler_settings', function($settings, $handler_slug) {
if ($handler_slug === 'my_handler') {
return MyHandlerSettings::class;
}
return $settings;
}, 10, 2);
add_filter('chubes_ai_tools', function($tools, $handler_slug, $handler_config) {
if ($handler_slug === 'my_handler') {
$tools['my_tool'] = [/* ... */];
}
return $tools;
}, 10, 3);
After trait (same functionality):
// ~15 lines total
self::registerHandler(
'my_handler',
'publish',
MyHandler::class,
__('My Handler', 'textdomain'),
__('Description', 'textdomain'),
true,
MyHandlerAuth::class,
MyHandlerSettings::class,
function($tools, $handler_slug, $handler_config) {
if ($handler_slug === 'my_handler') {
$tools['my_tool'] = [/* ... */];
}
return $tools;
}
);
Consistency
- Ensures all handlers follow identical registration patterns
- Prevents missing or incorrectly configured filters
- Centralizes validation logic for handler metadata
Maintainability
- Single location for registration logic updates
- Easy to add new registration requirements
- Simplified debugging of handler registration issues
Type Safety
- Method signature provides clear parameter requirements
- IDE autocomplete support for all parameters
- PHP type hints prevent registration errors
See Also
- Core Filters – Complete filter reference
- Fetch Handler – Fetch handler base class
- Publish Handler – Publish handler base class
- Settings Handler – Settings base classes
Related Documentation
- Handler Defaults System – Configuration merging logic
- Services Layer – Architectural overview