| [ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * Entity Actions API: WP_Entity_Actions_Registry class 4 * 5 * @package WordPress 6 * @subpackage Entity Actions 7 * @since 7.2.0 8 */ 9 10 /** 11 * Holds the actions registered for entities. 12 * 13 * The registry maps an entity, identified by its kind and name, to its 14 * registered action definitions keyed by id, in registration order, each 15 * with the origin that registered it, and to the script modules registered 16 * for it, each with the ids of the actions it applies to. register() adds 17 * actions and validates the definitions before storing them: an action 18 * that cannot be stored is reported and skipped, and the rest of the call 19 * is stored. To change a registered action, unregister it and register it 20 * again. 21 * 22 * Actions are registered on the `wp_entity_actions_api_init` action, and only 23 * there, with wp_register_entity_actions() and wp_unregister_entity_actions(): 24 * register() and unregister() refuse to run while the action is not 25 * firing. 26 * 27 * The registry is filled lazily: the first time its actions are read, it 28 * fires the `wp_entity_actions_api_init` action, on which the actions of every 29 * entity are registered. A read before `init` has completed is refused, 30 * see initialize(). 31 * 32 * Once the action has fired the registry does not change: every reader of 33 * a request, the REST controller as well as the import map of the editor 34 * script, sees the same actions. 35 * 36 * @since 7.2.0 37 * 38 * @access private 39 */ 40 class WP_Entity_Actions_Registry { 41 42 /** 43 * The values DataViews supports for the properties of an action that 44 * take one of a set of values, see packages/dataviews/src/types/dataviews.ts. 45 * 46 * @since 7.2.0 47 * 48 * @var array<string, string[]> 49 */ 50 const SUPPORTED_VALUES = array( 51 'context' => array( 'list' ), 52 'modalSize' => array( 'small', 'medium', 'large', 'fill' ), 53 ); 54 55 /** 56 * Registered actions, as kind => name => array of action id => definition. 57 * 58 * Kept nested rather than under a joined `{$kind}/{$name}` key: both parts 59 * may contain any character, so no separator keeps two entities apart. 60 * 61 * @since 7.2.0 62 * 63 * @var array<string, array<string, array<string, array>>> 64 */ 65 protected $actions = array(); 66 67 /** 68 * Registered script modules, as kind => name => array of module id => 69 * list of the ids of the actions the module applies to, in registration 70 * order. 71 * 72 * @since 7.2.0 73 * 74 * @var array<string, array<string, array<string, string[]>>> 75 */ 76 protected $action_modules = array(); 77 78 /** 79 * Whether the `wp_entity_actions_api_init` action has fired since the registry 80 * was created. 81 * 82 * @since 7.2.0 83 * 84 * @var bool 85 */ 86 protected $initialized = false; 87 88 /** 89 * Whether the registry is firing the `wp_entity_actions_api_init` action, the 90 * only time register() and unregister() run. 91 * 92 * @since 7.2.0 93 * 94 * @var bool 95 */ 96 protected $initializing = false; 97 98 /** 99 * The singleton instance. 100 * 101 * @since 7.2.0 102 * 103 * @var WP_Entity_Actions_Registry|null 104 */ 105 protected static $instance = null; 106 107 /** 108 * Returns the singleton instance. 109 * 110 * @since 7.2.0 111 * 112 * @return WP_Entity_Actions_Registry The registry. 113 */ 114 public static function get_instance() { 115 if ( null === self::$instance ) { 116 self::$instance = new self(); 117 } 118 119 return self::$instance; 120 } 121 122 /** 123 * Registers actions for an entity. 124 * 125 * The actions must be new: an action with the id of a registered action 126 * is reported and skipped, and so is every definition after the first of 127 * an id that appears more than once in the call. The rest of the actions 128 * of the call are registered: an action another plugin got to first does 129 * not cost a plugin the others. A definition that is not an array with a 130 * non-empty string `id` is reported and skipped the same way. To replace 131 * a registered action, unregister it first. The script module, if any, 132 * applies to every action the call registers. 133 * 134 * A value DataViews does not support is reported, and a property only a 135 * script module can provide is reported and removed, see 136 * report_invalid_values(). 137 * 138 * The origin is stored as the `origin` property of each action, as 139 * `registeredBy`, replacing any `origin` the definition sets. 140 * 141 * @since 7.2.0 142 * 143 * @param string $origin Who registers the actions: `core`, or 144 * the slug of the plugin or theme. 145 * @param string $kind The entity kind (e.g. `postType`). 146 * @param string $name The entity name (e.g. `page`). 147 * @param array[] $actions The list of action definitions, each with an `id`. 148 * @param string|null $script_module The id of the script module providing 149 * the JavaScript parts of the actions, if any. 150 * @return string[] The ids of the actions registered, in the order of the 151 * call. Empty when none is, when called outside the 152 * `wp_entity_actions_api_init` action, or when an argument is 153 * invalid. 154 */ 155 public function register( $origin, $kind, $name, $actions, $script_module = null ) { 156 if ( ! $this->validate_arguments( __METHOD__, $origin, $kind, $name, $actions, $script_module ) ) { 157 return array(); 158 } 159 $actions = $this->skip_invalid_definitions( __METHOD__, $kind, $name, $actions ); 160 if ( ! $actions ) { 161 return array(); 162 } 163 164 $new_actions = array(); 165 $duplicated = array(); 166 $registered_ids = array(); 167 foreach ( $actions as $action ) { 168 $id = $action['id']; 169 if ( isset( $this->actions[ $kind ][ $name ][ $id ] ) ) { 170 $registered_ids[ $id ] = $id; 171 } elseif ( isset( $new_actions[ $id ] ) ) { 172 $duplicated[ $id ] = $id; 173 } else { 174 $new_actions[ $id ] = $action; 175 } 176 } 177 178 if ( $duplicated ) { 179 _doing_it_wrong( 180 __METHOD__, 181 sprintf( 182 /* translators: 1: Entity kind, e.g. postType. 2: Entity name, e.g. page. 3: Comma-separated list of action ids. */ 183 __( 'An action can only be registered once. These actions of %1$s "%2$s" appear more than once in the same call: %3$s. Only their first definition is registered.' ), 184 $kind, 185 $name, 186 implode( ', ', $duplicated ) 187 ), 188 '7.2.0' 189 ); 190 } 191 192 if ( $registered_ids ) { 193 _doing_it_wrong( 194 __METHOD__, 195 sprintf( 196 /* translators: 1: Entity kind, e.g. postType. 2: Entity name, e.g. page. 3: Comma-separated list of action ids. */ 197 __( 'An action can only be registered once. These actions of %1$s "%2$s" are skipped because they are already registered: %3$s. Unregister an action first to replace it.' ), 198 $kind, 199 $name, 200 implode( ', ', $registered_ids ) 201 ), 202 '7.2.0' 203 ); 204 } 205 206 if ( ! $new_actions ) { 207 return array(); 208 } 209 $new_actions = $this->report_invalid_values( __METHOD__, $kind, $name, $new_actions ); 210 211 foreach ( $new_actions as $action ) { 212 $this->actions[ $kind ][ $name ][ $action['id'] ] = array_merge( 213 $action, 214 array( 215 'origin' => array( 216 'registeredBy' => $origin, 217 ), 218 ) 219 ); 220 } 221 $ids = array_column( $new_actions, 'id' ); 222 $this->add_action_module( $kind, $name, $ids, $script_module ); 223 224 return $ids; 225 } 226 227 /** 228 * Reports the values of action definitions that DataViews does not 229 * support, and the properties only a script module can provide, with 230 * _doing_it_wrong(). 231 * 232 * A value DataViews does not support is otherwise silent: an action 233 * whose `context` is not `list` shows on no screen. Such a value is 234 * kept, like the field types the fields registry reports. 235 * `callback`, `RenderModal`, and `isEligible` are functions and 236 * components, which only a script module can provide: a value set on 237 * the server would be called on the client and fail, so it is removed. 238 * 239 * @since 7.2.0 240 * 241 * @param string $method The calling method, for the notice. 242 * @param string $kind The entity kind. 243 * @param string $name The entity name. 244 * @param array[] $actions The action definitions, keyed by id. 245 * @return array[] The definitions, without the properties only a script 246 * module can provide. 247 */ 248 protected function report_invalid_values( $method, $kind, $name, $actions ) { 249 $invalid = array(); 250 foreach ( $actions as $id => $action ) { 251 foreach ( self::SUPPORTED_VALUES as $property => $values ) { 252 if ( array_key_exists( $property, $action ) && ! in_array( $action[ $property ], $values, true ) ) { 253 $invalid[] = sprintf( 254 '%1$s (%2$s)', 255 $id, 256 wp_sprintf( 257 /* translators: 1: Property name, e.g. context. 2: List of the values DataViews supports. */ 258 __( '%1$s is not one of %2$l.' ), 259 $property, 260 $values 261 ) 262 ); 263 } 264 } 265 foreach ( array( 'callback', 'RenderModal', 'isEligible' ) as $property ) { 266 if ( array_key_exists( $property, $action ) ) { 267 unset( $actions[ $id ][ $property ] ); 268 $invalid[] = sprintf( 269 /* translators: 1: Action id. 2: Property name, e.g. callback. */ 270 __( '%1$s (%2$s can only come from a script module, so it is removed.)' ), 271 $id, 272 $property 273 ); 274 } 275 } 276 } 277 if ( $invalid ) { 278 _doing_it_wrong( 279 $method, 280 sprintf( 281 /* translators: 1: Entity kind, e.g. postType. 2: Entity name, e.g. page. 3: Comma-separated list of action ids, each with the error of a value. */ 282 __( 'These actions of %1$s "%2$s" have values DataViews does not support: %3$s' ), 283 $kind, 284 $name, 285 implode( ', ', $invalid ) 286 ), 287 '7.2.0' 288 ); 289 } 290 291 return $actions; 292 } 293 294 /** 295 * Unregisters actions of an entity. 296 * 297 * Unregistering an action removes its registered definition and drops 298 * it from the script modules that applied to it (a module left with no 299 * action is forgotten). Unregistering every action forgets the entity: 300 * its registered actions and script modules. 301 * 302 * Like register(), it only runs on the `wp_entity_actions_api_init` action, and 303 * an invalid entity is reported and unregisters nothing. An id that is 304 * not a non-empty string is reported and skipped, like a definition 305 * register() cannot store. 306 * 307 * @since 7.2.0 308 * 309 * @param string $kind The entity kind (e.g. `postType`). 310 * @param string $name The entity name (e.g. `page`). 311 * @param string[]|null $ids The ids of the actions to unregister. 312 * Default null, every action of the entity. 313 * @return array[] The list of the definitions unregistered, in 314 * registration order, as get_registered() returns them. 315 * Empty when none of the actions is registered, when 316 * called outside the `wp_entity_actions_api_init` action, or 317 * when the entity is invalid. 318 */ 319 public function unregister( $kind, $name, $ids = null ) { 320 if ( ! $this->doing_entity_actions_api_init( __METHOD__ ) || ! $this->validate_entity( __METHOD__, $kind, $name ) ) { 321 return array(); 322 } 323 324 if ( null === $ids ) { 325 $unregistered = array_values( $this->actions[ $kind ][ $name ] ?? array() ); 326 unset( $this->actions[ $kind ][ $name ], $this->action_modules[ $kind ][ $name ] ); 327 $this->forget_empty_entity( $kind, $name ); 328 return $unregistered; 329 } 330 331 $ids = $this->skip_invalid_ids( __METHOD__, $kind, $name, (array) $ids ); 332 if ( ! $ids ) { 333 return array(); 334 } 335 336 $unregistered = array_intersect_key( $this->actions[ $kind ][ $name ] ?? array(), array_flip( $ids ) ); 337 if ( empty( $unregistered ) ) { 338 return array(); 339 } 340 341 // A script module only ever applies to registered actions: register() 342 // adds it for the actions it stores, and actions leave both lists 343 // together here. So the actions removed are all the registry loses, 344 // and the modules are not returned: the ones that applied to them are 345 // listed by get_registered_action_modules(), read beforehand. 346 $ids = array_keys( $unregistered ); 347 foreach ( $ids as $id ) { 348 unset( $this->actions[ $kind ][ $name ][ $id ] ); 349 } 350 foreach ( $this->action_modules[ $kind ][ $name ] ?? array() as $module => $module_ids ) { 351 $remaining = array_values( array_diff( $module_ids, $ids ) ); 352 if ( empty( $remaining ) ) { 353 unset( $this->action_modules[ $kind ][ $name ][ $module ] ); 354 } else { 355 $this->action_modules[ $kind ][ $name ][ $module ] = $remaining; 356 } 357 } 358 $this->forget_empty_entity( $kind, $name ); 359 360 return array_values( $unregistered ); 361 } 362 363 /** 364 * Returns the actions registered for an entity. 365 * 366 * @since 7.2.0 367 * 368 * @param string $kind The entity kind (e.g. `postType`). 369 * @param string $name The entity name (e.g. `page`). 370 * @return array[] The list of action definitions, in registration order. 371 * Empty when the entity is invalid. 372 */ 373 public function get_registered( $kind, $name ) { 374 if ( ! $this->validate_entity( __METHOD__, $kind, $name ) ) { 375 return array(); 376 } 377 $this->initialize(); 378 return array_values( $this->actions[ $kind ][ $name ] ?? array() ); 379 } 380 381 /** 382 * Returns the actions registered for every entity. 383 * 384 * @since 7.2.0 385 * 386 * @return array<string, array<string, array[]>> The lists of action 387 * definitions, keyed by 388 * kind, then by name. 389 */ 390 public function get_all_registered() { 391 $this->initialize(); 392 return array_map( 393 static function ( $entities ) { 394 return array_map( 'array_values', $entities ); 395 }, 396 $this->actions 397 ); 398 } 399 400 /** 401 * Returns the script modules registered for an entity. 402 * 403 * @since 7.2.0 404 * 405 * @param string $kind The entity kind (e.g. `postType`). 406 * @param string $name The entity name (e.g. `page`). 407 * @return array[] { 408 * The script modules, in registration order. Empty when the entity 409 * is invalid. 410 * 411 * @type array ...$0 { 412 * @type string $id The id of the script module. 413 * @type string[] $actions The ids of the actions the module 414 * applies to, in registration order. 415 * } 416 * } 417 */ 418 public function get_registered_action_modules( $kind, $name ) { 419 if ( ! $this->validate_entity( __METHOD__, $kind, $name ) ) { 420 return array(); 421 } 422 $this->initialize(); 423 $modules = array(); 424 foreach ( $this->action_modules[ $kind ][ $name ] ?? array() as $module => $action_ids ) { 425 $modules[] = array( 426 // A numeric module id is an integer as an array key. 427 'id' => (string) $module, 428 'actions' => $action_ids, 429 ); 430 } 431 return $modules; 432 } 433 434 /** 435 * Returns the ids of the script modules registered for every entity. 436 * 437 * @since 7.2.0 438 * 439 * @return array<string, array<string, string[]>> The lists of module ids, 440 * keyed by kind, then by 441 * name. 442 */ 443 public function get_all_registered_action_modules() { 444 $this->initialize(); 445 return array_map( 446 static function ( $entities ) { 447 return array_map( 448 static function ( $modules ) { 449 // A numeric module id is an integer as an array key. 450 return array_map( 'strval', array_keys( $modules ) ); 451 }, 452 $entities 453 ); 454 }, 455 $this->action_modules 456 ); 457 } 458 459 /** 460 * Fires the `wp_entity_actions_api_init` action the first time the registry 461 * is read. 462 * 463 * The read is refused until `init` has completed. The registry holds the 464 * actions of post types, and post types are not known until then: core 465 * registers its own on `init` at priority 0, plugins theirs at the 466 * default priority, and supports are added and removed on `init` too. 467 * The actions of a post type can derive from its supports, and the 468 * action fires once, so a read before or during `init` would fix them 469 * from the post types registered so far for the rest of the request. 470 * 471 * did_action() is true from the first `init` callback on, hence the 472 * doing_action() check for the reads made while it runs. 473 * 474 * @since 7.2.0 475 */ 476 protected function initialize() { 477 if ( $this->initialized ) { 478 return; 479 } 480 481 if ( ! did_action( 'init' ) || doing_action( 'init' ) ) { 482 _doing_it_wrong( 483 __METHOD__, 484 __( 'The registered actions cannot be read until the `init` action has completed: the post types and supports they derive from are registered on `init`. Read them once `init` has completed, or hook `wp_entity_actions_api_init`.' ), 485 '7.2.0' 486 ); 487 return; 488 } 489 490 // Set before firing, so a callback reading the registry to inspect 491 // the actions it unregisters does not fire the action again. 492 $this->initialized = true; 493 494 $this->initializing = true; 495 try { 496 /** 497 * Fires the first time the registered actions are read, after `init`. 498 * 499 * Register or remove actions here, with wp_register_entity_actions() and 500 * wp_unregister_entity_actions(): it is the only time they run. 501 * 502 * The first read happens wherever the actions are needed: while 503 * handling a REST request as well as on `admin_footer` of the pages 504 * that load the editor script. A callback should register actions 505 * and nothing else; script modules, styles, and their enqueue hooks 506 * belong on `init`. 507 * 508 * @since 7.2.0 509 */ 510 do_action( 'wp_entity_actions_api_init' ); 511 } finally { 512 $this->initializing = false; 513 } 514 } 515 516 /** 517 * Checks that the registry is firing the `wp_entity_actions_api_init` action, 518 * as register() and unregister() require. 519 * 520 * Outside the action a registration would either come before the 521 * registrations made on it, and take the ids they register, or after 522 * the actions have been read and the import map of the editor script 523 * built from them. Refusing keeps the registry immutable once read, 524 * even when the action is fired again with do_action(), which is why 525 * the registry tracks its own firing rather than check doing_action(). 526 * 527 * @since 7.2.0 528 * 529 * @param string $method The calling method, for the notice. 530 * @return bool Whether the action is firing. 531 */ 532 protected function doing_entity_actions_api_init( $method ) { 533 if ( $this->initializing ) { 534 return true; 535 } 536 537 _doing_it_wrong( 538 $method, 539 __( 'Actions can only be registered and unregistered on the `wp_entity_actions_api_init` action.' ), 540 '7.2.0' 541 ); 542 return false; 543 } 544 545 /** 546 * Validates the arguments of register(). 547 * 548 * @since 7.2.0 549 * 550 * @param string $method The calling method, for the notice. 551 * @param mixed $origin The origin. 552 * @param mixed $kind The entity kind. 553 * @param mixed $name The entity name. 554 * @param mixed $actions The action definitions. 555 * @param mixed $script_module The script module id, if any. 556 * @return bool Whether the call may proceed: the `wp_entity_actions_api_init` 557 * action is firing and the arguments are valid. 558 */ 559 protected function validate_arguments( $method, $origin, $kind, $name, $actions, $script_module ) { 560 if ( ! $this->doing_entity_actions_api_init( $method ) ) { 561 return false; 562 } 563 564 if ( ! is_string( $origin ) || '' === $origin ) { 565 _doing_it_wrong( 566 $method, 567 __( 'The origin must be a non-empty string.' ), 568 '7.2.0' 569 ); 570 return false; 571 } 572 573 if ( ! $this->validate_entity( $method, $kind, $name ) ) { 574 return false; 575 } 576 577 if ( ! is_array( $actions ) || empty( $actions ) || ! array_is_list( $actions ) ) { 578 _doing_it_wrong( 579 $method, 580 __( 'The actions must be a list of non-empty action definitions.' ), 581 '7.2.0' 582 ); 583 return false; 584 } 585 586 if ( null !== $script_module && ( ! is_string( $script_module ) || '' === $script_module ) ) { 587 _doing_it_wrong( 588 $method, 589 __( 'The script module must be the id of a script module.' ), 590 '7.2.0' 591 ); 592 return false; 593 } 594 595 return true; 596 } 597 598 /** 599 * Checks that the entity kind and name are non-empty strings, reporting 600 * them with _doing_it_wrong() otherwise. 601 * 602 * @since 7.2.0 603 * 604 * @param string $method The calling method, for the notice. 605 * @param mixed $kind The entity kind. 606 * @param mixed $name The entity name. 607 * @return bool Whether both are valid. 608 */ 609 protected function validate_entity( $method, $kind, $name ) { 610 foreach ( array( $kind, $name ) as $argument ) { 611 if ( ! is_string( $argument ) || '' === $argument ) { 612 _doing_it_wrong( 613 $method, 614 __( 'The entity kind and the entity name must be non-empty strings.' ), 615 '7.2.0' 616 ); 617 return false; 618 } 619 } 620 return true; 621 } 622 623 /** 624 * Drops the definitions that are not an array with a non-empty string 625 * `id`, reporting their positions in the call with _doing_it_wrong(): 626 * like a duplicated action, an invalid definition does not cost the call 627 * its other actions. 628 * 629 * @since 7.2.0 630 * 631 * @param string $method The calling method, for the notice. 632 * @param string $kind The entity kind. 633 * @param string $name The entity name. 634 * @param array[] $actions The list of action definitions. 635 * @return array[] The valid definitions, in the order of the call. 636 */ 637 protected function skip_invalid_definitions( $method, $kind, $name, $actions ) { 638 $valid = array(); 639 $invalid = array(); 640 foreach ( $actions as $position => $action ) { 641 if ( is_array( $action ) && isset( $action['id'] ) && is_string( $action['id'] ) && '' !== $action['id'] ) { 642 $valid[] = $action; 643 } else { 644 $invalid[] = '#' . ( $position + 1 ); 645 } 646 } 647 648 if ( $invalid ) { 649 $message = sprintf( 650 /* translators: 1: Entity kind, e.g. postType. 2: Entity name, e.g. page. 3: Comma-separated list of positions, e.g. #2, #4. */ 651 __( 'Every action definition must be an array with a non-empty string `id`. These definitions of %1$s "%2$s" are skipped: %3$s.' ), 652 $kind, 653 $name, 654 implode( ', ', $invalid ) 655 ); 656 if ( $valid ) { 657 $message .= ' ' . __( 'The rest of the actions of the call are stored.' ); 658 } 659 _doing_it_wrong( $method, $message, '7.2.0' ); 660 } 661 662 return $valid; 663 } 664 665 /** 666 * Drops the ids that are not a non-empty string, reporting their 667 * positions in the call with _doing_it_wrong(): like an invalid 668 * definition, an invalid id does not cost the call its other ids. 669 * 670 * @since 7.2.0 671 * 672 * @param string $method The calling method, for the notice. 673 * @param string $kind The entity kind. 674 * @param string $name The entity name. 675 * @param array $ids The ids of the actions. 676 * @return string[] The valid ids, in the order of the call. 677 */ 678 protected function skip_invalid_ids( $method, $kind, $name, $ids ) { 679 $valid = array(); 680 $invalid = array(); 681 foreach ( array_values( $ids ) as $position => $id ) { 682 if ( is_string( $id ) && '' !== $id ) { 683 $valid[] = $id; 684 } else { 685 $invalid[] = '#' . ( $position + 1 ); 686 } 687 } 688 689 if ( $invalid ) { 690 $message = sprintf( 691 /* translators: 1: Entity kind, e.g. postType. 2: Entity name, e.g. page. 3: Comma-separated list of positions, e.g. #2, #4. */ 692 __( 'Every action id must be a non-empty string. These ids of %1$s "%2$s" are skipped: %3$s.' ), 693 $kind, 694 $name, 695 implode( ', ', $invalid ) 696 ); 697 if ( $valid ) { 698 $message .= ' ' . __( 'The rest of the actions of the call are unregistered.' ); 699 } 700 _doing_it_wrong( $method, $message, '7.2.0' ); 701 } 702 703 return $valid; 704 } 705 706 /** 707 * Applies a script module to actions of an entity, after the actions it 708 * already applies to. 709 * 710 * @since 7.2.0 711 * 712 * @param string $kind The entity kind. 713 * @param string $name The entity name. 714 * @param string[] $ids The ids of the actions. 715 * @param string|null $script_module The id of the script module, if any. 716 */ 717 protected function add_action_module( $kind, $name, $ids, $script_module ) { 718 if ( null === $script_module ) { 719 return; 720 } 721 722 $module_ids = $this->action_modules[ $kind ][ $name ][ $script_module ] ?? array(); 723 foreach ( $ids as $id ) { 724 if ( ! in_array( $id, $module_ids, true ) ) { 725 $module_ids[] = $id; 726 } 727 } 728 $this->action_modules[ $kind ][ $name ][ $script_module ] = $module_ids; 729 } 730 731 /** 732 * Forgets an entity left without actions or script modules, and its kind 733 * once no entity of the kind is left, so the registry only lists 734 * entities that have some. 735 * 736 * @since 7.2.0 737 * 738 * @param string $kind The entity kind. 739 * @param string $name The entity name. 740 */ 741 protected function forget_empty_entity( $kind, $name ) { 742 if ( empty( $this->actions[ $kind ][ $name ] ) ) { 743 unset( $this->actions[ $kind ][ $name ] ); 744 } 745 if ( empty( $this->actions[ $kind ] ) ) { 746 unset( $this->actions[ $kind ] ); 747 } 748 if ( empty( $this->action_modules[ $kind ][ $name ] ) ) { 749 unset( $this->action_modules[ $kind ][ $name ] ); 750 } 751 if ( empty( $this->action_modules[ $kind ] ) ) { 752 unset( $this->action_modules[ $kind ] ); 753 } 754 } 755 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated : Mon Nov 9 08:20:01 2026 | Cross-referenced by PHPXref |