| 1 |
<?php |
| 2 |
/** |
| 3 |
* Merchant Abilities Registry. |
| 4 |
* |
| 5 |
* Registers all gateway abilities with WordPress and manages |
| 6 |
* module adapter resolution. |
| 7 |
* |
| 8 |
* @package Merchant |
| 9 |
* @since 2.3.0 |
| 10 |
*/ |
| 11 |
|
| 12 |
if ( ! defined( 'ABSPATH' ) ) { |
| 13 |
exit; |
| 14 |
} |
| 15 |
|
| 16 |
/** |
| 17 |
* Merchant_Abilities_Registry |
| 18 |
* |
| 19 |
* Central registry that registers all Merchant abilities with the |
| 20 |
* WP Abilities API and resolves module adapters for campaign |
| 21 |
* summary formatting. |
| 22 |
* |
| 23 |
* @since 2.3.0 |
| 24 |
*/ |
| 25 |
class Merchant_Abilities_Registry { |
| 26 |
|
| 27 |
/** |
| 28 |
* Module IDs excluded from all ability surfaces. |
| 29 |
* |
| 30 |
* Single source of truth — handlers reference this |
| 31 |
* instead of maintaining their own copies. |
| 32 |
* |
| 33 |
* @var array<int, string> |
| 34 |
*/ |
| 35 |
private static $excluded_module_ids = array( 'global-settings' ); |
| 36 |
|
| 37 |
/** |
| 38 |
* Check if a module is excluded from abilities. |
| 39 |
* |
| 40 |
* @param string $module_id The module identifier. |
| 41 |
* |
| 42 |
* @return bool True if excluded. |
| 43 |
*/ |
| 44 |
public static function is_excluded( $module_id ) { |
| 45 |
return in_array( $module_id, self::$excluded_module_ids, true ); |
| 46 |
} |
| 47 |
|
| 48 |
/** |
| 49 |
* Schema generator instance. |
| 50 |
* |
| 51 |
* @var Merchant_Schema_Generator |
| 52 |
*/ |
| 53 |
private $schema_generator; |
| 54 |
|
| 55 |
/** |
| 56 |
* Field validator instance. |
| 57 |
* |
| 58 |
* @var Merchant_Field_Validator |
| 59 |
*/ |
| 60 |
private $field_validator; |
| 61 |
|
| 62 |
/** |
| 63 |
* Campaign resolver instance. |
| 64 |
* |
| 65 |
* @var Merchant_Campaign_Resolver |
| 66 |
*/ |
| 67 |
private $campaign_resolver; |
| 68 |
|
| 69 |
/** |
| 70 |
* Registered module adapters. |
| 71 |
* |
| 72 |
* @var array<string, Merchant_Module_Abilities_Interface> |
| 73 |
*/ |
| 74 |
private $adapters = array(); |
| 75 |
|
| 76 |
/** |
| 77 |
* Ability definitions contributed by other plugins (e.g. merchant-pro). |
| 78 |
* |
| 79 |
* @var array<lowercase-string&non-falsy-string, array<string, mixed>> |
| 80 |
*/ |
| 81 |
private $contributed = array(); |
| 82 |
|
| 83 |
/** |
| 84 |
* Constructor. |
| 85 |
* |
| 86 |
* @param Merchant_Schema_Generator $schema_generator Schema generator instance. |
| 87 |
* @param Merchant_Field_Validator $field_validator Field validator instance. |
| 88 |
* @param Merchant_Campaign_Resolver $campaign_resolver Campaign resolver instance. |
| 89 |
*/ |
| 90 |
public function __construct( $schema_generator, $field_validator, $campaign_resolver ) { |
| 91 |
$this->schema_generator = $schema_generator; |
| 92 |
$this->field_validator = $field_validator; |
| 93 |
$this->campaign_resolver = $campaign_resolver; |
| 94 |
} |
| 95 |
|
| 96 |
/** |
| 97 |
* Register all 10 gateway abilities with WordPress, followed by any |
| 98 |
* abilities contributed via register_ability_definition(). |
| 99 |
* |
| 100 |
* @return void |
| 101 |
*/ |
| 102 |
public function register_all_abilities() { |
| 103 |
$abilities = $this->get_ability_definitions(); |
| 104 |
|
| 105 |
foreach ( $abilities as $ability_id => $definition ) { |
| 106 |
wp_register_ability( $ability_id, $definition ); |
| 107 |
} |
| 108 |
|
| 109 |
foreach ( $this->contributed as $ability_id => $definition ) { |
| 110 |
wp_register_ability( $ability_id, $definition ); |
| 111 |
} |
| 112 |
} |
| 113 |
|
| 114 |
/** |
| 115 |
* Contribute an ability definition to be registered alongside the core map. |
| 116 |
* |
| 117 |
* Lets other plugins (e.g. merchant-pro) add abilities without |
| 118 |
* modifying the core definitions. Contributions are deduped by id; |
| 119 |
* registering the same id again overwrites the previous definition. |
| 120 |
* |
| 121 |
* @param lowercase-string&non-falsy-string $id The ability identifier. |
| 122 |
* @param array<string, mixed> $def The ability definition, in the same |
| 123 |
* shape as wp_register_ability() expects. |
| 124 |
* |
| 125 |
* @return void |
| 126 |
*/ |
| 127 |
public function register_ability_definition( $id, $def ) { |
| 128 |
$this->contributed[ $id ] = $def; |
| 129 |
} |
| 130 |
|
| 131 |
/** |
| 132 |
* Register a custom module adapter. |
| 133 |
* |
| 134 |
* @param string $module_id The module identifier. |
| 135 |
* @param Merchant_Module_Abilities_Interface $adapter The adapter instance. |
| 136 |
* |
| 137 |
* @return void |
| 138 |
*/ |
| 139 |
public function register_adapter( $module_id, $adapter ) { |
| 140 |
$this->adapters[ $module_id ] = $adapter; |
| 141 |
} |
| 142 |
|
| 143 |
/** |
| 144 |
* Get the adapter for a module. |
| 145 |
* |
| 146 |
* Returns a custom adapter if registered, otherwise a default adapter. |
| 147 |
* |
| 148 |
* @param string $module_id The module identifier. |
| 149 |
* |
| 150 |
* @return Merchant_Module_Abilities_Interface |
| 151 |
*/ |
| 152 |
public function get_adapter( $module_id ) { |
| 153 |
if ( isset( $this->adapters[ $module_id ] ) ) { |
| 154 |
return $this->adapters[ $module_id ]; |
| 155 |
} |
| 156 |
|
| 157 |
return new Merchant_Default_Module_Adapter( $module_id ); |
| 158 |
} |
| 159 |
|
| 160 |
/** |
| 161 |
* Get the schema generator instance. |
| 162 |
* |
| 163 |
* @return Merchant_Schema_Generator |
| 164 |
*/ |
| 165 |
public function get_schema_generator() { |
| 166 |
return $this->schema_generator; |
| 167 |
} |
| 168 |
|
| 169 |
/** |
| 170 |
* Get the field validator instance. |
| 171 |
* |
| 172 |
* @return Merchant_Field_Validator |
| 173 |
*/ |
| 174 |
public function get_field_validator() { |
| 175 |
return $this->field_validator; |
| 176 |
} |
| 177 |
|
| 178 |
/** |
| 179 |
* Get the campaign resolver instance. |
| 180 |
* |
| 181 |
* @return Merchant_Campaign_Resolver |
| 182 |
*/ |
| 183 |
public function get_campaign_resolver() { |
| 184 |
return $this->campaign_resolver; |
| 185 |
} |
| 186 |
|
| 187 |
/** |
| 188 |
* Build all 10 ability definition arrays. |
| 189 |
* |
| 190 |
* @return array<lowercase-string&non-falsy-string, array<string, mixed>> |
| 191 |
*/ |
| 192 |
private function get_ability_definitions() { |
| 193 |
$registry = $this; |
| 194 |
|
| 195 |
return array( |
| 196 |
'merchant/list-modules' => array( |
| 197 |
'label' => __( 'List Merchant Modules', 'merchant' ), |
| 198 |
'description' => __( 'Discover all available Merchant modules with their types and status.', 'merchant' ), |
| 199 |
'category' => 'merchant', |
| 200 |
'meta' => array( |
| 201 |
'show_in_rest' => true, |
| 202 |
'annotations' => array( |
| 203 |
'readonly' => true, |
| 204 |
'destructive' => false, |
| 205 |
'idempotent' => true, |
| 206 |
), |
| 207 |
), |
| 208 |
'input_schema' => array( |
| 209 |
'type' => 'object', |
| 210 |
'additionalProperties' => false, |
| 211 |
'properties' => array( |
| 212 |
'filter' => array( |
| 213 |
'type' => 'string', |
| 214 |
'description' => 'Filter by status: active, inactive, or empty for all.', |
| 215 |
'enum' => array( 'active', 'inactive' ), |
| 216 |
'default' => '', |
| 217 |
), |
| 218 |
'section' => array( |
| 219 |
'type' => 'string', |
| 220 |
'description' => 'Filter by section slug.', |
| 221 |
'default' => '', |
| 222 |
), |
| 223 |
), |
| 224 |
), |
| 225 |
'output_schema' => array( |
| 226 |
'type' => 'object', |
| 227 |
'description' => 'Module listing with counts.', |
| 228 |
'required' => array( 'success', 'data' ), |
| 229 |
'properties' => array( |
| 230 |
'success' => array( 'type' => 'boolean' ), |
| 231 |
'data' => array( |
| 232 |
'type' => 'object', |
| 233 |
'properties' => array( |
| 234 |
'modules' => array( |
| 235 |
'type' => 'array', |
| 236 |
'items' => array( |
| 237 |
'type' => 'object', |
| 238 |
'properties' => array( |
| 239 |
'module_id' => array( 'type' => 'string' ), |
| 240 |
'is_active' => array( 'type' => 'boolean' ), |
| 241 |
'is_pro' => array( 'type' => 'boolean' ), |
| 242 |
'section' => array( 'type' => 'string' ), |
| 243 |
), |
| 244 |
), |
| 245 |
), |
| 246 |
'total_count' => array( 'type' => 'integer' ), |
| 247 |
'active_count' => array( 'type' => 'integer' ), |
| 248 |
), |
| 249 |
), |
| 250 |
), |
| 251 |
), |
| 252 |
'permission_callback' => function () { |
| 253 |
return Merchant_Abilities_Permissions::check( 'merchant/list-modules' ); |
| 254 |
}, |
| 255 |
'execute_callback' => function ( $params = array() ) { |
| 256 |
$handler = new Merchant_List_Modules_Handler(); |
| 257 |
return $handler->handle( $params ); |
| 258 |
}, |
| 259 |
), |
| 260 |
'merchant/toggle-module' => array( |
| 261 |
'label' => __( 'Toggle Merchant Module', 'merchant' ), |
| 262 |
'description' => __( 'Activate or deactivate a Merchant module.', 'merchant' ), |
| 263 |
'category' => 'merchant', |
| 264 |
'meta' => array( |
| 265 |
'show_in_rest' => true, |
| 266 |
'annotations' => array( |
| 267 |
'readonly' => false, |
| 268 |
'destructive' => false, |
| 269 |
'idempotent' => true, |
| 270 |
), |
| 271 |
), |
| 272 |
'input_schema' => array( |
| 273 |
'type' => 'object', |
| 274 |
'additionalProperties' => false, |
| 275 |
'properties' => array( |
| 276 |
'module_id' => array( |
| 277 |
'type' => 'string', |
| 278 |
'minLength' => 1, |
| 279 |
'description' => 'The module identifier.', |
| 280 |
), |
| 281 |
'action' => array( |
| 282 |
'type' => 'string', |
| 283 |
'description' => 'activate or deactivate.', |
| 284 |
'enum' => array( 'activate', 'deactivate' ), |
| 285 |
), |
| 286 |
), |
| 287 |
'required' => array( 'module_id', 'action' ), |
| 288 |
), |
| 289 |
'output_schema' => array( |
| 290 |
'type' => 'object', |
| 291 |
'description' => 'Toggle result with before/after status.', |
| 292 |
'required' => array( 'success', 'data' ), |
| 293 |
'properties' => array( |
| 294 |
'success' => array( 'type' => 'boolean' ), |
| 295 |
'data' => array( |
| 296 |
'type' => 'object', |
| 297 |
'properties' => array( |
| 298 |
'module_id' => array( 'type' => 'string' ), |
| 299 |
'previous_status' => array( 'type' => 'string' ), |
| 300 |
'new_status' => array( 'type' => 'string' ), |
| 301 |
), |
| 302 |
), |
| 303 |
), |
| 304 |
), |
| 305 |
'permission_callback' => function () { |
| 306 |
return Merchant_Abilities_Permissions::check( 'merchant/toggle-module' ); |
| 307 |
}, |
| 308 |
'execute_callback' => function ( $params = array() ) { |
| 309 |
$handler = new Merchant_Toggle_Module_Handler(); |
| 310 |
return $handler->handle( $params ); |
| 311 |
}, |
| 312 |
), |
| 313 |
'merchant/get-module-settings' => array( |
| 314 |
'label' => __( 'Get Module Settings', 'merchant' ), |
| 315 |
'description' => __( 'Read a module\'s settings with full field schemas.', 'merchant' ), |
| 316 |
'category' => 'merchant', |
| 317 |
'meta' => array( |
| 318 |
'show_in_rest' => true, |
| 319 |
'annotations' => array( |
| 320 |
'readonly' => true, |
| 321 |
'destructive' => false, |
| 322 |
'idempotent' => true, |
| 323 |
), |
| 324 |
), |
| 325 |
'input_schema' => array( |
| 326 |
'type' => 'object', |
| 327 |
'additionalProperties' => false, |
| 328 |
'properties' => array( |
| 329 |
'module_id' => array( |
| 330 |
'type' => 'string', |
| 331 |
'minLength' => 1, |
| 332 |
'description' => 'The module identifier.', |
| 333 |
), |
| 334 |
'include_schema' => array( |
| 335 |
'type' => 'boolean', |
| 336 |
'description' => 'Include field schemas in response.', |
| 337 |
'default' => true, |
| 338 |
), |
| 339 |
), |
| 340 |
'required' => array( 'module_id' ), |
| 341 |
), |
| 342 |
'output_schema' => array( |
| 343 |
'type' => 'object', |
| 344 |
'properties' => array( |
| 345 |
'success' => array( 'type' => 'boolean' ), |
| 346 |
'data' => array( |
| 347 |
'type' => 'object', |
| 348 |
'properties' => array( |
| 349 |
'module_id' => array( 'type' => 'string' ), |
| 350 |
'is_active' => array( 'type' => 'boolean' ), |
| 351 |
'settings' => array( 'type' => 'object' ), |
| 352 |
), |
| 353 |
), |
| 354 |
), |
| 355 |
), |
| 356 |
'permission_callback' => function () { |
| 357 |
return Merchant_Abilities_Permissions::check( 'merchant/get-module-settings' ); |
| 358 |
}, |
| 359 |
'execute_callback' => function ( $params = array() ) use ( $registry ) { |
| 360 |
$handler = new Merchant_Get_Settings_Handler( $registry->get_schema_generator() ); |
| 361 |
return $handler->handle( $params ); |
| 362 |
}, |
| 363 |
), |
| 364 |
'merchant/update-module-settings' => array( |
| 365 |
'label' => __( 'Update Module Settings', 'merchant' ), |
| 366 |
'description' => __( 'Update a module\'s settings with validation and before/after reporting.', 'merchant' ), |
| 367 |
'category' => 'merchant', |
| 368 |
'meta' => array( |
| 369 |
'show_in_rest' => true, |
| 370 |
'annotations' => array( |
| 371 |
'readonly' => false, |
| 372 |
'destructive' => false, |
| 373 |
'idempotent' => true, |
| 374 |
), |
| 375 |
), |
| 376 |
'input_schema' => array( |
| 377 |
'type' => 'object', |
| 378 |
'additionalProperties' => false, |
| 379 |
'properties' => array( |
| 380 |
'module_id' => array( |
| 381 |
'type' => 'string', |
| 382 |
'minLength' => 1, |
| 383 |
'description' => 'The module identifier.', |
| 384 |
), |
| 385 |
'updates' => array( |
| 386 |
'type' => 'object', |
| 387 |
'description' => 'Key-value pairs of settings to update.', |
| 388 |
'maxProperties' => 50, |
| 389 |
), |
| 390 |
), |
| 391 |
'required' => array( 'module_id', 'updates' ), |
| 392 |
), |
| 393 |
'output_schema' => array( |
| 394 |
'type' => 'object', |
| 395 |
'properties' => array( |
| 396 |
'success' => array( 'type' => 'boolean' ), |
| 397 |
'data' => array( |
| 398 |
'type' => 'object', |
| 399 |
'properties' => array( |
| 400 |
'updated_fields' => array( 'type' => 'object' ), |
| 401 |
'updated_count' => array( 'type' => 'integer' ), |
| 402 |
), |
| 403 |
), |
| 404 |
'errors' => array( 'type' => 'array' ), |
| 405 |
'warnings' => array( 'type' => 'array' ), |
| 406 |
), |
| 407 |
), |
| 408 |
'permission_callback' => function () { |
| 409 |
return Merchant_Abilities_Permissions::check( 'merchant/update-module-settings' ); |
| 410 |
}, |
| 411 |
'execute_callback' => function ( $params = array() ) use ( $registry ) { |
| 412 |
$handler = new Merchant_Update_Settings_Handler( |
| 413 |
$registry->get_field_validator() |
| 414 |
); |
| 415 |
return $handler->handle( $params ); |
| 416 |
}, |
| 417 |
), |
| 418 |
'merchant/list-campaigns' => array( |
| 419 |
'label' => __( 'List Module Campaigns', 'merchant' ), |
| 420 |
'description' => __( 'List campaigns with configuration summaries and analytics snapshots.', 'merchant' ), |
| 421 |
'category' => 'merchant', |
| 422 |
'meta' => array( |
| 423 |
'show_in_rest' => true, |
| 424 |
'annotations' => array( |
| 425 |
'readonly' => true, |
| 426 |
'destructive' => false, |
| 427 |
'idempotent' => true, |
| 428 |
), |
| 429 |
), |
| 430 |
'input_schema' => array( |
| 431 |
'type' => 'object', |
| 432 |
'additionalProperties' => false, |
| 433 |
'properties' => array( |
| 434 |
'module_id' => array( |
| 435 |
'type' => 'string', |
| 436 |
'minLength' => 1, |
| 437 |
'description' => 'The module identifier.', |
| 438 |
), |
| 439 |
), |
| 440 |
'required' => array( 'module_id' ), |
| 441 |
), |
| 442 |
'output_schema' => array( |
| 443 |
'type' => 'object', |
| 444 |
'properties' => array( |
| 445 |
'success' => array( 'type' => 'boolean' ), |
| 446 |
'data' => array( |
| 447 |
'type' => 'object', |
| 448 |
'properties' => array( |
| 449 |
'module_id' => array( 'type' => 'string' ), |
| 450 |
'campaigns' => array( |
| 451 |
'type' => 'array', |
| 452 |
'items' => array( |
| 453 |
'type' => 'object', |
| 454 |
'properties' => array( |
| 455 |
'index' => array( 'type' => 'integer' ), |
| 456 |
'name' => array( 'type' => 'string' ), |
| 457 |
'summary' => array( 'type' => 'object' ), |
| 458 |
), |
| 459 |
), |
| 460 |
), |
| 461 |
'total_count' => array( 'type' => 'integer' ), |
| 462 |
'field_schema' => array( |
| 463 |
'type' => 'object', |
| 464 |
'description' => 'Per-field JSON schema for this module\'s campaign layout, including x-merchant-* AI guidance.', |
| 465 |
), |
| 466 |
), |
| 467 |
), |
| 468 |
), |
| 469 |
), |
| 470 |
'permission_callback' => function () { |
| 471 |
return Merchant_Abilities_Permissions::check( 'merchant/list-campaigns' ); |
| 472 |
}, |
| 473 |
'execute_callback' => function ( $params = array() ) use ( $registry ) { |
| 474 |
$handler = new Merchant_List_Campaigns_Handler( $registry ); |
| 475 |
return $handler->handle( $params ); |
| 476 |
}, |
| 477 |
), |
| 478 |
'merchant/create-campaign' => array( |
| 479 |
'label' => __( 'Create Campaign', 'merchant' ), |
| 480 |
'description' => __( 'Create a new campaign with defaults and validation. Call merchant/list-campaigns or merchant/get-module-settings (include_schema=true) first to read the field contract and per-field usage hints.', 'merchant' ), |
| 481 |
'category' => 'merchant', |
| 482 |
'meta' => array( |
| 483 |
'show_in_rest' => true, |
| 484 |
'annotations' => array( |
| 485 |
'readonly' => false, |
| 486 |
'destructive' => false, |
| 487 |
'idempotent' => false, |
| 488 |
), |
| 489 |
), |
| 490 |
'input_schema' => array( |
| 491 |
'type' => 'object', |
| 492 |
'additionalProperties' => false, |
| 493 |
'properties' => array( |
| 494 |
'module_id' => array( |
| 495 |
'type' => 'string', |
| 496 |
'minLength' => 1, |
| 497 |
'description' => 'The module identifier.', |
| 498 |
), |
| 499 |
'campaign' => array( |
| 500 |
'type' => 'object', |
| 501 |
'description' => 'Campaign data to create.', |
| 502 |
'maxProperties' => 50, |
| 503 |
), |
| 504 |
), |
| 505 |
'required' => array( 'module_id' ), |
| 506 |
), |
| 507 |
'output_schema' => array( |
| 508 |
'type' => 'object', |
| 509 |
'properties' => array( |
| 510 |
'success' => array( 'type' => 'boolean' ), |
| 511 |
'data' => array( |
| 512 |
'type' => 'object', |
| 513 |
'properties' => array( |
| 514 |
'module_id' => array( 'type' => 'string' ), |
| 515 |
'index' => array( 'type' => 'integer' ), |
| 516 |
'campaign' => array( 'type' => 'object' ), |
| 517 |
), |
| 518 |
), |
| 519 |
), |
| 520 |
), |
| 521 |
'permission_callback' => function () { |
| 522 |
return Merchant_Abilities_Permissions::check( 'merchant/create-campaign' ); |
| 523 |
}, |
| 524 |
'execute_callback' => function ( $params = array() ) use ( $registry ) { |
| 525 |
$handler = new Merchant_Create_Campaign_Handler( |
| 526 |
$registry, |
| 527 |
$registry->get_field_validator() |
| 528 |
); |
| 529 |
return $handler->handle( $params ); |
| 530 |
}, |
| 531 |
), |
| 532 |
'merchant/update-campaign' => array( |
| 533 |
'label' => __( 'Update Campaign', 'merchant' ), |
| 534 |
'description' => __( 'Update specific fields of an existing campaign with validation and diff reporting. Call merchant/list-campaigns or merchant/get-module-settings (include_schema=true) first to read the field contract and per-field usage hints.', 'merchant' ), |
| 535 |
'category' => 'merchant', |
| 536 |
'meta' => array( |
| 537 |
'show_in_rest' => true, |
| 538 |
'annotations' => array( |
| 539 |
'readonly' => false, |
| 540 |
'destructive' => false, |
| 541 |
'idempotent' => true, |
| 542 |
), |
| 543 |
), |
| 544 |
'input_schema' => array( |
| 545 |
'type' => 'object', |
| 546 |
'additionalProperties' => false, |
| 547 |
'properties' => array( |
| 548 |
'module_id' => array( |
| 549 |
'type' => 'string', |
| 550 |
'minLength' => 1, |
| 551 |
'description' => 'The module identifier.', |
| 552 |
), |
| 553 |
'campaign_identifier' => array( |
| 554 |
'type' => 'string', |
| 555 |
'minLength' => 1, |
| 556 |
'description' => 'Campaign flexible_id UUID, numeric index (0-based), or campaign name.', |
| 557 |
), |
| 558 |
'updates' => array( |
| 559 |
'type' => 'object', |
| 560 |
'description' => 'Key-value pairs to update.', |
| 561 |
), |
| 562 |
), |
| 563 |
'required' => array( 'module_id', 'campaign_identifier', 'updates' ), |
| 564 |
), |
| 565 |
'output_schema' => array( |
| 566 |
'type' => 'object', |
| 567 |
'description' => 'Update result with before/after diff and optional validation warnings.', |
| 568 |
'required' => array( 'success', 'data' ), |
| 569 |
'properties' => array( |
| 570 |
'success' => array( 'type' => 'boolean' ), |
| 571 |
'data' => array( |
| 572 |
'type' => 'object', |
| 573 |
'properties' => array( |
| 574 |
'module_id' => array( 'type' => 'string' ), |
| 575 |
'campaign_index' => array( 'type' => 'integer' ), |
| 576 |
'updated_fields' => array( 'type' => 'object' ), |
| 577 |
), |
| 578 |
), |
| 579 |
'warnings' => array( 'type' => 'array' ), |
| 580 |
), |
| 581 |
), |
| 582 |
'permission_callback' => function () { |
| 583 |
return Merchant_Abilities_Permissions::check( 'merchant/update-campaign' ); |
| 584 |
}, |
| 585 |
'execute_callback' => function ( $params = array() ) use ( $registry ) { |
| 586 |
$handler = new Merchant_Update_Campaign_Handler( |
| 587 |
$registry->get_campaign_resolver(), |
| 588 |
$registry, |
| 589 |
$registry->get_field_validator() |
| 590 |
); |
| 591 |
return $handler->handle( $params ); |
| 592 |
}, |
| 593 |
), |
| 594 |
'merchant/delete-campaign' => array( |
| 595 |
'label' => __( 'Delete Campaign', 'merchant' ), |
| 596 |
'description' => __( 'Delete a campaign with confirmation guard.', 'merchant' ), |
| 597 |
'category' => 'merchant', |
| 598 |
'meta' => array( |
| 599 |
'show_in_rest' => true, |
| 600 |
'annotations' => array( |
| 601 |
'readonly' => false, |
| 602 |
'destructive' => true, |
| 603 |
'idempotent' => true, |
| 604 |
), |
| 605 |
), |
| 606 |
'input_schema' => array( |
| 607 |
'type' => 'object', |
| 608 |
'additionalProperties' => false, |
| 609 |
'properties' => array( |
| 610 |
'module_id' => array( |
| 611 |
'type' => 'string', |
| 612 |
'minLength' => 1, |
| 613 |
'description' => 'The module identifier.', |
| 614 |
), |
| 615 |
'campaign_identifier' => array( |
| 616 |
'type' => 'string', |
| 617 |
'minLength' => 1, |
| 618 |
'description' => 'Campaign flexible_id UUID. Use merchant/list-campaigns to find it.', |
| 619 |
), |
| 620 |
'confirm' => array( |
| 621 |
'type' => 'boolean', |
| 622 |
'description' => 'Confirmation guard.', |
| 623 |
'default' => false, |
| 624 |
), |
| 625 |
), |
| 626 |
'required' => array( 'module_id', 'campaign_identifier', 'confirm' ), |
| 627 |
), |
| 628 |
'output_schema' => array( |
| 629 |
'type' => 'object', |
| 630 |
'properties' => array( |
| 631 |
'success' => array( 'type' => 'boolean' ), |
| 632 |
'data' => array( |
| 633 |
'type' => 'object', |
| 634 |
'properties' => array( |
| 635 |
'module_id' => array( 'type' => 'string' ), |
| 636 |
'deleted_index' => array( 'type' => 'integer' ), |
| 637 |
'deleted_name' => array( 'type' => 'string' ), |
| 638 |
'remaining_campaigns_count' => array( 'type' => 'integer' ), |
| 639 |
), |
| 640 |
), |
| 641 |
), |
| 642 |
), |
| 643 |
'permission_callback' => function () { |
| 644 |
return Merchant_Abilities_Permissions::check( 'merchant/delete-campaign' ); |
| 645 |
}, |
| 646 |
'execute_callback' => function ( $params = array() ) use ( $registry ) { |
| 647 |
$handler = new Merchant_Delete_Campaign_Handler( |
| 648 |
$registry->get_campaign_resolver(), |
| 649 |
$registry |
| 650 |
); |
| 651 |
return $handler->handle( $params ); |
| 652 |
}, |
| 653 |
), |
| 654 |
'merchant/get-analytics' => array( |
| 655 |
'label' => __( 'Get Analytics', 'merchant' ), |
| 656 |
'description' => __( 'View analytics at global, module, or campaign scope.', 'merchant' ), |
| 657 |
'category' => 'merchant', |
| 658 |
'meta' => array( |
| 659 |
'show_in_rest' => true, |
| 660 |
'annotations' => array( |
| 661 |
'readonly' => true, |
| 662 |
'destructive' => false, |
| 663 |
'idempotent' => true, |
| 664 |
), |
| 665 |
), |
| 666 |
'input_schema' => array( |
| 667 |
'type' => 'object', |
| 668 |
'additionalProperties' => false, |
| 669 |
'properties' => array( |
| 670 |
'scope' => array( |
| 671 |
'type' => 'string', |
| 672 |
'description' => 'Analytics scope: global, module, or campaign.', |
| 673 |
'enum' => array( 'global', 'module', 'campaign' ), |
| 674 |
'default' => 'global', |
| 675 |
), |
| 676 |
'module_id' => array( |
| 677 |
'type' => 'string', |
| 678 |
'description' => 'Module identifier (required for module/campaign scope).', |
| 679 |
), |
| 680 |
'campaign_id' => array( |
| 681 |
'type' => 'string', |
| 682 |
'description' => 'Campaign identifier (required for campaign scope).', |
| 683 |
), |
| 684 |
), |
| 685 |
), |
| 686 |
'output_schema' => array( |
| 687 |
'type' => 'object', |
| 688 |
'properties' => array( |
| 689 |
'success' => array( 'type' => 'boolean' ), |
| 690 |
'data' => array( |
| 691 |
'type' => 'object', |
| 692 |
'properties' => array( |
| 693 |
'scope' => array( 'type' => 'string' ), |
| 694 |
'metrics' => array( 'type' => 'object' ), |
| 695 |
'module_id' => array( 'type' => 'string' ), |
| 696 |
'campaign_id' => array( 'type' => 'string' ), |
| 697 |
), |
| 698 |
), |
| 699 |
), |
| 700 |
), |
| 701 |
'permission_callback' => function () { |
| 702 |
return Merchant_Abilities_Permissions::check( 'merchant/get-analytics' ); |
| 703 |
}, |
| 704 |
'execute_callback' => function ( $params = array() ) { |
| 705 |
$handler = new Merchant_Get_Analytics_Handler(); |
| 706 |
return $handler->handle( $params ); |
| 707 |
}, |
| 708 |
), |
| 709 |
'merchant/get-recommendations' => array( |
| 710 |
'label' => __( 'Get Recommendations', 'merchant' ), |
| 711 |
'description' => __( 'Get optimization recommendations based on analytics data.', 'merchant' ), |
| 712 |
'category' => 'merchant', |
| 713 |
'meta' => array( |
| 714 |
'show_in_rest' => true, |
| 715 |
'annotations' => array( |
| 716 |
'readonly' => true, |
| 717 |
'destructive' => false, |
| 718 |
'idempotent' => true, |
| 719 |
), |
| 720 |
), |
| 721 |
'input_schema' => array( |
| 722 |
'type' => 'object', |
| 723 |
'additionalProperties' => false, |
| 724 |
'properties' => array( |
| 725 |
'module_id' => array( |
| 726 |
'type' => 'string', |
| 727 |
'description' => 'Optional. Limit recommendations to a specific module.', |
| 728 |
), |
| 729 |
'focus' => array( |
| 730 |
'type' => 'string', |
| 731 |
'description' => 'Recommendation focus area.', |
| 732 |
'enum' => array( 'conversion', 'revenue', 'engagement', 'general' ), |
| 733 |
'default' => 'general', |
| 734 |
), |
| 735 |
'date_range' => array( |
| 736 |
'type' => 'object', |
| 737 |
'description' => 'Optional date range for recommendations. Defaults to last 30 days.', |
| 738 |
'properties' => array( |
| 739 |
'start' => array( |
| 740 |
'type' => 'string', |
| 741 |
'description' => 'Start date (Y-m-d or m/d/y).', |
| 742 |
), |
| 743 |
'end' => array( |
| 744 |
'type' => 'string', |
| 745 |
'description' => 'End date (Y-m-d or m/d/y).', |
| 746 |
), |
| 747 |
), |
| 748 |
), |
| 749 |
), |
| 750 |
), |
| 751 |
'output_schema' => array( |
| 752 |
'type' => 'object', |
| 753 |
'properties' => array( |
| 754 |
'success' => array( 'type' => 'boolean' ), |
| 755 |
'data' => array( |
| 756 |
'type' => 'object', |
| 757 |
'properties' => array( |
| 758 |
'recommendations' => array( |
| 759 |
'type' => 'array', |
| 760 |
'items' => array( |
| 761 |
'type' => 'object', |
| 762 |
'properties' => array( |
| 763 |
'flag' => array( 'type' => 'string' ), |
| 764 |
'severity' => array( 'type' => 'string' ), |
| 765 |
'module_id' => array( 'type' => 'string' ), |
| 766 |
'context' => array( 'type' => 'string' ), |
| 767 |
'metrics' => array( 'type' => 'object' ), |
| 768 |
), |
| 769 |
), |
| 770 |
), |
| 771 |
'total_recommendations' => array( 'type' => 'integer' ), |
| 772 |
), |
| 773 |
), |
| 774 |
), |
| 775 |
), |
| 776 |
'permission_callback' => function () { |
| 777 |
return Merchant_Abilities_Permissions::check( 'merchant/get-recommendations' ); |
| 778 |
}, |
| 779 |
'execute_callback' => function ( $params = array() ) use ( $registry ) { |
| 780 |
$handler = new Merchant_Get_Recommendations_Handler( $registry ); |
| 781 |
return $handler->handle( $params ); |
| 782 |
}, |
| 783 |
), |
| 784 |
); |
| 785 |
} |
| 786 |
} |
| 787 |
|