[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/ -> class-wp-entity-actions-registry.php (source)

   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', 'single' ),
  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` or `single` shows on no screen. Such a
 234       * value is 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<string, string[]> The ids of the actions each module
 408       *                                 applies to, keyed by module id, in
 409       *                                 registration order. Empty when the
 410       *                                 entity is invalid.
 411       */
 412  	public function get_registered_action_modules( $kind, $name ) {
 413          if ( ! $this->validate_entity( __METHOD__, $kind, $name ) ) {
 414              return array();
 415          }
 416          $this->initialize();
 417          return $this->action_modules[ $kind ][ $name ] ?? array();
 418      }
 419  
 420      /**
 421       * Returns the ids of the script modules registered for every entity.
 422       *
 423       * @since 7.2.0
 424       *
 425       * @return array<string, array<string, string[]>> The lists of module ids,
 426       *                                                keyed by kind, then by
 427       *                                                name.
 428       */
 429  	public function get_all_registered_action_modules() {
 430          $this->initialize();
 431          return array_map(
 432              static function ( $entities ) {
 433                  return array_map(
 434                      static function ( $modules ) {
 435                          // A numeric module id is an integer as an array key.
 436                          return array_map( 'strval', array_keys( $modules ) );
 437                      },
 438                      $entities
 439                  );
 440              },
 441              $this->action_modules
 442          );
 443      }
 444  
 445      /**
 446       * Fires the `wp_entity_actions_api_init` action the first time the registry
 447       * is read.
 448       *
 449       * The read is refused until `init` has completed. The registry holds the
 450       * actions of post types, and post types are not known until then: core
 451       * registers its own on `init` at priority 0, plugins theirs at the
 452       * default priority, and supports are added and removed on `init` too.
 453       * The actions of a post type can derive from its supports, and the
 454       * action fires once, so a read before or during `init` would fix them
 455       * from the post types registered so far for the rest of the request.
 456       *
 457       * did_action() is true from the first `init` callback on, hence the
 458       * doing_action() check for the reads made while it runs.
 459       *
 460       * @since 7.2.0
 461       */
 462  	protected function initialize() {
 463          if ( $this->initialized ) {
 464              return;
 465          }
 466  
 467          if ( ! did_action( 'init' ) || doing_action( 'init' ) ) {
 468              _doing_it_wrong(
 469                  __METHOD__,
 470                  __( '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`.' ),
 471                  '7.2.0'
 472              );
 473              return;
 474          }
 475  
 476          // Set before firing, so a callback reading the registry to inspect
 477          // the actions it unregisters does not fire the action again.
 478          $this->initialized = true;
 479  
 480          $this->initializing = true;
 481          try {
 482              /**
 483               * Fires the first time the registered actions are read, after `init`.
 484               *
 485               * Register or remove actions here, with wp_register_entity_actions() and
 486               * wp_unregister_entity_actions(): it is the only time they run.
 487               *
 488               * The first read happens wherever the actions are needed: while
 489               * handling a REST request as well as on `admin_footer` of the pages
 490               * that load the editor script. A callback should register actions
 491               * and nothing else; script modules, styles, and their enqueue hooks
 492               * belong on `init`.
 493               *
 494               * @since 7.2.0
 495               */
 496              do_action( 'wp_entity_actions_api_init' );
 497          } finally {
 498              $this->initializing = false;
 499          }
 500      }
 501  
 502      /**
 503       * Checks that the registry is firing the `wp_entity_actions_api_init` action,
 504       * as register() and unregister() require.
 505       *
 506       * Outside the action a registration would either come before the
 507       * registrations made on it, and take the ids they register, or after
 508       * the actions have been read and the import map of the editor script
 509       * built from them. Refusing keeps the registry immutable once read,
 510       * even when the action is fired again with do_action(), which is why
 511       * the registry tracks its own firing rather than check doing_action().
 512       *
 513       * @since 7.2.0
 514       *
 515       * @param string $method The calling method, for the notice.
 516       * @return bool Whether the action is firing.
 517       */
 518  	protected function doing_entity_actions_api_init( $method ) {
 519          if ( $this->initializing ) {
 520              return true;
 521          }
 522  
 523          _doing_it_wrong(
 524              $method,
 525              __( 'Actions can only be registered and unregistered on the `wp_entity_actions_api_init` action.' ),
 526              '7.2.0'
 527          );
 528          return false;
 529      }
 530  
 531      /**
 532       * Validates the arguments of register().
 533       *
 534       * @since 7.2.0
 535       *
 536       * @param string $method        The calling method, for the notice.
 537       * @param mixed  $origin        The origin.
 538       * @param mixed  $kind          The entity kind.
 539       * @param mixed  $name          The entity name.
 540       * @param mixed  $actions       The action definitions.
 541       * @param mixed  $script_module The script module id, if any.
 542       * @return bool Whether the call may proceed: the `wp_entity_actions_api_init`
 543       *              action is firing and the arguments are valid.
 544       */
 545  	protected function validate_arguments( $method, $origin, $kind, $name, $actions, $script_module ) {
 546          if ( ! $this->doing_entity_actions_api_init( $method ) ) {
 547              return false;
 548          }
 549  
 550          if ( ! is_string( $origin ) || '' === $origin ) {
 551              _doing_it_wrong(
 552                  $method,
 553                  __( 'The origin must be a non-empty string.' ),
 554                  '7.2.0'
 555              );
 556              return false;
 557          }
 558  
 559          if ( ! $this->validate_entity( $method, $kind, $name ) ) {
 560              return false;
 561          }
 562  
 563          if ( ! is_array( $actions ) || empty( $actions ) || ! array_is_list( $actions ) ) {
 564              _doing_it_wrong(
 565                  $method,
 566                  __( 'The actions must be a list of non-empty action definitions.' ),
 567                  '7.2.0'
 568              );
 569              return false;
 570          }
 571  
 572          if ( null !== $script_module && ( ! is_string( $script_module ) || '' === $script_module ) ) {
 573              _doing_it_wrong(
 574                  $method,
 575                  __( 'The script module must be the id of a script module.' ),
 576                  '7.2.0'
 577              );
 578              return false;
 579          }
 580  
 581          return true;
 582      }
 583  
 584      /**
 585       * Checks that the entity kind and name are non-empty strings, reporting
 586       * them with _doing_it_wrong() otherwise.
 587       *
 588       * @since 7.2.0
 589       *
 590       * @param string $method The calling method, for the notice.
 591       * @param mixed  $kind   The entity kind.
 592       * @param mixed  $name   The entity name.
 593       * @return bool Whether both are valid.
 594       */
 595  	protected function validate_entity( $method, $kind, $name ) {
 596          foreach ( array( $kind, $name ) as $argument ) {
 597              if ( ! is_string( $argument ) || '' === $argument ) {
 598                  _doing_it_wrong(
 599                      $method,
 600                      __( 'The entity kind and the entity name must be non-empty strings.' ),
 601                      '7.2.0'
 602                  );
 603                  return false;
 604              }
 605          }
 606          return true;
 607      }
 608  
 609      /**
 610       * Drops the definitions that are not an array with a non-empty string
 611       * `id`, reporting their positions in the call with _doing_it_wrong():
 612       * like a duplicated action, an invalid definition does not cost the call
 613       * its other actions.
 614       *
 615       * @since 7.2.0
 616       *
 617       * @param string  $method  The calling method, for the notice.
 618       * @param string  $kind    The entity kind.
 619       * @param string  $name    The entity name.
 620       * @param array[] $actions The list of action definitions.
 621       * @return array[] The valid definitions, in the order of the call.
 622       */
 623  	protected function skip_invalid_definitions( $method, $kind, $name, $actions ) {
 624          $valid   = array();
 625          $invalid = array();
 626          foreach ( $actions as $position => $action ) {
 627              if ( is_array( $action ) && isset( $action['id'] ) && is_string( $action['id'] ) && '' !== $action['id'] ) {
 628                  $valid[] = $action;
 629              } else {
 630                  $invalid[] = '#' . ( $position + 1 );
 631              }
 632          }
 633  
 634          if ( $invalid ) {
 635              $message = sprintf(
 636                  /* translators: 1: Entity kind, e.g. postType. 2: Entity name, e.g. page. 3: Comma-separated list of positions, e.g. #2, #4. */
 637                  __( 'Every action definition must be an array with a non-empty string `id`. These definitions of %1$s "%2$s" are skipped: %3$s.' ),
 638                  $kind,
 639                  $name,
 640                  implode( ', ', $invalid )
 641              );
 642              if ( $valid ) {
 643                  $message .= ' ' . __( 'The rest of the actions of the call are stored.' );
 644              }
 645              _doing_it_wrong( $method, $message, '7.2.0' );
 646          }
 647  
 648          return $valid;
 649      }
 650  
 651      /**
 652       * Drops the ids that are not a non-empty string, reporting their
 653       * positions in the call with _doing_it_wrong(): like an invalid
 654       * definition, an invalid id does not cost the call its other ids.
 655       *
 656       * @since 7.2.0
 657       *
 658       * @param string $method The calling method, for the notice.
 659       * @param string $kind   The entity kind.
 660       * @param string $name   The entity name.
 661       * @param array  $ids    The ids of the actions.
 662       * @return string[] The valid ids, in the order of the call.
 663       */
 664  	protected function skip_invalid_ids( $method, $kind, $name, $ids ) {
 665          $valid   = array();
 666          $invalid = array();
 667          foreach ( array_values( $ids ) as $position => $id ) {
 668              if ( is_string( $id ) && '' !== $id ) {
 669                  $valid[] = $id;
 670              } else {
 671                  $invalid[] = '#' . ( $position + 1 );
 672              }
 673          }
 674  
 675          if ( $invalid ) {
 676              $message = sprintf(
 677                  /* translators: 1: Entity kind, e.g. postType. 2: Entity name, e.g. page. 3: Comma-separated list of positions, e.g. #2, #4. */
 678                  __( 'Every action id must be a non-empty string. These ids of %1$s "%2$s" are skipped: %3$s.' ),
 679                  $kind,
 680                  $name,
 681                  implode( ', ', $invalid )
 682              );
 683              if ( $valid ) {
 684                  $message .= ' ' . __( 'The rest of the actions of the call are unregistered.' );
 685              }
 686              _doing_it_wrong( $method, $message, '7.2.0' );
 687          }
 688  
 689          return $valid;
 690      }
 691  
 692      /**
 693       * Applies a script module to actions of an entity, after the actions it
 694       * already applies to.
 695       *
 696       * @since 7.2.0
 697       *
 698       * @param string      $kind          The entity kind.
 699       * @param string      $name          The entity name.
 700       * @param string[]    $ids           The ids of the actions.
 701       * @param string|null $script_module The id of the script module, if any.
 702       */
 703  	protected function add_action_module( $kind, $name, $ids, $script_module ) {
 704          if ( null === $script_module ) {
 705              return;
 706          }
 707  
 708          $module_ids = $this->action_modules[ $kind ][ $name ][ $script_module ] ?? array();
 709          foreach ( $ids as $id ) {
 710              if ( ! in_array( $id, $module_ids, true ) ) {
 711                  $module_ids[] = $id;
 712              }
 713          }
 714          $this->action_modules[ $kind ][ $name ][ $script_module ] = $module_ids;
 715      }
 716  
 717      /**
 718       * Forgets an entity left without actions or script modules, and its kind
 719       * once no entity of the kind is left, so the registry only lists
 720       * entities that have some.
 721       *
 722       * @since 7.2.0
 723       *
 724       * @param string $kind The entity kind.
 725       * @param string $name The entity name.
 726       */
 727  	protected function forget_empty_entity( $kind, $name ) {
 728          if ( empty( $this->actions[ $kind ][ $name ] ) ) {
 729              unset( $this->actions[ $kind ][ $name ] );
 730          }
 731          if ( empty( $this->actions[ $kind ] ) ) {
 732              unset( $this->actions[ $kind ] );
 733          }
 734          if ( empty( $this->action_modules[ $kind ][ $name ] ) ) {
 735              unset( $this->action_modules[ $kind ][ $name ] );
 736          }
 737          if ( empty( $this->action_modules[ $kind ] ) ) {
 738              unset( $this->action_modules[ $kind ] );
 739          }
 740      }
 741  }


Generated : Tue Oct 20 08:20:34 2026 Cross-referenced by PHPXref