WP_Ability::prepare_properties( $args ): array<string,

Prepares and validates the properties used to instantiate the ability.

Description

Errors are thrown as exceptions instead of WP_Errors to allow for simpler handling and overloading. They are then caught and converted to a WP_Error by WP_Abilities_Registry::register().

See also

Parameters

mixed> $args { An associative array of arguments used to instantiate the ability class.
@type string $label The human-readable label for the ability.
@type string $description A detailed description of what the ability does.
@type string $category The ability category slug this ability belongs to.
@type callable $execute_callback A callback function to execute when the ability is invoked.
Receives optional mixed input and returns mixed result or WP_Error.
@type callable $permission_callback A callback function to check permissions before execution.
Receives optional mixed input and returns bool or WP_Error.
@type array<string, mixed> $input_schema Optional. JSON Schema definition for the ability’s input. Required if ability accepts an input.
@type array<string, mixed> $output_schema Optional. JSON Schema definition for the ability’s output.
@type array<string, mixed> $meta { Optional. Additional metadata for the ability.
@type array<string, bool|null> $annotations { Optional. Semantic annotations describing the ability’s behavioral characteristics.
These annotations are hints for tooling and documentation.
@type bool|null $readonly Optional. If true, the ability does not modify its environment.
@type bool|null $destructive Optional. If true, the ability may perform destructive updates to its environment.
If false, the ability performs only additive updates.
@type bool|null $idempotent Optional. If true, calling the ability repeatedly with the same arguments will have no additional effect on its environment.
} @type bool $public Optional. Whether the ability is meant to be available to clients such as the REST API, MCP, or AI agents.
Seeds the default for per-channel flags like $show_in_rest. Defaults to false.
@type bool $show_in_rest Optional. Whether to expose this ability in the REST API.
Default is the value of $public when set, false otherwise.
} }

Return

array<string, mixed> { An associative array of arguments with validated and prepared properties for the ability class.
@type string $label The human-readable label for the ability.
@type string $description A detailed description of what the ability does.
@type string $category The ability category slug this ability belongs to.
@type callable $execute_callback A callback function to execute when the ability is invoked.
Receives optional mixed input and returns mixed result or WP_Error.
@type callable $permission_callback A callback function to check permissions before execution.
Receives optional mixed input and returns bool or WP_Error.
@type array<string, mixed> $input_schema Optional. JSON Schema definition for the ability’s input.
@type array<string, mixed> $output_schema Optional. JSON Schema definition for the ability’s output.
@type array<string, mixed> $meta { Additional metadata for the ability.
@type array<string, bool|null> $annotations { Semantic annotations describing the ability’s behavioral characteristics.
These annotations are hints for tooling and documentation.
@type bool|null $readonly If true, the ability does not modify its environment.
@type bool|null $destructive If true, the ability may perform destructive updates to its environment.
If false, the ability performs only additive updates.
@type bool|null $idempotent If true, calling the ability repeatedly with the same arguments will have no additional effect on its environment.
} @type bool $public Whether the ability is meant to be available to clients such as the REST API, MCP, or AI agents. Defaults to false.
@type bool $show_in_rest Whether to expose this ability in the REST API.
} }

Source

protected function prepare_properties( array $args ): array {
	// Required args must be present and of the correct type.
	if ( empty( $args['label'] ) || ! is_string( $args['label'] ) ) {
		throw new InvalidArgumentException(
			__( 'The ability properties must contain a `label` string.' )
		);
	}

	if ( empty( $args['description'] ) || ! is_string( $args['description'] ) ) {
		throw new InvalidArgumentException(
			__( 'The ability properties must contain a `description` string.' )
		);
	}

	if ( empty( $args['category'] ) || ! is_string( $args['category'] ) ) {
		throw new InvalidArgumentException(
			__( 'The ability properties must contain a `category` string.' )
		);
	}

	// If we are not overriding `ability_class` parameter during instantiation, then we need to validate the execute_callback.
	if ( get_class( $this ) === self::class && ( empty( $args['execute_callback'] ) || ! is_callable( $args['execute_callback'] ) ) ) {
		throw new InvalidArgumentException(
			__( 'The ability properties must contain a valid `execute_callback` function.' )
		);
	}

	// If we are not overriding `ability_class` parameter during instantiation, then we need to validate the permission_callback.
	if ( get_class( $this ) === self::class && ( empty( $args['permission_callback'] ) || ! is_callable( $args['permission_callback'] ) ) ) {
		throw new InvalidArgumentException(
			__( 'The ability properties must provide a valid `permission_callback` function.' )
		);
	}

	// Optional args only need to be of the correct type if they are present.
	if ( isset( $args['input_schema'] ) && ! is_array( $args['input_schema'] ) ) {
		throw new InvalidArgumentException(
			__( 'The ability properties should provide a valid `input_schema` definition.' )
		);
	}

	if ( isset( $args['output_schema'] ) && ! is_array( $args['output_schema'] ) ) {
		throw new InvalidArgumentException(
			__( 'The ability properties should provide a valid `output_schema` definition.' )
		);
	}

	if ( isset( $args['meta'] ) && ! is_array( $args['meta'] ) ) {
		throw new InvalidArgumentException(
			__( 'The ability properties should provide a valid `meta` array.' )
		);
	}

	if ( isset( $args['meta']['annotations'] ) && ! is_array( $args['meta']['annotations'] ) ) {
		throw new InvalidArgumentException(
			__( 'The ability meta should provide a valid `annotations` array.' )
		);
	}

	if ( isset( $args['meta']['show_in_rest'] ) && ! is_bool( $args['meta']['show_in_rest'] ) ) {
		throw new InvalidArgumentException(
			__( 'The ability meta should provide a valid `show_in_rest` boolean.' )
		);
	}

	if ( isset( $args['meta']['public'] ) && ! is_bool( $args['meta']['public'] ) ) {
		throw new InvalidArgumentException(
			__( 'The ability meta should provide a valid `public` boolean.' )
		);
	}

	// Set defaults for optional meta.
	$args['meta'] = wp_parse_args(
		$args['meta'] ?? array(),
		array(
			'annotations' => static::$default_annotations,
		)
	);

	$args['meta']['annotations'] = wp_parse_args(
		$args['meta']['annotations'],
		static::$default_annotations
	);

	/*
	 * Resolve `show_in_rest` from most specific to least specific: an explicit
	 * `show_in_rest` value wins, then the high-level `public` flag seeds the
	 * default, then the built-in default applies.
	 */
	$args['meta']['show_in_rest'] = $args['meta']['show_in_rest'] ?? $args['meta']['public'] ?? self::DEFAULT_SHOW_IN_REST;
	$args['meta']['public']       = $args['meta']['public'] ?? self::DEFAULT_PUBLIC;

	return $args;
}

Changelog

VersionDescription
6.9.0Introduced.

User Contributed Notes

You must log in before being able to contribute a note or feedback.