-
Notifications
You must be signed in to change notification settings - Fork 55
Add serialization methods to WP_Ability and WP_Ability_Category #109
base: trunk
Are you sure you want to change the base?
Changes from 4 commits
5a4d0da
1b11c60
d2bc425
1684e1d
c6b6dc9
e35000a
25d2e4c
87d6989
766f5a6
426993c
5552d68
5e2b1fc
74ebf3a
203c29f
63e3b5f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,7 +18,7 @@ | |
| * | ||
| * @see WP_Abilities_Registry | ||
| */ | ||
| class WP_Ability { | ||
| class WP_Ability implements \JsonSerializable { | ||
|
|
||
| /** | ||
| * The default value for the `show_in_rest` meta. | ||
|
|
@@ -340,6 +340,138 @@ public function get_meta_item( string $key, $default_value = null ) { | |
| return array_key_exists( $key, $this->meta ) ? $this->meta[ $key ] : $default_value; | ||
| } | ||
|
|
||
| /** | ||
| * Converts the ability to an array representation. | ||
| * | ||
| * Returns a complete array representation of the ability including name, label, | ||
| * description, schemas, and metadata. Callbacks are excluded as they are not serializable. | ||
| * | ||
| * @since n.e.x.t | ||
| * | ||
| * @return array<string,mixed> { | ||
| * The ability as an associative array. | ||
| * | ||
| * @type string $name The ability name with namespace. | ||
| * @type string $label The human-readable label. | ||
| * @type string $description The detailed description. | ||
| * @type array $input_schema The input validation schema. | ||
| * @type array $output_schema The output validation schema. | ||
| * @type array $meta { | ||
| * Metadata for the ability. | ||
| * | ||
| * @type array $annotations { | ||
| * Behavior annotations. | ||
| * | ||
| * @type string $instructions Usage instructions. | ||
| * @type bool $readonly Whether the ability is read-only. | ||
| * @type bool $destructive Whether the ability is destructive. | ||
| * @type bool $idempotent Whether the ability is idempotent. | ||
| * } | ||
| * @type bool $show_in_rest Whether the ability is exposed in REST API. | ||
| * } | ||
| * } | ||
| */ | ||
| public function to_array(): array { | ||
| $array = array( | ||
| 'name' => $this->get_name(), | ||
| 'label' => $this->get_label(), | ||
| 'description' => $this->get_description(), | ||
| 'input_schema' => $this->get_input_schema(), | ||
| 'output_schema' => $this->get_output_schema(), | ||
| 'meta' => $this->get_meta(), | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here, to make the PHPDoc correct, you would have to account for the callback in any custom meta provided or limit that object to
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good point I will change the docblock, as I feel like the |
||
| ); | ||
|
|
||
| /** | ||
| * Filters the array representation of an ability. | ||
| * | ||
| * @since n.e.x.t | ||
| * | ||
| * @param array<string,mixed> $array The ability as an associative array. | ||
| * @param \WP_Ability $ability The ability instance. | ||
| */ | ||
| return apply_filters( "wp_ability_{$this->get_name()}_to_array", $array, $this ); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some example from WP core: I don't see filters used there. @justlevine shared some concerns regarding using filters on methods that are executed multiple times in #37 (comment). More broadly, I'm curious what scenarios this helper method would require these filters, taking into account that the consumer can still manipulate the result however they like.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Filtering here allows individual modification of the "context" for the AI models later on, which is not required for the other methods like this one
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you share an example of how this
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @gziolo thanks for tagging me 🙇 IMO semantically it would make sense that a filter on I also like @bordoni 's use case, since that sort of tailoring wouldn't really make sense extending the class to overload this function. (Though would like to know more as to what modifications you would want injected at that point in the lifecycle and not earlier). That said, I do think it's perfectly fine for WordPress 6.9 to not allow devs to inject top-level properties via a hook. They can already filter args, and dump whatever they want in (Per previous decisions we can merge now and decide whether to strip it during beta).
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When wanting to keep structures concrete, filters are not a great tool :) It's a problem that's discussed over and over, every once in a while it comes up, but obviously, in a filter callback one can do anything one likes. I am not opposed to adding a filter here, but I am much more of a proponent of adding one based on concrete needs. In WordPress Core, every API interface you add will have to be there more or less forever. You can't remove it. But you can always add something. So unless there's a critical need we know of ahead of time, I'd always vote for most minimal public API surfaces possible. If we still want to proceed with adding a filter here right away, I'd strongly suggest to not have it run on the entire data. The use-case mentioned is to inject additional key-value pairs - that's totally reasonable and can be done by filtering an empty array, then merging it into the base result. This way, we allow adding stuff, but we don't allow messing up the base result, which is critical to ensure data integrity. Alternatively, to achieve the same goal, create a copy of
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is there already an existing use case for the filters, or is this a case of "we expect people will want this"? It's not a popular opinion in the WP community, but I'm a big fan of not adding filters to early versions of things that don't have a lot of use yet. It's early days and we may need to change things we can't realize yet. In other words, I'm a fan of code that's easy to change, at this stage of development. Like @felixarntz says above, every API interface you add basically has to remain forever, unless/until it's deprecated and replaced by something else. In this case, we have PHP classes, methods, and filters, all of which are public and a form of an API, and all of which are harder to change once they're in the wild. If there are already solid needs for the filters, then the additive approach mentioned by Felix seems the better way to go. |
||
| } | ||
|
|
||
| /** | ||
| * Serializes the ability to a value that can be serialized natively by json_encode(). | ||
| * | ||
| * Implements the JsonSerializable interface to allow the ability to be passed | ||
| * directly to json_encode() without manually calling to_array(). | ||
| * | ||
| * @since n.e.x.t | ||
| * | ||
| * @return array<string,mixed> The ability as an associative array. | ||
| */ | ||
| public function jsonSerialize(): array { | ||
| return $this->to_array(); | ||
| } | ||
|
|
||
| /** | ||
| * Converts the ability to a JSON Schema representation. | ||
| * | ||
| * Generates a JSON Schema Draft 7 compliant schema describing the ability's | ||
| * structure, including input/output schemas and metadata. | ||
| * | ||
| * @since n.e.x.t | ||
| * | ||
| * @return array<string,mixed> A JSON Schema representation of the ability. | ||
| */ | ||
| public function to_json_schema(): array { | ||
| $input_schema = $this->get_input_schema(); | ||
| $output_schema = $this->get_output_schema(); | ||
|
|
||
| $schema = array( | ||
| '$schema' => 'http://json-schema.org/draft-07/schema#', | ||
| 'type' => 'object', | ||
| 'title' => $this->get_label(), | ||
| 'description' => $this->get_description(), | ||
| 'properties' => array( | ||
| 'name' => array( | ||
| 'type' => 'string', | ||
| 'const' => $this->get_name(), | ||
| ), | ||
| 'meta' => array( | ||
| 'type' => 'object', | ||
| 'properties' => array( | ||
| 'annotations' => array( | ||
| 'type' => 'object', | ||
| 'properties' => array( | ||
| 'instructions' => array( 'type' => 'string' ), | ||
| 'readonly' => array( 'type' => 'boolean' ), | ||
| 'destructive' => array( 'type' => 'boolean' ), | ||
| 'idempotent' => array( 'type' => 'boolean' ), | ||
| ), | ||
| ), | ||
| 'show_in_rest' => array( | ||
| 'type' => 'boolean', | ||
| ), | ||
| ), | ||
| ), | ||
| ), | ||
| 'required' => array( 'name', 'meta' ), | ||
| ); | ||
|
|
||
| if ( ! empty( $input_schema ) ) { | ||
| $schema['properties']['input_schema'] = $input_schema; | ||
| $schema['required'][] = 'input_schema'; | ||
| } | ||
|
|
||
| if ( ! empty( $output_schema ) ) { | ||
| $schema['properties']['output_schema'] = $output_schema; | ||
| $schema['required'][] = 'output_schema'; | ||
| } | ||
|
|
||
| /** | ||
| * Filters the JSON Schema representation of an ability. | ||
| * | ||
| * @since n.e.x.t | ||
| * | ||
| * @param array<string,mixed> $schema The JSON Schema representation. | ||
| * @param \WP_Ability $ability The ability instance. | ||
| */ | ||
| return apply_filters( "wp_ability_{$this->get_name()}_to_json_schema", $schema, $this ); | ||
| } | ||
|
|
||
| /** | ||
| * Validates input data against the input schema. | ||
| * | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.