JSON Schema preparation for client compatibility in WordPress 7.1

WordPress 7.1 introduces a shared JSONJSON JSON, or JavaScript Object Notation, is a minimal, readable format for structuring data. It is used primarily to transmit data between a server and web application, as an alternative to XML. Schema preparation layer for schemas exposed to REST clients, frontend applications, and AI tools.

WordPress accepts several internal schema conventions that are useful during server-side validation but are not portable JSON Schema draft-04. Passing these schemas directly to external validators could cause validation errors or expose PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 7.4 or higher callbacks and other server-only implementation details.

The wp_prepare_json_schema_for_client() function

The new wp_prepare_json_schema_for_client() function converts a WordPress schema into a portable, client-facing representation before it is exposed to REST clients, frontend applications, AI tools, or other external consumers.

Most developers do not need to take action. CoreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. now applies this preparation automatically to:

  • Abilities APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. schemas exposed through REST responses.
  • Ability input schemas converted into AI Client function declarations.
$prepared_schema = wp_prepare_json_schema_for_client( $schema );

This keeps the schemas used by clients (REST clients, JavaScriptJavaScript JavaScript or JS is an object-oriented computer programming language commonly used to create interactive effects within web browsers. WordPress makes extensive use of JS for a better user experience. While PHP is executed on the server, JS executes within a user’s browser. https://www.javascript.com applications, and AI tools) consistent. See ticketticket Created for both bug reports and feature development on the bug tracker. #64955 and changeset [62591].

Compatibility guidance

This change is primarily automatic. Existing ability registration and execution code does not need to call the new function.

Call wp_prepare_json_schema_for_client() directly when a pluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party. exposes a WordPress-style schema outside the server-side PHP validation boundary, for example through:

  • a custom REST endpoint;
  • a JavaScript configuration object;
  • an MCP tool declaration;
  • an AI function declaration; or
  • another external schema consumer.

Do not replace the schema stored by an ability with the prepared version. Keep the canonical WordPress schema for server-side use and prepare a copy only when sending it to a client.

Choosing a schema profile

This new function accepts a schema and an optional schema profile:

/** 
 * 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 provides two schema profiles out of the box:

  • draft-04 is the default. Use it when publishing a standalone schema to general-purpose clients, including Ability metadata, frontend validators, MCP integrations, and AI tooling. It preserves the broader JSON Schema Draft 4 vocabulary, including composition and reference keywords such as $ref, definitions, allOf, not, dependencies, and additionalItems.
  • rest-api uses the narrower keyword set supported by WordPress REST APIREST API The REST API is an acronym for the RESTful Application Program Interface (API) that uses HTTP requests to GET, PUT, POST and DELETE data. It is how the front end of an application (think “phone app” or “website”) can communicate with the data store (think “database” or “file system”) https://developer.wordpress.org/rest-api/ route schemas. Use it when preparing a schema that must follow the same conventions as a REST route’s argument or response schema.
// General client-facing or Ability schema.
$prepared_schema = wp_prepare_json_schema_for_client( $schema );

// Schema intended to match WordPress REST API conventions.
$prepared_rest_schema = wp_prepare_json_schema_for_client(
	$schema,
	'rest-api'
);

Both profiles produce JSON Schema Draft 4 output. The difference is the set of keywords retained in the prepared schema.

What is JSON Schema Draft 4?

“Draft 4” refers to the fourth published draft of the JSON Schema specification, which defines a JSON-based contract for describing and validating JSON data. See the JSON Schema Draft 4 core specification for its terminology and behaviour.

Schema transformations

Preparation is recursive and applies to nested object properties, array items, composition keywords, definitions, dependencies, and other subschemas.

Required properties use Draft 4 syntax

WordPress schemas may mark individual properties as required:

'properties' => array(
	'title' => array(
		'type'     => 'string',
		'required' => true,
	),
)

The prepared schema moves those property names into the containing object’s Draft 4 required array:

'required' => array( 'title' ),

The property-level boolean is then removed.

If the object already has a valid required array, that array takes precedence over property-level boolean values. A property-level required => false is removed without creating an empty required array.

A boolean required value on a scalar schema is also removed because it has no Draft 4 equivalent.

This preparation only affects schemas sent to clients. It does not change the server-side behaviour of rest_validate_value_from_schema() or WP_Ability::validate_input().

Example of transforming schema:

$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 );

The prepared schema is equivalent to:

array(
	'type'       => 'object',
	'required'   => array( 'title' ),
	'properties' => array(
		'title'   => array(
			'type' => 'string',
		),
		'content' => array(
			'type' => 'string',
		),
	),
);

The original $schema is not modified.

Server-only keywords are removed

PHP callbacks and other WordPress-specific keywords cannot be represented meaningfully in JSON. The preparation process removes unsupported keywords, including:

  • sanitize_callback
  • validate_callback
  • arg_options

These keywords are removed recursively, including when they appear inside:

  • properties
  • patternProperties
  • definitions
  • dependencies
  • items
  • additionalItems
  • additionalProperties
  • anyOf
  • oneOf
  • allOf
  • not

The callbacks remain available in the original server-side schema. They are removed only from its client-facing representation.

Ability authors should also note that validate_callback and sanitize_callback are not executed by the Abilities API’s runtime validation. Custom ability validation should use the wp_ability_validate_input and wp_ability_validate_output filters introduced in WordPress 7.1.

Empty object defaults are represented as objects

In PHP, an empty array serializes to [], even when its schema declares an object:

array(
	'type'    => 'object',
	'default' => array(),
)

For client-facing schemas, the empty default is prepared so that JSON serialization produces an object:

{
	"type": "object",
	"default": {}
}

This prevents client validators from rejecting the default because its serialized type does not match the declared object type.

Allowed keywords filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output.

wp_prepare_json_schema_for_client() uses wp_get_json_schema_allowed_keywords() to decide which keywords to preserve.

The broader draft-04 profile can preserve composition and documentation keywords such as:

  • $ref
  • definitions
  • allOf
  • not
  • dependencies
  • additionalItems

Preserving a keyword means that it may be included in the client-facing schema. It does not mean that WordPress validates or sanitizes values against that keyword on the server.

The allowed keyword list is filterable:

add_filter(
	'wp_json_schema_allowed_keywords',
	function ( $keywords, $schema_profile ) {
		if ( 'draft-04' === $schema_profile ) {
			$keywords[] = 'x-example-keyword';
		}

		return $keywords;
	},
	10,
	2
);

Custom keywords should only be exposed when the receiving clients are known to understand them.

Abilities REST API changes

WordPress now prepares an ability’s input and output schemas before including them in Abilities REST API responses.

For abilities registered with REST visibility, consumers of endpoints under:

/wp-json/wp-abilities/v1/abilities

receive portable schemas instead of the original WordPress-internal schema arrays.

This is an output-boundary transformation:

  • WP_Ability::get_input_schema() and WP_Ability::get_output_schema() continue to return the original schemas to server-side PHP.
  • REST responses contain prepared versions.
  • Ability execution and server-side validation remain unchanged.

Developers comparing a schema retrieved directly from a WP_Ability object with one returned through REST may therefore see intentional differences.

AI Client integration

When the WordPress AI Client converts abilities into function declarations, it now prepares each ability’s input schema first:

$input_schema = wp_prepare_json_schema_for_client(
	$ability->get_input_schema()
);

This prevents WordPress-only schema keywords and nonportable required conventions from being passed directly into AI function declarations.

The helper prepares a portable Draft 4 schema; it is not a provider-specific compiler. Individual AI providers may support a smaller schema vocabulary or impose additional requirements. Provider-specific adaptation may therefore still occur elsewhere in the integration.

Follow-up

Provider-specific adaptation is tracked in WordPress/php-ai-client#256: each provider should be able to override the input schema for its own API requirements, which differ across providers and evolve over time.

  • #64955 — Add schema compiler for AI tool calling compatibility
  • Changeset [62591] — Abilities API: Reuse JSON Schema client preparation
  • Changeset [62549] — REST API: Add a shared helper for JSON Schema allowed keywords.
  • Changeset [62449] — Abilities API: Normalize required schema shape for REST responses 

Props to @jorbin for peer review and suggested improvements.

#abilities-api, #7-1, #dev-notes, #dev-notes-7-1, #rest-api

Abilities API improvements in WordPress 7.1

WordPress 7.1 expands the Abilities APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. with custom validation hooksHooks In WordPress theme and development, hooks are functions that can be applied to an action or a Filter in WordPress. Actions are functions performed when a certain event occurs in WordPress. Filters allow you to modify certain functions. Arguments used to hook both filters and actions look the same., a new invocation lifecycle action, richer user information, selective field responses, and more consistent schemas for the coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. abilities introduced in WordPress 6.9.

Custom input and output validation

WP_Ability validates input and output against each ability’s JSONJSON JSON, or JavaScript Object Notation, is a minimal, readable format for structuring data. It is used primarily to transmit data between a server and web application, as an alternative to XML. Schema. WordPress 7.1 adds two filters that let extenders supplement that validation:

  • wp_ability_validate_input
  • wp_ability_validate_output

Each filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. receives the existing validation result, the value being validated, and the ability name:

/**
 * @param true|WP_Error $is_valid Validation result.
 * @param mixed         $value    Input or output value.
 * @param string        $name     Ability name.
 */

For example, a pluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party. can enforce a rule that cannot be expressed by the JSON Schema implementation used by WordPress:

add_filter(
	'wp_ability_validate_input',
	function ( $is_valid, $input, $ability_name ) {
		if ( 'my-plugin/send-message' !== $ability_name ) {
			return $is_valid;
		}

		// Preserve errors produced by the default schema validation.
		if ( is_wp_error( $is_valid ) ) {
			return $is_valid;
		}

		if (
			! is_array( $input )
			|| empty( $input['recipient'] )
			|| ! str_ends_with( $input['recipient'], '@example.com' )
		) {
			return new WP_Error(
				'invalid_recipient',
				__( 'The recipient must use the example.com domain.', 'my-plugin' )
			);
		}

		return true;
	},
	10,
	3
);

Output can be validated in the same way:

add_filter(
	'wp_ability_validate_output',
	function ( $is_valid, $output, $ability_name ) {
		if ( 'my-plugin/send-message' !== $ability_name ) {
			return $is_valid;
		}

		if ( is_wp_error( $is_valid ) ) {
			return $is_valid;
		}

		if ( ! is_array( $output ) || empty( $output['message_id'] ) ) {
			return new WP_Error(
				'invalid_message_output',
				__( 'The ability did not return a message ID.', 'my-plugin' )
			);
		}

		return true;
	},
	10,
	3
);

Callbacks should return true when the value is valid or a WP_Error describing why it is invalidinvalid A resolution on the bug tracker (and generally common in software development, sometimes also notabug) that indicates the ticket is not a bug, is a support request, or is generally invalid.. Returning false also fails validation, but WordPress converts it to a generic WP_Error. The filters operate on the validation result rather than the schema, allowing plugins to augment an existing error or reject data that otherwise passed JSON Schema validation.

REST-style validate_callback and sanitize_callback schema keywords are not executed by the Abilities API. Custom runtime validation should use these new filters. See ticketticket Created for both bug reports and feature development on the bug tracker. #64311.

Observing every ability invocation

WordPress 7.1 adds the wp_ability_invoked action at the beginning of WP_Ability::execute():

do_action( 'wp_ability_invoked', $this->name, $input, $this );

The action fires before input normalization, validation, permission checks, and the wp_pre_execute_ability short-circuit filter. Consequently, it runs for every invocation, including calls that:

  • contain invalid input;
  • fail their permission check;
  • are short-circuited;
  • return a cached result;
  • require approval; or
  • proceed to the execution callback.

This makes the action suitable for auditing, telemetry, tracing, and invocation accounting:

add_action(
	'wp_ability_invoked',
	function ( $ability_name, $input, $ability ) {
		// Avoid storing sensitive input without appropriate filtering.
		do_action(
			'my_plugin_record_ability_invocation',
			array(
				'ability'  => $ability_name,
				'timestamp' => time(),
			)
		);
	},
	10,
	3
);

The action receives raw, unnormalized input. Plugins should therefore avoid logging input indiscriminately, because it may contain credentials, personal information, or other sensitive data.

The existing wp_before_execute_ability and wp_after_execute_ability actions also receive the corresponding WP_Ability instance as an additional final argument. Existing callbacks continue to work unchanged. To receive the new argument, update the callback signature and $accepted_args. See ticket #65248.

Expanded core/get-user-info responses

The core/get-user-info ability now returns five additional profile fields for the current authenticated user:

  • first_name
  • last_name
  • nickname
  • description
  • user_url

When no input is supplied, the response contains all supported properties:

{
	"id": 1,
	"display_name": "Jane Doe",
	"user_nicename": "jane-doe",
	"user_login": "jane",
	"roles": [ "administrator" ],
	"locale": "en_US",
	"first_name": "Jane",
	"last_name": "Doe",
	"nickname": "Jane",
	"description": "Site administrator and contributor.",
	"user_url": "https://example.com"
}

The roles property is now normalized with array_values() so that it is consistently encoded as a JSON array, regardless of its PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 7.4 or higher array keys.

Callers can also use the new optional fields input property to request a subset of the response:

$ability = wp_get_ability( 'core/get-user-info' );

$result = $ability->execute(
	array(
		'fields' => array(
			'display_name',
			'first_name',
			'last_name',
		),
	)
);

The resulting value contains only the requested properties:

{
	"display_name": "Jane Doe",
	"first_name": "Jane",
	"last_name": "Doe"
}

Supported field names are declared through an enum in the input schema. Passing an unknown name causes execution to return an ability_invalid_input error before the ability callback runs.

The permission requirement remains unchanged: the requester must be logged in. See ticket #65234 and changeset [62419].

Consistent schemas across core abilities

The following core abilities now follow the same schema conventions:

  • core/get-site-info
  • core/get-user-info
  • core/get-environment-info

Every output property declares a translatable, Title Case title and a description. This provides better metadata to REST, MCP, WebMCP, AI, and other programmatic clients that use the schema to present or select ability fields.

core/get-environment-info now supports the same optional fields input as the other two abilities:

$ability = wp_get_ability( 'core/get-environment-info' );

$result = $ability->execute(
	array(
		'fields' => array( 'php_version' ),
	)
);

Unknown field names are rejected through schema validation.

In addition, core/get-user-info is now exposed through the REST APIREST API The REST API is an acronym for the RESTful Application Program Interface (API) that uses HTTP requests to GET, PUT, POST and DELETE data. It is how the front end of an application (think “phone app” or “website”) can communicate with the data store (think “database” or “file system”) https://developer.wordpress.org/rest-api/. Like the other core abilities, it declares the new public metaMeta Meta is a term that refers to the inside workings of a group. For us, this is the team that works on internal WordPress sites like WordCamp Central and Make WordPress. flag introduced in WordPress 7.1. Authenticated clients can discover it through:

/wp-json/wp-abilities/v1/abilities

The exact ordered set of input field names and output properties is covered by registration tests. Developers extending or consuming these core abilities should use the schemas for discovery rather than assuming a fixed response shape. See ticket #65355.

Typed input for REST ability runs

REST requests that run an ability over GET or DELETE deliver every query string value as a string, and a comma-separated list as a single string. In previous releases, the ability received this input as-is: an integer arrived as "10", a boolean as "true", and strict comparisons inside the callback silently failed unless the ability hand-rolled its own casting.

WordPress 7.1 coerces the input of a run request to the types declared in the ability’s input_schema before the ability runs. The coercion is registered as the input argument’s sanitize_callback, so the permission callback and the execute callback both receive natively typed input from the same request object:

GET /wp-json/wp-abilities/v1/abilities/my-plugin/list-items/run
    ?input[limit]=10&input[featured]=true&input[ids]=1,2,3

With an input schema declaring limit as an integer, featured as a boolean, and ids as an array of integers, the callbacks now receive:

array(
	'limit'    => 10,
	'featured' => true,
	'ids'      => array( 1, 2, 3 ),
)

Coercion never changes what validation accepts. Input is coerced only when validate_input() already accepts it, so invalid input reaches validation untouched and returns the same ability_invalid_input error as before.

Props to @benjamin_zekavica and @annezazu for peer review, and to @jorgefilipecosta for review and collaboration.

#abilities-api, #7-1, #dev-notes, #dev-notes-7-1, #rest-api

Design System Theming in WordPress 7.1

WordPress 7.1 will include foundational support for theming design aspects of adminadmin (and super admin) interface components, including color, roundness, and cursor pointers for interactive controls. The background and purpose behind these new features were shared previously in Merge Proposal: Design System Theming. This post aims to provide information about what is included with WordPress 7.1.

Design Tokens in the wp-theme stylesheet

A new wp-theme stylesheet will be registered by default and is available as a dependency for plugins. When enqueued, the stylesheet includes a full set of semantic design tokens formatted as CSS custom properties (variables) that can be referenced in WordPress or pluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party. styles that are building user interfaces for the wp-admin dashboard. Design tokens can be used in place of hard-coded values to keep styles in sync across related UIUI User interface components, for aspects such as color, typography, spacing, and more. When paired with the ThemeProvider, design tokens automatically inherit aspects of color and roundness for that area of a page.

Typically, design tokens would be used in the implementation of common WordPress UI components, and a plugin would use those components instead of interfacing with the design tokens directly in their own styles. But the design tokens are generally available for both WordPress-internal styling as well as a plugin’s unique use-cases so that styles can be applied consistently.

The following example demonstrates a hypothetical component for a simple card layout. In the blockBlock Block is the abstract term used to describe units of markup that, composed together, form the content or layout of a webpage using the WordPress editor. The idea combines concepts of what in the past may have achieved with shortcodes, custom HTML, and embed discovery into a single consistent API and user experience. editor or site editor, you should use the Card React component instead.

.card {
	background-color: var(--wpds-color-background-surface-neutral-strong);
	color: var(--wpds-color-foreground-content-neutral);
	border: var(--wpds-border-width-xs) solid var(--wpds-color-stroke-surface-neutral-weak);
	border-radius: var(--wpds-border-radius-lg);
	padding: var(--wpds-dimension-padding-2xl);
}
Screenshot of the card component described in the caption
An example card component inheriting ThemeProvider settings with a light gray background
Screenshot of the card component described in the caption
An example card component inheriting ThemeProvider settings with a dark blue background and a more pronounced border radius

To learn more about design tokens, refer to the “Design Tokens” section of the @wordpress/theme package documentation.

For more information about the available token options, a design system token reference describes the structure, purpose, and name of each token.

Design tokens are used as the basis for all components in the @wordpress/ui React component library, and is used in applying the user’s preferred color scheme to the Site Editor in WordPress 7.1. As a foundational piece, this will be expanded in subsequent WordPress releases to apply to more of the admin interface, which is detailed in the merge proposal.

ThemeProvider ReactReact React is a JavaScript library that makes it easy to reason about, construct, and maintain stateless and stateful user interfaces. https://reactjs.org component in the wp-theme script handle

A new wp-theme JavaScriptJavaScript JavaScript or JS is an object-oriented computer programming language commonly used to create interactive effects within web browsers. WordPress makes extensive use of JS for a better user experience. While PHP is executed on the server, JS executes within a user’s browser. https://www.javascript.com script handle will be registered by default and is available as a dependency for plugins. The wp-theme script provides a single ThemeProvider React component that can be used to wrap content in an area of the page to override the default design token values that are provide from the wp-theme stylesheet.

import { ThemeProvider } from '@wordpress/theme';
import { Card } from '@wordpress/ui';

function Application() {
	return (
		<ThemeProvider
			color={ { primary: '#3858e9', background: '#11004d' } }
			cornerRadius="pronounced"
		>
			<Card.Root>
				<Card.Content>
					WordPress is designed for everyone. We believe great
					software should work with minimum set up,
					emphasizing accessibility, performance, security,
					and ease of use.
				</Card.Content>
			</Card.Root>
		</ThemeProvider>
	);
}

Given a pair of primary and background seed color values, the component internally generates a color ramp which is visually harmonious and provides contrast between elements, such as between foreground and background, or between background and border. While the color algorithm aims for accessible contrast targets, it is not possible to guarantee for every color combination, so due diligence is still required to verify its outputs for a given set of colors.

ThemeProvider currently includes five options for customizing the behavior of a themed section of a page:

PropDescription
color.primaryThe primary seed color to use for the theme. Accepts a fully opaque sRGB-parseable string: a hex value (e.g. #3858e9), an rgb()/rgba() string, or a CSSCSS Cascading Style Sheets. named color (e.g. 'blue').
color.backgroundThe background seed color to use for the theme. Accepts a fully opaque sRGB-parseable string: a hex value (e.g. #f8f8f8), an rgb()/rgba() string, or a CSS named color (e.g. 'blue').
cursor.controlThe cursor style for interactive controls that are not links (e.g. buttons, checkboxes, and toggles). By default, it inherits from the parent ThemeProvider, and falls back to the prebuilt default (pointer).
cornerRadiusOverall roundness preset for the theme subtree: none (square corners), subtlemoderate, or pronounced (most rounded). By default, it inherits from the parent ThemeProvider, and falls back to the prebuilt default (subtle).
isRootWhen a ThemeProvider is the root provider, it will apply its theming settings also to the root document element (e.g. the html element). Render at most one root provider per document.

ThemeProvider can be used by plugin authors to express their unique brand identity while appearing consistent within the broader WordPress admin interface.

To learn more about using the ThemeProvider component, refer to the “Theme Provider” section of the @wordpress/theme package documentation.

Further Reading

  • Merge Proposal: Design System Theming (Make/CoreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. post)
  • Design System: Support for admin redesign (GitHubGitHub GitHub is a website that offers online implementation of git repositories that can easily be shared, copied and modified by other developers. Public repositories are free to host, private repositories require a paid subscription. GitHub introduced the concept of the ‘pull request’ where code changes done in branches by contributors can be reviewed and discussed before being merged by the repository owner. https://github.com/ issue)
  • A themeable and scalable primitive system (GitHub issue)

Props to @wildworks and @tyxla for reviewing this post’s content.

#dev-notes, #dev-notes-7-1

Filtering Site Editor Screens in WordPress 7.1

This work is part of the iteration issue DataViews, DataForm, et. al. in WordPress 7.1 and it has been tracked at #76544. Check the full details of the API in the handbook.

WordPress 7.1 introduces four new filters to configure Site Editor screens:

PageFilterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. name
Pagesget_entity_view_config_postType_page
Templatesget_entity_view_config_postType_wp_template
Partsget_entity_view_config_postType_wp_template_part
Patternsget_entity_view_config_postType_wp_block

Each filter can configure the DataViews and DataForm components that power those screens:

  • default_view: the default DataViews configuration (e.g., what fields are visible, what is the default sort order, etc.)
  • default_layouts: the default DataViews layouts (e.g., what layouts are available for the user to choose from)
  • view_list: the preconfigured views displayed in the sidebarSidebar A sidebar in WordPress is referred to a widget-ready area used by WordPress themes to display information that is not a part of the main content. It is not always a vertical column on the side. It can be a horizontal rectangle below or above the content area, footer, header, or any where in the theme. (e.g. “All”, “Published”, “Drafts”, etc.)
  • form: the DataForm configuration used for the Quick Edit form (e.g. which fields are displayed in the form and their order)

Filter callbacks receive an object with the config for the given entity with a set of methods to work with data (API). For example, this code will update the Pages screen by setting grid as the default layout, sort it by ascending title, and add a new visible field date:

function example_filter_page_view_config( $data ) {
	$patch = array(
        'default_view' => array(
            'type'   => 'grid',
            'sort'   => array(
                'field'     => 'title',
                'direction' => 'asc',
            ),
            'fields' => array( 'date' ),
        ),
    );
    $data->merge( $patch, 1 );

    return $data;
}
add_filter( 'get_entity_view_config_postType_page', 'example_filter_page_view_config' );

Next steps

This mechanism is designed to grow in the future by creating filters for other entities and updating screens to use them. The goal is to have a single place of configuration for an entity that works across screens and components. An example of this work is the experiment to power the editor inspector (built with DataForm) with the data coming from these filters, consolidating Site Editor’s QuickEdit and the editor inspectors.

Future work also includes registration of fields that work across DataViews and DataForm.

Props to @ntsekouras and @priethor for review.

#dev-notes #dev-notes-7-1 #7-1

Leaner, steadier PHPUnit runs for upcoming releases

In recent years, the CI load across coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. WordPress GitHubGitHub GitHub is a website that offers online implementation of git repositories that can easily be shared, copied and modified by other developers. Public repositories are free to host, private repositories require a paid subscription. GitHub introduced the concept of the ‘pull request’ where code changes done in branches by contributors can be reviewed and discussed before being merged by the repository owner. https://github.com/ repos increased as the project evolved. This is normal for an active project.

But, the load can be especially high when running the full PHPUnit matrix at once on many PRs, such as during a release with many backportbackport A port is when code from one branch (or trunk) is merged into another branch or trunk. Some changes in WordPress point releases are the result of backporting code from trunk to the release branch. branches. Cases like this mean the number of jobs can strain the capacity of the system.

Ahead of 7.1, we’ve landed a round of trims and reliability fixes aimed at increasing capacity and running leaner while ensuring quality checks still run.

This CI work builds on the test-suite optimization work from many contributors in the past.

Two key changes

  1. Trimmed the PHPUnit matrix to boundary PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 7.4 or higher versions (#12719 on trunktrunk A directory in Subversion containing the latest development code in preparation for the next major release cycle. If you are running "trunk", then you are on the latest revision., #12720 for 7.0). Full PHP coverage kept, redundant database combinations dropped. Per run: ~52% fewer jobs and ~54% fewer job-minutes.
  2. Fetch the GutenbergGutenberg The Gutenberg project is the new Editor Interface for WordPress. The editor improves the process and experience of creating new content, making writing rich content much simpler. It uses ‘blocks’ to add richness rather than shortcodes, custom HTML etc. https://wordpress.org/gutenberg/ build once per run (#12701) instead of once per job, plus bounded retries on Docker image pulls (#12703). Runs needing a rerun to go green roughly halved, from ~68% to ~36%.

Source: measured per run from the GitHub Actions APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. (job counts and durations, and rerun counts) across comparable runs before / after the changes.

Next up

  • Trim the 6.8 matrix (#12726).
  • Pilot a dedicated larger-runner pool for use during release windows to help with concurrency issues (more on that in a future update).

Note: The PHPUnit tests themselves could be further tuned. The trims above cut job count, not job duration—so we could give more attention to the tests themselves to find more efficiency.

Thanks to contributions from adrianmoldovanwp, barry, garyj, @johnbillion, @jonsurrell, @jorbin, lucasbustamante, and @mukesh27.

jQuery UI updated to 1.14.2 in WordPress 7.1

WordPress 7.1 includes an update to the latest stable version of jQuery UI, 1.14.2 from version 1.13.3. This update drops support for all versions of Internet Explorer & Edge Legacy which is inline with the WordPress Browser Support Policy.

This update sets jQuery.uiBackCompat to be equal to true to ensure that code written for the jQuery 1.11 APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways. continues to function as expected. Additionally, $.fn._form, $.ui.ie, $.ui.safeActiveElement, and $.ui.safeBlur have been removed. WordPress coreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. does not use any of these functions, but you should check your code and update it accordingly if it does.

See [62747] for the specific changes and #62757 for more background information.

props @masteradhoc and @joedolson for review

#7-1, #dev-notes, #dev-notes-7-1, #external-libraries

New execution lifecycle filters for the Abilities API in WordPress 7.1

WordPress 7.1 introduces four filters that allow plugins to customise the execution lifecycle of abilities registered with the Abilities APIAPI An API or Application Programming Interface is a software intermediary that allows programs to interact with each other and share data in limited, clearly defined ways..

The Abilities API previously provided the wp_before_execute_ability and wp_after_execute_ability actions. These actions are useful for observing execution, but they cannot change its behaviour.

The new filters allow developers to:

  • Short-circuit ability execution.
  • Transform normalised input.
  • Apply additional authorisation rules.
  • Transform or recover an execution result.

These changes were introduced in TracTrac An open source project by Edgewall Software that serves as a bug tracker and project management tool for WordPress. ticketticket Created for both bug reports and feature development on the bug tracker. #64989 and changeset [62397].

Updated execution lifecycle

The filters are applied in the following order:

wp_pre_execute_ability
        │
        ├── short-circuit when an override is returned
        ↓
WP_Ability::normalize_input()
        ↓
wp_ability_normalize_input
        ↓
WP_Ability::validate_input()
        ↓
WP_Ability::check_permissions()
        ↓
wp_ability_permission_result
        ↓
wp_before_execute_ability
        ↓
Registered execute callback
        ↓
wp_ability_execute_result
        ↓
WP_Ability::validate_output()
        ↓
wp_after_execute_ability
        ↓
Return result

Input and output transformations occur before their respective schema-validation steps. Transformed values must therefore continue to satisfy the ability’s registered schemas.

The exception is wp_pre_execute_ability, which bypasses the rest of the pipeline completely.

Short-circuiting execution with wp_pre_execute_ability

The wp_pre_execute_ability filterFilter Filters are one of the two types of Hooks https://codex.wordpress.org/Plugin_API/Hooks. They provide a way for functions to modify data of other functions. They are the counterpart to Actions. Unlike Actions, filters are meant to work in an isolated manner, and should never have side effects such as affecting global variables and output. runs at the beginning of WP_Ability::execute(), before input normalization, validation or permission checks.

/**
 * Filters whether to short-circuit ability execution.
 *
 * @param mixed      $pre          Precomputed result. Return it unchanged to
 *                                 continue normal execution.
 * @param string     $ability_name Name of the ability.
 * @param mixed      $input        Raw input passed to execute().
 * @param WP_Ability $ability      Ability instance.
 */
apply_filters(
    'wp_pre_execute_ability',
    $pre,
    $ability_name,
    $input,
    $ability
);

Returning $pre unchanged allows execution to continue. Returning any other value short-circuits execution and returns that value directly to the caller.

The filter uses a unique internal sentinel as its default. This means that any PHPPHP The web scripting language in which WordPress is primarily architected. WordPress requires PHP 7.4 or higher value—including null, false, or an object—can be used as a legitimate short-circuit result.

The filter can be used for caching, rate limiting, maintenance mode, approval workflows and test mocking.

Temporarily disabling an ability

The filter can short-circuit selected abilities during maintenance without running input validation, permission checks, or the registered callback:

add_filter(
    'wp_pre_execute_ability',
    function ( $pre, $ability_name, $input, $ability ) {
        if ( 'my-plugin/sync-catalog' !== $ability_name ) {
            return $pre;
        }

        if ( ! get_option( 'my_plugin_maintenance_mode', false ) ) {
            return $pre;
        }

        return new WP_Error(
            'ability_temporarily_unavailable',
            __( 'This operation is temporarily unavailable due to maintenance.', 'my-plugin' ),
            array(
                'status' => 503,
            )
        );
    },
    10,
    4
);

Returning $pre unchanged continues normal execution. When maintenance mode is enabled, the WP_Error is returned immediately, and the remaining ability pipeline is bypassed.

Because this filter runs before permission checks and validation, it should make only narrow decisions that do not depend on validated input or the current ability authorisation result.

Transforming input with wp_ability_normalize_input

The wp_ability_normalize_input filter runs inside WP_Ability::normalize_input(), after the method has applied any defaults declared by the input schema.

/**
 * Filters normalized ability input.
 *
 * @param mixed      $input        Normalized input.
 * @param string     $ability_name Name of the ability.
 * @param WP_Ability $ability      Ability instance.
 */
apply_filters(
    'wp_ability_normalize_input',
    $input,
    $ability_name,
    $ability
);

This filter can be used to:

  • Add defaults that cannot be expressed through JSONJSON JSON, or JavaScript Object Notation, is a minimal, readable format for structuring data. It is used primarily to transmit data between a server and web application, as an alternative to XML. Schema.
  • Normalize incoming values.
  • Enrich an AI prompt.
  • Inject caller or execution-context metadata.

Adding contextual input

add_filter(
    'wp_ability_normalize_input',
    function ( $input, $ability_name, $ability ) {
        if ( 'my-plugin/process-content' !== $ability_name ) {
            return $input;
        }

        if ( ! is_array( $input ) ) {
            $input = array();
        }

        $input['requesting_user_id'] = get_current_user_id();
        $input['site_url']           = home_url();

        return $input;
    },
    10,
    3
);

The transformed input is subsequently checked against the ability’s input_schema.

Returning a WP_Error stops execution before input validation, permission checks and the registered callback:

add_filter(
    'wp_ability_normalize_input',
    function ( $input, $ability_name ) {
        if ( 'my-plugin/process-content' !== $ability_name ) {
            return $input;
        }

        if ( my_plugin_rate_limit_exceeded() ) {
            return new WP_Error(
                'ability_rate_limit_exceeded',
                __( 'The ability rate limit has been exceeded.', 'my-plugin' ),
                array( 'status' => 429 )
            );
        }

        return $input;
    },
    10,
    2
);

When execution occurs through the Abilities REST APIREST API The REST API is an acronym for the RESTful Application Program Interface (API) that uses HTTP requests to GET, PUT, POST and DELETE data. It is how the front end of an application (think “phone app” or “website”) can communicate with the data store (think “database” or “file system”) https://developer.wordpress.org/rest-api/, a WP_Error returned during normalization is now propagated by the REST controller. It defaults to HTTPHTTP HTTP is an acronym for Hyper Text Transfer Protocol. HTTP is the underlying protocol used by the World Wide Web and this protocol defines how messages are formatted and transmitted, and what actions Web servers and browsers should take in response to various commands. status 400 unless the error specifies another status, such as 422 or 429.

Filtering permission results with wp_ability_permission_result

The wp_ability_permission_result filter runs inside WP_Ability::check_permissions(), after the registered permission_callback has executed.

/**
 * Filters the result of an ability permission check.
 *
 * @param bool|WP_Error $permission   Result from permission_callback.
 * @param string        $ability_name Name of the ability.
 * @param mixed         $input        Input used for the permission check.
 * @param WP_Ability    $ability      Ability instance.
 */
apply_filters(
    'wp_ability_permission_result',
    $permission,
    $ability_name,
    $input,
    $ability
);

The filter may return:

  • true to permit execution.
  • false to deny execution.
  • A WP_Error to deny execution with a specific error and message.

Any other return value is converted to false.

Because the filter is part of check_permissions(), it also applies when permission checks are performed independently of execute(), including REST API and WP-CLIWP-CLI WP-CLI is the Command Line Interface for WordPress, used to do administrative and development tasks in a programmatic way. The project page is http://wp-cli.org/ https://make.wordpress.org/cli/ integrations.

Applying an additional authorisation policy

add_filter(
    'wp_ability_permission_result',
    function ( $permission, $ability_name, $input, $ability ) {
        if ( 'my-plugin/delete-records' !== $ability_name ) {
            return $permission;
        }

        // preserve both false and WP_Error results
        if ( false === $permission || is_wp_error( $permission ) ) {
            return $permission;
        }

        if ( ! current_user_can( 'manage_options' ) ) {
            return new WP_Error(
                'ability_additional_permission_required',
                __( 'This operation requires administrator access.', 'my-plugin' )
            );
        }

        return true;
    },
    10,
    4
);

Plugins should exercise particular care with this filter because returning true can override a denial from the ability’s original permission_callback.

Transforming results with wp_ability_execute_result

The wp_ability_execute_result filter runs after the ability’s registered execution callback and before output validation.

/**
 * Filters the result returned by an ability execute callback.
 *
 * @param mixed      $result       Result returned by the execute callback,
 *                                 or WP_Error when execution failed.
 * @param string     $ability_name Name of the ability.
 * @param mixed      $input        Normalized input.
 * @param WP_Ability $ability      Ability instance.
 */
apply_filters(
    'wp_ability_execute_result',
    $result,
    $ability_name,
    $input,
    $ability
);

Possible uses include:

  • Formatting a response.
  • Removing internal metadata.
  • Applying content-safety filtering.
  • Enriching a result.
  • Converting a successful result into an error.
  • Recovering from an execution error.

Removing internal response data

add_filter(
    'wp_ability_execute_result',
    function ( $result, $ability_name, $input, $ability ) {
        if (
            'my-plugin/get-report' !== $ability_name ||
            is_wp_error( $result ) ||
            ! is_array( $result )
        ) {
            return $result;
        }

        unset( $result['internal_debug_data'] );

        return $result;
    },
    10,
    4
);

The filtered result is subsequently validated against the ability’s output_schema.

Recovering from selected execution failures

The filter receives WP_Error values produced by the registered callback, so plugins may implement narrowly scoped recovery behaviour:

add_filter(
    'wp_ability_execute_result',
    function ( $result, $ability_name, $input, $ability ) {
        if (
            'my-plugin/get-remote-data' !== $ability_name ||
            ! is_wp_error( $result ) ||
            'remote_service_unavailable' !== $result->get_error_code()
        ) {
            return $result;
        }

        $fallback = my_plugin_get_fallback_data();

        /*
         * The fallback must conform to the ability's registered
         * output_schema because it will be validated after this filter.
         */
        return $fallback;
    },
    10,
    4
);

Any recovered value must still conform to the registered output_schema.

New WP_Filter_Sentinel class

WordPress 7.1 also introduces WP_Filter_Sentinel, a reusable marker class loaded alongside WP_Hook.

CoreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. uses a unique sentinel instance as the default value for wp_pre_execute_ability. Comparing object identity allows Core to distinguish an unchanged default from every possible user-supplied value, including null, false, arrays and arbitrary objects.

Developers using wp_pre_execute_ability do not need to instantiate this class. To continue normal execution, callbacks should simply return the received $pre value unchanged.

Backward compatibility

These changes are additive:

  • Existing abilities require no changes.
  • Existing wp_before_execute_ability and wp_after_execute_ability callbacks continue to work.
  • Ability callbacks and permission callbacks retain their existing behaviour when none of the new filters is used.
  • Input and output schemas remain the final validation boundaries for normal execution.

Plugins that already provide their own ability-execution hooksHooks In WordPress theme and development, hooks are functions that can be applied to an action or a Filter in WordPress. Actions are functions performed when a certain event occurs in WordPress. Filters allow you to modify certain functions. Arguments used to hook both filters and actions look the same. may wish to evaluate whether some functionality can now use these Core filters. Protocol- or domain-specific hooks can still be layered on top when they need more specialised context.

Summary

WordPress 7.1 adds the following Abilities API filters:

FilterPurpose
wp_pre_execute_abilityShort-circuit the complete execution pipeline
wp_ability_normalize_inputTransform normalized input before validation
wp_ability_permission_resultModify or override permission results
wp_ability_execute_resultTransform or recover results before output validation

These filters make the Abilities API more extensibleExtensible This is the ability to add additional functionality to the code. Plugins extend the WordPress core software. for AI integrations, automation systems, protocol adapters, authorisation layers and other tools that mediate ability execution.

For additional context, see Trac ticket #64989 and changeset [62397].

Props to @benjamin_zekavica and @audrasjb for peer review.

#abilities-api, #7-1, #dev-notes, #dev-notes-7-1

X-post: Help shape the next chapter of WP Credits: a developer track, and a pilot opportunity

X-comment from +make.wordpress.org/community: Comment on Help shape the next chapter of WP Credits: a developer track, and a pilot opportunity

Performance Chat Summary: 28 July 2026

The full chat log is available beginning here on Slack.

WordPress Performance TracTrac An open source project by Edgewall Software that serves as a bug tracker and project management tool for WordPress. tickets

  • @westonruter highlighted #65634, a minor improvement to the development environment to make it easier to do performance tests so it is more reflective of an actual normal environment, with a small patchpatch A special text file that describes changes to code, by identifying the files and lines which are added, removed, and altered. It may also be referred to as a diff. A patch can be applied to a codebase for testing. ready for review.
  • For #65215, @westonruter shared that there is some feedback on the PR #11790 that has not been actioned yet.

    Performance Lab PluginPlugin A plugin is a piece of software containing a group of functions that can be added to a WordPress website. They can extend functionality or add new features to your WordPress websites. WordPress plugins are written in the PHP programming language and integrate seamlessly with WordPress. These can be free in the WordPress.org Plugin Directory https://wordpress.org/plugins/ or can be cost-based plugin from a third-party. (and other performance plugins)

    • @westonruter highlighted PR #2601, which updates wp-coding-standards/wpcs to 3.4.1, and shared that there was an important security release for WPCSWordPress Community Support A public benefit corporation and a subsidiary of the WordPress Foundation, established in 2016.. While it has been applied to the Performance repo, anyone with other repositories using an older version should update as soon as possible.
    • @mukesh27 shared that work has been ongoing over the past few weeks on accurate sizes for the Gallery blockBlock Block is the abstract term used to describe units of markup that, composed together, form the content or layout of a webpage using the WordPress editor. The idea combines concepts of what in the past may have achieved with shortcodes, custom HTML, and embed discovery into a single consistent API and user experience. and that the full PR will soon be ready for review.
    • @b1ink0 asked for feedback on a comment in PR #2336. @westonruter shared that it has been added to saved items.

    Our next chat will be held on Tuesday, August 11, 2026 at 16:00 UTC in the #core-performance channel in Slack.

    #core-performance, #hosting, #performance, #performance-chat, #summary

    Dev Chat Agenda – July 28, 2026

    The next WordPress Developers Chat will take place on Tuesday, July 28, 2026, at 15:00 UTC in the core channel on Make WordPress Slack.

    The live meeting will focus on the discussion for upcoming releases, and have an open floor section.

    The various curated agenda sections below refer to additional items. If you have ticketticket Created for both bug reports and feature development on the bug tracker. requests for help, please continue to post details in the comments section at the end of this agenda or bring them up during the dev chat.

    Announcements 📢

    Note: Dev Chat has been moved to Tuesdays at 15:00 UTC for the duration of the 7.1 release cycle.

    7.1

    General

    Discussions 💬

    The discussion section of the agenda is for discussing important topics affecting the upcoming release or larger initiatives that impact the CoreCore Core is the set of software required to run WordPress. The Core Development Team builds WordPress. Team. To nominate a topic for discussion, please leave a comment on this agenda with a summary of the topic, any relevant links that will help people get context for the discussion, and what kind of feedback you are looking for from others participating in the discussion.

    Open floor  🎙️

    Any topic can be raised for discussion in the comments, as well as requests for assistance on tickets. Tickets in the milestone for the next major or maintenance release will be prioritized.

    Please include details of tickets / PRs and the links in the comments, and indicate whether you intend to be available during the meeting for discussion or will be async.

    #7-1, #agenda, #core, #dev-chat