PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.11.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.11.0
2.11.0 2.10.0 2.9.0 2.8.0 2.7.0 2.6.0 2.5.0 2.4.0 2.3.0 2.2.0 2.1.1 2.1.0 2.0.2 2.0.1 2.0.0 1.32.0 1.31.0 1.30.0 1.29.0 1.28.0 1.27.0 1.26.0 1.25.0 trunk 1.0.0 All 52 releases
thinkrank / dependencies / vendor / wordpress / abilities-api / includes / abilities-api / class-wp-abilities-registry.php

class-wp-abilities-registry.php in ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO 2.11.0, at dependencies/vendor/wordpress/abilities-api/includes/abilities-api/class-wp-abilities-registry.php

322 lines 10.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 if ( ! wp_has_ability_category( $args['category'] ) ) {
125 _doing_it_wrong(
126 __METHOD__,
127 sprintf(
128 /* translators: %1$s: ability category slug, %2$s: ability name */
129 __( 'Ability category "%1$s" is not registered. Please register the ability category before assigning it to ability "%2$s".' ),
130 esc_html( $args['category'] ),
131 esc_html( $name )
132 ),
133 '6.9.0'
134 );
135 return null;
136 }
137 }
138
139 // The class is only used to instantiate the ability, and is not a property of the ability itself.
140 if ( isset( $args['ability_class'] ) && ! is_a( $args['ability_class'], WP_Ability::class, true ) ) {
141 _doing_it_wrong(
142 __METHOD__,
143 __( 'The ability args should provide a valid `ability_class` that extends WP_Ability.' ),
144 '6.9.0'
145 );
146 return null;
147 }
148
149 /** @var class-string<WP_Ability> */
150 $ability_class = $args['ability_class'] ?? WP_Ability::class;
151 unset( $args['ability_class'] );
152
153 try {
154 // WP_Ability::prepare_properties() will throw an exception if the properties are invalid.
155 $ability = new $ability_class( $name, $args );
156 } catch ( InvalidArgumentException $e ) {
157 _doing_it_wrong(
158 __METHOD__,
159 $e->getMessage(),
160 '6.9.0'
161 );
162 return null;
163 }
164
165 $this->registered_abilities[ $name ] = $ability;
166 return $ability;
167 }
168
169 /**
170 * Unregisters an ability.
171 *
172 * Do not use this method directly. Instead, use the `wp_unregister_ability()` function.
173 *
174 * @since 6.9.0
175 *
176 * @see wp_unregister_ability()
177 *
178 * @param string $name The name of the registered ability, with its namespace.
179 * @return WP_Ability|null The unregistered ability instance on success, null on failure.
180 */
181 public function unregister( string $name ): ?WP_Ability {
182 if ( ! $this->is_registered( $name ) ) {
183 _doing_it_wrong(
184 __METHOD__,
185 /* translators: %s: Ability name. */
186 sprintf( __( 'Ability "%s" not found.' ), esc_html( $name ) ),
187 '6.9.0'
188 );
189 return null;
190 }
191
192 $unregistered_ability = $this->registered_abilities[ $name ];
193 unset( $this->registered_abilities[ $name ] );
194
195 return $unregistered_ability;
196 }
197
198 /**
199 * Retrieves the list of all registered abilities.
200 *
201 * Do not use this method directly. Instead, use the `wp_get_abilities()` function.
202 *
203 * @since 6.9.0
204 *
205 * @see wp_get_abilities()
206 *
207 * @return WP_Ability[] The array of registered abilities.
208 */
209 public function get_all_registered(): array {
210 return $this->registered_abilities;
211 }
212
213 /**
214 * Checks if an ability is registered.
215 *
216 * Do not use this method directly. Instead, use the `wp_has_ability()` function.
217 *
218 * @since 6.9.0
219 *
220 * @see wp_has_ability()
221 *
222 * @param string $name The name of the registered ability, with its namespace.
223 * @return bool True if the ability is registered, false otherwise.
224 */
225 public function is_registered( string $name ): bool {
226 return isset( $this->registered_abilities[ $name ] );
227 }
228
229 /**
230 * Retrieves a registered ability.
231 *
232 * Do not use this method directly. Instead, use the `wp_get_ability()` function.
233 *
234 * @since 6.9.0
235 *
236 * @see wp_get_ability()
237 *
238 * @param string $name The name of the registered ability, with its namespace.
239 * @return WP_Ability|null The registered ability instance, or null if it is not registered.
240 */
241 public function get_registered( string $name ): ?WP_Ability {
242 if ( ! $this->is_registered( $name ) ) {
243 _doing_it_wrong(
244 __METHOD__,
245 /* translators: %s: Ability name. */
246 sprintf( __( 'Ability "%s" not found.' ), esc_html( $name ) ),
247 '6.9.0'
248 );
249 return null;
250 }
251 return $this->registered_abilities[ $name ];
252 }
253
254 /**
255 * Utility method to retrieve the main instance of the registry class.
256 *
257 * The instance will be created if it does not exist yet.
258 *
259 * @since 6.9.0
260 *
261 * @return WP_Abilities_Registry|null The main registry instance, or null when `init` action has not fired.
262 */
263 public static function get_instance(): ?self {
264 if ( ! did_action( 'init' ) ) {
265 _doing_it_wrong(
266 __METHOD__,
267 sprintf(
268 // translators: %s: init action.
269 __( 'Ability API should not be initialized before the %s action has fired.' ),
270 '<code>init</code>'
271 ),
272 '6.9.0'
273 );
274 return null;
275 }
276
277 if ( null === self::$instance ) {
278 self::$instance = new self();
279
280 // Ensure ability category registry is initialized first to allow categories to be registered
281 // before abilities that depend on them.
282 WP_Ability_Categories_Registry::get_instance();
283
284 /**
285 * Fires when preparing abilities registry.
286 *
287 * Abilities should be created and register their hooks on this action rather
288 * than another action to ensure they're only loaded when needed.
289 *
290 * @since 6.9.0
291 *
292 * @param WP_Abilities_Registry $instance Abilities registry object.
293 */
294 do_action( 'wp_abilities_api_init', self::$instance );
295 }
296
297 return self::$instance;
298 }
299
300 /**
301 * Wakeup magic method.
302 *
303 * @since 6.9.0
304 * @throws LogicException If the registry object is unserialized.
305 * This is a security hardening measure to prevent unserialization of the registry.
306 */
307 public function __wakeup(): void {
308 throw new LogicException( __CLASS__ . ' should never be unserialized.' );
309 }
310
311 /**
312 * Sleep magic method.
313 *
314 * @since 6.9.0
315 * @throws LogicException If the registry object is serialized.
316 * This is a security hardening measure to prevent serialization of the registry.
317 */
318 public function __sleep(): array {
319 throw new LogicException( __CLASS__ . ' should never be serialized.' );
320 }
321 }
322