[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/abilities-api/ -> class-wp-abilities-registry.php (source)

   1  <?php
   2  /**
   3   * Abilities API
   4   *
   5   * Defines WP_Abilities_Registry class.
   6   *
   7   * @package WordPress
   8   * @subpackage Abilities API
   9   * @since 6.9.0
  10   */
  11  
  12  declare( strict_types = 1 );
  13  
  14  /**
  15   * Manages the registration and lookup of abilities.
  16   *
  17   * @since 6.9.0
  18   * @access private
  19   */
  20  final class WP_Abilities_Registry {
  21      /**
  22       * The singleton instance of the registry.
  23       *
  24       * @since 6.9.0
  25       * @var self|null
  26       */
  27      private static $instance = null;
  28  
  29      /**
  30       * Holds the registered abilities.
  31       *
  32       * @since 6.9.0
  33       * @var WP_Ability[]
  34       */
  35      private $registered_abilities = array();
  36  
  37      /**
  38       * Registers a new ability.
  39       *
  40       * Do not use this method directly. Instead, use the `wp_register_ability()` function.
  41       *
  42       * @since 6.9.0
  43       *
  44       * @see wp_register_ability()
  45       *
  46       * @param string               $name The name of the ability. The name must be a string containing a namespace
  47       *                                   prefix, i.e. `my-plugin/my-ability`. It can only contain lowercase
  48       *                                   alphanumeric characters, dashes and the forward slash.
  49       * @param array<string, mixed> $args {
  50       *     An associative array of arguments for the ability.
  51       *
  52       *     @type string               $label                 The human-readable label for the ability.
  53       *     @type string               $description           A detailed description of what the ability does.
  54       *     @type string               $category              The ability category slug this ability belongs to.
  55       *     @type callable             $execute_callback      A callback function to execute when the ability is invoked.
  56       *                                                       Receives optional mixed input and returns mixed result or WP_Error.
  57       *     @type callable             $permission_callback   A callback function to check permissions before execution.
  58       *                                                       Receives optional mixed input and returns bool or WP_Error.
  59       *     @type array<string, mixed> $input_schema          Optional. JSON Schema definition for the ability's input.
  60       *     @type array<string, mixed> $output_schema         Optional. JSON Schema definition for the ability's output.
  61       *     @type array<string, mixed> $meta                  {
  62       *         Optional. Additional metadata for the ability.
  63       *
  64       *         @type array<string, null|bool> $annotations  Optional. Annotation metadata for the ability.
  65       *         @type bool                     $show_in_rest Optional. Whether to expose this ability in the REST API. Default false.
  66       *     }
  67       *     @type string               $ability_class         Optional. Custom class to instantiate instead of WP_Ability.
  68       * }
  69       * @return WP_Ability|null The registered ability instance on success, null on failure.
  70       */
  71  	public function register( string $name, array $args ): ?WP_Ability {
  72          if ( ! preg_match( '/^[a-z0-9-]+\/[a-z0-9-]+$/', $name ) ) {
  73              _doing_it_wrong(
  74                  __METHOD__,
  75                  __(
  76                      'Ability name must be a string containing a namespace prefix, i.e. "my-plugin/my-ability". It can only contain lowercase alphanumeric characters, dashes and the forward slash.'
  77                  ),
  78                  '6.9.0'
  79              );
  80              return null;
  81          }
  82  
  83          if ( $this->is_registered( $name ) ) {
  84              _doing_it_wrong(
  85                  __METHOD__,
  86                  /* translators: %s: Ability name. */
  87                  sprintf( __( 'Ability "%s" is already registered.' ), esc_html( $name ) ),
  88                  '6.9.0'
  89              );
  90              return null;
  91          }
  92  
  93          /**
  94           * Filters the ability arguments before they are validated and used to instantiate the ability.
  95           *
  96           * @since 6.9.0
  97           *
  98           * @param array<string, mixed> $args {
  99           *     An associative array of arguments for the ability.
 100           *
 101           *     @type string               $label                 The human-readable label for the ability.
 102           *     @type string               $description           A detailed description of what the ability does.
 103           *     @type string               $category              The ability category slug this ability belongs to.
 104           *     @type callable             $execute_callback      A callback function to execute when the ability is invoked.
 105           *                                                       Receives optional mixed input and returns mixed result or WP_Error.
 106           *     @type callable             $permission_callback   A callback function to check permissions before execution.
 107           *                                                       Receives optional mixed input and returns bool or WP_Error.
 108           *     @type array<string, mixed> $input_schema          Optional. JSON Schema definition for the ability's input.
 109           *     @type array<string, mixed> $output_schema         Optional. JSON Schema definition for the ability's output.
 110           *     @type array<string, mixed> $meta                  {
 111           *         Optional. Additional metadata for the ability.
 112           *
 113           *         @type array<string, bool|string> $annotations  Optional. Annotation metadata for the ability.
 114           *         @type bool                       $show_in_rest Optional. Whether to expose this ability in the REST API. Default false.
 115           *     }
 116           *     @type string               $ability_class         Optional. Custom class to instantiate instead of WP_Ability.
 117           * }
 118           * @param string               $name The name of the ability, with its namespace.
 119           */
 120          $args = apply_filters( 'wp_register_ability_args', $args, $name );
 121  
 122          // Validate ability category exists if provided (will be validated as required in WP_Ability).
 123          if ( isset( $args['category'] ) ) {
 124              $category_registry = WP_Ability_Categories_Registry::get_instance();
 125              if ( ! $category_registry->is_registered( $args['category'] ) ) {
 126                  _doing_it_wrong(
 127                      __METHOD__,
 128                      sprintf(
 129                          /* translators: %1$s: ability category slug, %2$s: ability name */
 130                          __( 'Ability category "%1$s" is not registered. Please register the ability category before assigning it to ability "%2$s".' ),
 131                          esc_html( $args['category'] ),
 132                          esc_html( $name )
 133                      ),
 134                      '6.9.0'
 135                  );
 136                  return null;
 137              }
 138          }
 139  
 140          // The class is only used to instantiate the ability, and is not a property of the ability itself.
 141          if ( isset( $args['ability_class'] ) && ! is_a( $args['ability_class'], WP_Ability::class, true ) ) {
 142              _doing_it_wrong(
 143                  __METHOD__,
 144                  __( 'The ability args should provide a valid `ability_class` that extends WP_Ability.' ),
 145                  '6.9.0'
 146              );
 147              return null;
 148          }
 149  
 150          /** @var class-string<WP_Ability> */
 151          $ability_class = $args['ability_class'] ?? WP_Ability::class;
 152          unset( $args['ability_class'] );
 153  
 154          try {
 155              // WP_Ability::prepare_properties() will throw an exception if the properties are invalid.
 156              $ability = new $ability_class( $name, $args );
 157          } catch ( InvalidArgumentException $e ) {
 158              _doing_it_wrong(
 159                  __METHOD__,
 160                  $e->getMessage(),
 161                  '6.9.0'
 162              );
 163              return null;
 164          }
 165  
 166          $this->registered_abilities[ $name ] = $ability;
 167          return $ability;
 168      }
 169  
 170      /**
 171       * Unregisters an ability.
 172       *
 173       * Do not use this method directly. Instead, use the `wp_unregister_ability()` function.
 174       *
 175       * @since 6.9.0
 176       *
 177       * @see wp_unregister_ability()
 178       *
 179       * @param string $name The name of the registered ability, with its namespace.
 180       * @return WP_Ability|null The unregistered ability instance on success, null on failure.
 181       */
 182  	public function unregister( string $name ): ?WP_Ability {
 183          if ( ! $this->is_registered( $name ) ) {
 184              _doing_it_wrong(
 185                  __METHOD__,
 186                  /* translators: %s: Ability name. */
 187                  sprintf( __( 'Ability "%s" not found.' ), esc_html( $name ) ),
 188                  '6.9.0'
 189              );
 190              return null;
 191          }
 192  
 193          $unregistered_ability = $this->registered_abilities[ $name ];
 194          unset( $this->registered_abilities[ $name ] );
 195  
 196          return $unregistered_ability;
 197      }
 198  
 199      /**
 200       * Retrieves the list of all registered abilities.
 201       *
 202       * Do not use this method directly. Instead, use the `wp_get_abilities()` function.
 203       *
 204       * @since 6.9.0
 205       *
 206       * @see wp_get_abilities()
 207       *
 208       * @return WP_Ability[] The array of registered abilities.
 209       */
 210  	public function get_all_registered(): array {
 211          return $this->registered_abilities;
 212      }
 213  
 214      /**
 215       * Checks if an ability is registered.
 216       *
 217       * Do not use this method directly. Instead, use the `wp_has_ability()` function.
 218       *
 219       * @since 6.9.0
 220       *
 221       * @see wp_has_ability()
 222       *
 223       * @param string $name The name of the registered ability, with its namespace.
 224       * @return bool True if the ability is registered, false otherwise.
 225       */
 226  	public function is_registered( string $name ): bool {
 227          return isset( $this->registered_abilities[ $name ] );
 228      }
 229  
 230      /**
 231       * Retrieves a registered ability.
 232       *
 233       * Do not use this method directly. Instead, use the `wp_get_ability()` function.
 234       *
 235       * @since 6.9.0
 236       *
 237       * @see wp_get_ability()
 238       *
 239       * @param string $name The name of the registered ability, with its namespace.
 240       * @return ?WP_Ability The registered ability instance, or null if it is not registered.
 241       */
 242  	public function get_registered( string $name ): ?WP_Ability {
 243          if ( ! $this->is_registered( $name ) ) {
 244              _doing_it_wrong(
 245                  __METHOD__,
 246                  /* translators: %s: Ability name. */
 247                  sprintf( esc_html__( 'Ability "%s" not found.' ), esc_attr( $name ) ),
 248                  '6.9.0'
 249              );
 250              return null;
 251          }
 252          return $this->registered_abilities[ $name ];
 253      }
 254  
 255      /**
 256       * Utility method to retrieve the main instance of the registry class.
 257       *
 258       * The instance will be created if it does not exist yet.
 259       *
 260       * @since 6.9.0
 261       *
 262       * @return WP_Abilities_Registry|null The main registry instance, or null when `init` action has not fired.
 263       */
 264  	public static function get_instance(): ?self {
 265          if ( ! did_action( 'init' ) ) {
 266              _doing_it_wrong(
 267                  __METHOD__,
 268                  sprintf(
 269                      __( 'Ability API should not be initialized before the <code>init</code> action has fired' )
 270                  ),
 271                  '6.9.0'
 272              );
 273              return null;
 274          }
 275  
 276          if ( null === self::$instance ) {
 277              self::$instance = new self();
 278  
 279              // Ensure ability category registry is initialized first to allow categories to be registered
 280              // before abilities that depend on them.
 281              WP_Ability_Categories_Registry::get_instance();
 282  
 283              /**
 284               * Fires when preparing abilities registry.
 285               *
 286               * Abilities should be created and register their hooks on this action rather
 287               * than another action to ensure they're only loaded when needed.
 288               *
 289               * @since 6.9.0
 290               *
 291               * @param WP_Abilities_Registry $instance Abilities registry object.
 292               */
 293              do_action( 'wp_abilities_api_init', self::$instance );
 294          }
 295  
 296          return self::$instance;
 297      }
 298  
 299      /**
 300       * Wakeup magic method.
 301       *
 302       * @since 6.9.0
 303       * @throws LogicException If the registry object is unserialized.
 304       *                        This is a security hardening measure to prevent unserialization of the registry.
 305       */
 306  	public function __wakeup(): void {
 307          throw new LogicException( __CLASS__ . ' should never be unserialized.' );
 308      }
 309  
 310      /**
 311       * Sleep magic method.
 312       *
 313       * @since 6.9.0
 314       * @throws LogicException If the registry object is serialized.
 315       *                        This is a security hardening measure to prevent serialization of the registry.
 316       */
 317  	public function __sleep(): array {
 318          throw new LogicException( __CLASS__ . ' should never be serialized' );
 319      }
 320  }


Generated : Thu Oct 23 08:20:05 2025 Cross-referenced by PHPXref