[ Index ] |
PHP Cross Reference of WordPress Trunk (Updated Daily) |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated : Thu Oct 23 08:20:05 2025 | Cross-referenced by PHPXref |