The Role of JSON Schema Preparation in WordPress 7.1
For several release cycles, WordPress core and custom plugin developers have relied on internal JSON Schema conventions during server-side validation. Features like the REST API and the Abilities API accept schemas containing PHP-specific callbacks (such as sanitize_callback or validate_callback) and property-level 'required' => true declarations. While these conventions simplify server-side PHP processing, they violate standard portable JSON Schema Draft 4 specifications.
Exposing internal schemas directly to external entities—such as frontend JavaScript applications, Model Context Protocol (MCP) tool definitions, or AI Client function declarations—presents technical challenges. External schema validators fail when encountering non-standard property flags or unparseable PHP function references. Furthermore, leaking server-side callbacks can inadvertently expose implementation details to public clients.
To fix this boundary issue, WordPress 7.1 introduces a shared JSON Schema preparation layer anchored by the wp_prepare_json_schema_for_client() function. This utility recursively transforms internal WordPress schema arrays into portable, client-safe JSON Schema Draft 4 representations before output.
Function Signature and Available Schema Profiles
The core preparation utility accepts a canonical schema array and an optional profile parameter that dictates which keywords are preserved during transformation:
/**
* Prepares a JSON Schema for clients.
*
* @param array<string, mixed> $schema The schema array.
* @param string $schema_profile Optional. Name of the schema profile whose keywords should be preserved. Default 'draft-04'.
* @return array<string, mixed> The prepared schema.
*/
wp_prepare_json_schema_for_client( array $schema, string $schema_profile = 'draft-04' ): array
WordPress 7.1 provides two built-in schema profiles out of the box:
draft-04(Default): Designed for general-purpose external clients, standalone schemas, frontend JavaScript validators, MCP tool declarations, and AI integrations. It retains the full expressive vocabulary of JSON Schema Draft 4, including composition and reference keywords like$ref,definitions,allOf,not,dependencies, andadditionalItems.rest-api: Tailored for the narrower set of keywords historically supported by WordPress REST API route schemas. Use this profile when preparing schemas that must conform directly to REST route argument or response contracts.
Both profiles generate standards-compliant Draft 4 outputs; they differ strictly in the subset of schema keywords allowed to remain in the final structure:
// General client-facing schema (e.g., AI Client or frontend validator)
$prepared_schema = wp_prepare_json_schema_for_client( $schema );
// Schema strictly adhering to WordPress REST API route conventions
$prepared_rest_schema = wp_prepare_json_schema_for_client( $schema, 'rest-api' );
Transforming Property-Level Required Syntaxes to Draft-04
WordPress internally allows property definitions to declare their required status using inline booleans:
'properties' => array(
'title' => array(
'type' => 'string',
'required' => true,
),
)
In standard JSON Schema Draft 4, required must be defined at the parent object level as an array of property name strings. When wp_prepare_json_schema_for_client() executes, it converts these inline booleans into the proper Draft 4 array shape:
- Any property marked with
'required' => truehas its key added to the containing object’s top-levelrequiredarray, and the inlinerequiredboolean is removed. - If the parent object already contains a valid
requiredarray, that existing array takes precedence over property-level booleans. - Properties set to
'required' => falsesimply have the key removed without creating empty arrays. - Boolean
requiredflags on scalar schemas are stripped because Draft 4 does not support scalar required properties.
Recursively Stripping Server-Side Callbacks and Internal Keywords
PHP validation and sanitization callbacks cannot be safely executed or represented in client environments. The preparation function recursively traverses schema structures to remove non-standard keywords.
Specifically, the following internal server-side keys are purged:
sanitize_callbackvalidate_callbackarg_options
This removal occurs across all nested levels, including within properties, patternProperties, definitions, dependencies, items, additionalItems, additionalProperties, anyOf, oneOf, allOf, and not structures.
Concrete Code Example: Before and After Transformation
Consider the following internal server schema array containing both custom callbacks and property-level requirement flags:
$schema = array(
'type' => 'object',
'properties' => array(
'title' => array(
'type' => 'string',
'required' => true,
'sanitize_callback' => 'sanitize_text_field',
),
'content' => array(
'type' => 'string',
'validate_callback' => 'is_string',
),
),
);
$prepared_schema = wp_prepare_json_schema_for_client( $schema );
After passing through wp_prepare_json_schema_for_client(), the output schema is converted into clean, standard Draft 4 JSON Schema array structure:
array(
'type' => 'object',
'required' => array( 'title' ),
'properties' => array(
'title' => array(
'type' => 'string',
),
'content' => array(
'type' => 'string',
),
),
);
Solving PHP Array Serialization for Object Defaults
In PHP, an empty array is represented as array(). When serialized to JSON via standard json_encode(), an empty PHP array evaluates to a JSON list ([]). If a schema defines an object type with an empty default, native PHP serialization breaks JSON Schema typing rules:
// PHP Representation
array(
'type' => 'object',
'default' => array(),
)
Without conversion, this outputs {"type": "object", "default": []} in JSON, causing external client validators to throw a type mismatch error because an Array was provided where an Object was declared.
The preparation utility identifies empty default arrays on object schemas and normalizes them during preparation, guaranteeing that JSON serialization correctly yields:
{
"type": "object",
"default": {}
}
Automatic Client Preparation in Core: Abilities API and AI Client
Most developers do not need to manually invoke wp_prepare_json_schema_for_client() for standard core features. In WordPress 7.1, core applies this preparation step automatically at specific output boundaries:
- Abilities REST API Endpoints: When abilities registered with REST visibility are exposed under
/wp-json/wp-abilities/v1/abilities, core prepares their input and output schemas before outputting the REST payload. - AI Client Tool Declarations: When the WordPress AI Client converts an ability’s input schema into function declarations for AI models, it automatically calls
wp_prepare_json_schema_for_client( $ability->get_input_schema() )first.
By enforcing this preparation layer at the output boundary, core ensures that internal server-side processing keeps full access to raw PHP schemas while public endpoints output portable JSON representations.
Manual Schema Preparation for Custom Endpoints and Integrations
Plugin and theme developers should manually call wp_prepare_json_schema_for_client() whenever they expose internal WordPress-style schema arrays beyond the PHP runtime. Common practical use cases include:
- Exposing custom endpoints that return schema contracts to frontend SPA frameworks (React, Vue).
- Injecting schemas into inline JavaScript variables (via
wp_add_inline_script()orwp_localize_script()) for browser-side validation libraries. - Building custom Model Context Protocol (MCP) tool definitions or external API bridge tools.
// Preparing a custom schema for an inline JavaScript client contract
$raw_schema = $my_plugin_class->get_internal_schema();
$client_schema = wp_prepare_json_schema_for_client( $raw_schema, 'draft-04' );
wp_add_inline_script(
'my-plugin-script',
'const myPluginSchema = ' . wp_json_encode( $client_schema ) . ';',
'before'
);
Customizing Allowed Keywords via Filters
Under the hood, wp_prepare_json_schema_for_client() delegates keyword evaluation to wp_get_json_schema_allowed_keywords(). If your custom application requires passing vendor-specific schema extensions (e.g., custom UI annotations or extended validation keywords), you can extend the allowed keyword list using the wp_json_schema_allowed_keywords filter hook:
add_filter( 'wp_json_schema_allowed_keywords', function ( $keywords, $schema_profile ) {
if ( 'draft-04' === $schema_profile ) {
$keywords[] = 'x-custom-ui-annotation';
}
return $keywords;
}, 10, 2 );
Note: Preserving a keyword via this filter allows it to remain in the prepared client schema array. It does not mean WordPress will validate or sanitize values against that keyword during server-side PHP execution. Custom keywords should only be exposed when client consumers are known to understand them.
Critical Architectural Guidelines and Current Limitations
When working with the new preparation layer in WordPress 7.1, keep the following technical rules and limitations in mind:
- Do Not Overwrite Canonical Schemas: Never overwrite or re-register the primary schema stored inside a
WP_Abilityor endpoint controller with the prepared version. Server-side validation helpers—such asrest_validate_value_from_schema()andWP_Ability::validate_input()—rely on the canonical internal schema. Prepare a copy only when sending data to external clients. - Differences in Schema Retrieval: Comparing an internal schema retrieved directly from a PHP object instance (e.g.,
$ability->get_input_schema()) with the payload returned over REST endpoints (/wp-json/wp-abilities/v1/abilities) will show intentional structural differences. - Callback Execution Limits in Abilities API: Callbacks like
validate_callbackandsanitize_callbackare purged because they are not executed by the Abilities API runtime validation anyway. Developers requiring custom validation for abilities in WordPress 7.1 should use the newly introducedwp_ability_validate_inputandwp_ability_validate_outputfilter hooks. - AI Provider Adaptation: While
wp_prepare_json_schema_for_client()generates a valid Draft 4 schema for AI function calling, it is not a provider-specific compiler. Different LLM providers (e.g., OpenAI, Anthropic) impose unique restrictions or subsets on tool declarations. Additional downstream adjustments may be required by individual AI provider integrations.
Frequently asked questions
What is the purpose of wp_prepare_json_schema_for_client() in WordPress 7.1?
It converts internal WordPress JSON schema representations—which may include PHP callbacks and property-level 'required' booleans—into clean, portable JSON Schema Draft 4 structures suitable for REST clients, frontend JS, MCP tools, and AI function declarations.
Does preparing a schema modify the canonical schema stored on the server?
No. The canonical schema retained by WP_Ability or REST endpoints remains untouched in PHP memory to facilitate server-side validation. Schema preparation is an output-boundary operation applied to a copy of the schema.
What schema profiles are provided by default in WordPress 7.1?
WordPress 7.1 provides two default profiles: 'draft-04' (the default, preserving broad draft 4 keywords like $ref and definitions) and 'rest-api' (restricted to keywords aligned with REST API route schemas).
How are required properties handled during preparation?
Property-level 'required' => true booleans are removed from property definitions and consolidated into a top-level Draft 4 'required' array on the parent object schema.
How do I filter allowed keywords in a prepared JSON schema?
You can use the 'wp_json_schema_allowed_keywords' filter hook, which receives the array of allowed keyword strings and the active schema profile name as parameters.
Primary reference: Review the original announcement for exact release details. This article is an independent explanation and does not reproduce the source text.