PluginProbe
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages / 3.4.3
Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages v3.4.3
3.4.3 3.4.2 3.4.1 3.4.0 3.3.9 3.3.8 3.3.7 3.3.6 3.3.5 3.3.4 3.3.3 3.3.2 3.3.1 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.2.6 2.2.7 2.2.8 2.2.9 2.3.0 2.3.1 All 196 releases
convertkit / vendor / wordpress / mcp-adapter / includes / Domain / Utils / AbilityArgumentNormalizer.php

AbilityArgumentNormalizer.php in Kit (formerly ConvertKit) – Email Newsletter, Email Marketing, Membership, Subscribers and Landing Pages 3.4.3, at vendor/wordpress/mcp-adapter/includes/Domain/Utils/AbilityArgumentNormalizer.php

108 lines 4.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Normalizes ability arguments for MCP protocol compatibility.
4 *
5 * @package McpAdapter
6 */
7
8 declare( strict_types=1 );
9
10 namespace WP\MCP\Domain\Utils;
11
12 /**
13 * Normalizes ability arguments between MCP and WordPress Abilities API.
14 *
15 * MCP clients send {} (empty object) for tools without arguments.
16 * PHP decodes this as [] (empty array).
17 *
18 * Abilities without an input_schema expect null, not an empty array.
19 * Abilities with an input_schema usually expect an empty array, never null:
20 * PHP's [] satisfies an empty object or empty array schema, but null fails
21 * validation as "not of type <schema type>" (object, array, and so on). Two
22 * exceptions keep null: a schema whose type explicitly permits null (an
23 * explicit null value is passed through), and a schema with a top-level
24 * default, where null lets the Abilities API apply that default for both a
25 * null and an empty {} input. In both, null is the author's declared intent.
26 *
27 * @since 0.5.0
28 */
29 class AbilityArgumentNormalizer {
30
31 /**
32 * Normalize parameters for an ability based on its input schema.
33 *
34 * No input schema: empty arrays are converted to null, so abilities that
35 * take no parameters see null.
36 * Has input schema: null or an empty array normalizes to an empty array so a
37 * zero-argument call passes schema validation instead of failing as "not of
38 * type <schema type>" (object, array, and so on). Two exceptions return null:
39 * a top-level default (both null and {} return null so the Abilities API
40 * applies the default) and a type that explicitly permits null (an explicit
41 * null is passed through).
42 *
43 * @param \WP_Ability $ability The ability to normalize parameters for.
44 * @param mixed $parameters The parameters to normalize.
45 *
46 * @return mixed Normalized parameters (null when no schema and params are empty; empty array when a schema is present and params are empty or null, unless the schema declares a top-level default or its type permits null, in which case null is returned).
47 * @since 0.5.0
48 * @since 0.6.0 Empty or null parameters for schema-defining abilities normalize to an empty array, except when the schema declares a top-level default (honored for both null and empty {} input) or its type explicitly permits null.
49 */
50 public static function normalize( \WP_Ability $ability, $parameters ) {
51 $input_schema = $ability->get_input_schema();
52
53 // No schema: an empty {} means "no arguments" -> null.
54 if ( empty( $input_schema ) ) {
55 return is_array( $parameters ) && empty( $parameters ) ? null : $parameters;
56 }
57
58 // Has schema, missing/empty argument set (null or {}).
59 if ( null === $parameters || array() === $parameters ) {
60 // A top-level default is the author's declared "no input" value.
61 // Return null for BOTH null and {} so WP_Ability::normalize_input()
62 // applies the default -- it fills the default only when input is null.
63 // An MCP client sends {} to mean "no arguments", so {} must honor the
64 // default too, not just an omitted parameter.
65 if ( array_key_exists( 'default', $input_schema ) ) {
66 return null;
67 }
68
69 // An explicit null from the client is kept only when the schema's
70 // type permits null; {} stays [] as an empty object.
71 if ( null === $parameters && self::schema_permits_null( $input_schema ) ) {
72 return null;
73 }
74
75 // Otherwise use [], which satisfies an empty object or array schema
76 // so a zero-argument call validates. null never validates on its own.
77 return array();
78 }
79
80 return $parameters;
81 }
82
83 /**
84 * Whether the schema's top-level type explicitly permits null.
85 *
86 * Only an explicit top-level type is honored (JSON Schema "null", or a type
87 * array containing "null"). Composition keywords that also permit null
88 * (anyOf/oneOf/enum/const) are not inspected; such a schema falls through to
89 * [], which still validates when object or array is among the allowed forms.
90 * A schema with no type is treated as not permitting null, so a zero-argument
91 * call still normalizes to [] for callbacks that expect an array.
92 *
93 * @param array<string,mixed> $input_schema The ability input schema.
94 *
95 * @return bool True when null is a valid top-level value for the schema.
96 * @since 0.6.0
97 */
98 private static function schema_permits_null( array $input_schema ): bool {
99 $type = $input_schema['type'] ?? null;
100
101 if ( is_array( $type ) ) {
102 return in_array( 'null', $type, true );
103 }
104
105 return 'null' === $type;
106 }
107 }
108