Automattic\WooCommerce\Internal\Abilities\REST
RestAbilityFactory::relax_output_schema_for_wc_quirks
Recursively relax an output schema so it accepts the shapes WooCommerce REST controllers actually return.
Used on output schemas only — input schemas keep their tighter constraints so MCP clients still get useful hints when formatting tool calls. Must run AFTER {@see self::sanitize_schema()}, which converts the date-time pseudo-type to type: "string" + format: "date-time" — this method then strips the format.
Relaxations:
format: "date-time"andformat: "uri"are stripped. WooCommerce RESTdate strings (e.g. `2025-11-24T16:31:43`) omit the timezone suffix RFC 3339 requires, and `format: "uri"` fields routinely return empty strings.
- Any
typewhose declared members are all scalars and/ornulliswidened to {@see self::OUTPUT_SCALAR_UNION} — every JSON type plus `null`. Applies to single scalars (`string`, `integer`, `number`, `boolean`) and to pre-existing unions like `[integer, null]`. Fields that declare any compound type (`object`, `array`) are left alone. This is a deliberate accuracy tradeoff: many WooCommerce REST controllers declare types that disagree with what they actually return (e.g. `shipping_class_id` declared `string` but returned as `int`; `low_stock_amount` declared `[integer, null]` but returned as `""` when unset; `meta_data[].display_value` declared `string` but routinely an array for variation attributes and serialized custom meta). The alternative is per-controller schema fixes across legacy code. Skipped inside `anyOf` / `oneOf` / `allOf` branches: widening every branch breaks the "exactly one" rule for `oneOf`, and for `anyOf` / `allOf` the schema author was explicit about admissible shapes.
Recurses into properties, items (single schema and tuple form), additionalProperties, and the anyOf / oneOf / allOf combiners.
Method of the class: RestAbilityFactory{}
No Hooks.
Returns
Array. Relaxed schema node.
Usage
$result = RestAbilityFactory::relax_output_schema_for_wc_quirks( $schema, $apply_null_union ): array;
- $schema(array) (required)
- A JSON Schema node.
- $apply_null_union(true|false)
- Whether to apply the scalar-to-nullable widening at this node. False when recursing into combiner branches.
Default:true
RestAbilityFactory::relax_output_schema_for_wc_quirks() RestAbilityFactory::relax output schema for wc quirks code WC 10.9.4
private static function relax_output_schema_for_wc_quirks( array $schema, bool $apply_null_union = true ): array {
if ( isset( $schema['format'] ) && in_array( $schema['format'], array( 'date-time', 'uri' ), true ) ) {
unset( $schema['format'] );
}
if ( $apply_null_union && isset( $schema['type'] ) && self::should_widen_to_output_union( $schema['type'] ) ) {
$schema['type'] = self::OUTPUT_SCALAR_UNION;
}
if ( isset( $schema['properties'] ) && is_array( $schema['properties'] ) ) {
foreach ( $schema['properties'] as $key => $property ) {
if ( is_array( $property ) ) {
$schema['properties'][ $key ] = self::relax_output_schema_for_wc_quirks( $property, $apply_null_union );
}
}
}
if ( isset( $schema['items'] ) && is_array( $schema['items'] ) ) {
if ( isset( $schema['items'][0] ) ) {
// Tuple form: each numerically-indexed entry validates the array element at that position.
foreach ( $schema['items'] as $index => $entry ) {
if ( is_array( $entry ) ) {
$schema['items'][ $index ] = self::relax_output_schema_for_wc_quirks( $entry, $apply_null_union );
}
}
} else {
$schema['items'] = self::relax_output_schema_for_wc_quirks( $schema['items'], $apply_null_union );
}
}
if ( isset( $schema['additionalProperties'] ) && is_array( $schema['additionalProperties'] ) ) {
$schema['additionalProperties'] = self::relax_output_schema_for_wc_quirks( $schema['additionalProperties'], $apply_null_union );
}
foreach ( array( 'anyOf', 'oneOf', 'allOf' ) as $combiner ) {
if ( isset( $schema[ $combiner ] ) && is_array( $schema[ $combiner ] ) ) {
foreach ( $schema[ $combiner ] as $index => $branch ) {
if ( is_array( $branch ) ) {
// Entering a combiner from anywhere disables null-union for the entire subtree.
$schema[ $combiner ][ $index ] = self::relax_output_schema_for_wc_quirks( $branch, false );
}
}
}
}
return $schema;
}