7-0 – Make WordPress Core
Skip to content
Make WordPress Core
Welcome!
The WordPress
core
Core
Core is the set of software required to run WordPress. The Core Development Team builds WordPress.
development team builds WordPress! Follow this site for general updates, status reports, and the occasional code debate. There’s lots of ways to contribute:
Found a
bug
bug
A bug is an error or unexpected result. Performance improvements, code optimization, and are considered enhancements, not defects. After feature freeze, only bugs are dealt with, with regressions (adverse changes from the previous version) being the highest priority.
Create a ticket
in the bug tracker.
Want to contribute?
Get started quickly with tickets marked as
good first bugs
for new contributors or join a
bug scrub
. There’s more on the
reports page
, like
patches needing testing
, and on
feature projects page
Other questions?
Here is a detailed
handbook for contributors
, complete with tutorials.
Communication
Core uses
Slack
for real-time communication. Contributors live all over the world, so there are discussions happening at all hours of the day.
Core development meetings are every Wednesday at
15:00 UTC
in the
#core
channel on
Slack
. Anyone can join and participate or listen in!
Below you find a table that lists all
core
Core
Core is the set of software required to run WordPress. The Core Development Team builds WordPress.
blocks available in the inserter marks in the grid the feature they support in the
block
Block
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. It’s a basic lookup table that helps developers to find the information quickly.
While this post is released as part of 6.8, the content summarizes changes between 6.1 and 7.0. This is an
updated of the 6.8 edition
and provides a cumulative list of design supports added with the last ten WordPress releases. The icon ☑️ indicates new in 6.9 or 7.0.
The features covered are:
Align
Typography
Color
Dimension
Border
Layout
Gradient
Duotone
Shadow
Background image
Changes to Blocks
The Verse block was renamed to
Poetry
block in WordPress 7.0
New Blocks added
Accordion with Accordion Heading, Accordion Item, Accordion Panel
Breadcrumbs
Icon
Math
Post Time to Read
Term Query with Term Template, Term Count, Term Name
Table changes
In previous editions of this roster, the
PO/BB column
tracked a small, hardcoded set of core blocks where Pattern Overrides and Block Bindings were manually enabled — Button, Image, Paragraph, and Heading. That model no longer reflects how the feature works. WordPress 6.9 moved Block Bindings to a server-communicated list of supported attributes via the
block_bindings_supported_attributes
filter
Filter
Filters are one of the two types of 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.
, and WordPress 7.0 extended that same mechanism to Pattern Overrides, so any block attribute that opts into Block Bindings now also supports Pattern Overrides — including custom blocks. Because support is opt-in per block, per attribute, and per site, a single check mark in a lookup table can no longer represent it accurately. The column has been removed in favor of a note pointing readers to the
Pattern Overrides in WP 7.0
and
Block Bindings improvements in 6.9
dev notes
dev note
Each important change in WordPress Core is documented in a developers note, (usually called dev note). Good dev notes generally include a description of the change, the decision that led to this change, and a description of how developers are supposed to work with that change. Dev notes are published on Make/Core blog during the beta phase of WordPress release cycle. Publishing dev notes is particularly important when plugin/theme authors and WordPress developers need to be aware of those changes.In general, all dev notes are compiled into a Field Guide at the beginning of the release candidate phase.
Block
Align
Typography
Color
Dimension
Border
Layout
Gradient
Duotone
Shadow
Backgr.Img
Accordion
☑️ new
☑️ new
☑️ new
☑️ new
☑️ new
☑️ new
☑️ new
☑️ new
☑️ new
Accordion Heading
☑️ new
☑️ new
☑️ new
☑️ new
☑️ new
☑️ new
Accordion Item
☑️ new
☑️ new
☑️ new
☑️ new
☑️ new
☑️ new
☑️ new
Accordion Panel
☑️ new
☑️ new
☑️ new
☑️ new
☑️ new
☑️ new
☑️ new
Archives
Audio
Avatar
Avatar
An avatar is an image or illustration that specifically refers to a character that represents an online user. It’s usually a square box that appears next to the user’s name.
Breadcrumbs
☑️ new
☑️ new
☑️ new
☑️ new
☑️ new
☑️ new
Button
Buttons
Calendar
Categories
Code
Column
Columns
Comment Author Avatar
Comment Author Name
Comment Content
Comment Date
Comment Edit Link
Comment Reply Link
Comment Template
☑️ new
Comments
☑️ new
Comments Pagination
Comments Pagination Next
Comments Pagination Numbers
☑️ new
Comments Pagination Previous
Comments Title
Cover
☑️ new
☑️ new
Details
☑️ new
Embed
File
Footnotes
Gallery
Group
Heading
Home Link – Navigation
HTML
HTML
HyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers.
Icon
☑️ new
☑️ new
☑️ new
☑️ new
Image
Latest Comments
Latest Posts
List
List Item
☑️ new
Login/logout
Math
☑️ new
☑️ new
☑️ new
☑️ new
☑️ new
Media & Text
More (Read More)
☑️ new
Navigation Link
Navigation Submenu
☑️ new
Next Page (Page Break)
Page List
Paragraph
☑️ new
Poetry (formerly Verse)
Post Author
☑️ new
Post Author Biography
Post Author Name
Post Comments Count
☑️ new
Post Comments Form
Post Comments Link
☑️ new
Post Content
Post Date
Post
Excerpt
Excerpt
An excerpt is the description of the blog post or page that will by default show on the blog archive page, in search results (SERPs), and on social media. With an SEO plugin, the excerpt may also be in that plugin’s metabox.
Post
Featured Image
Featured image
A featured image is the main image used on your blog archive page and is pulled when the post or page is shared on social media. The image can be used to display in widget areas on your site or in a summary list of posts.
Post Navigation Link
Post Template
Post Terms
Post Title
Preformatted
✅ no link
Pullquote
Query
Query No Results
Query Pagination
Query Pagination Next
Query Pagination Numbers
Query Pagination Previous
Query Title
Query Total
Quote
RSS
Separator
Site Logo
Site Tagline
Site Title
Social Link
Social Links
Spacer
Table
Tag Cloud
Template Part
Term Count
☑️ new
☑️ new
☑️ new
☑️ new
☑️ new
Term Description
Term Name
☑️ new
☑️ new
☑️ new
☑️ new
☑️ new
☑️ new
Terms Query
☑️ new
☑️ new
Term Template
☑️ new
☑️ new
☑️ new
☑️ new
☑️ new
☑️ new
☑️ new
Time To Read
☑️ new
☑️ new
☑️ new
☑️ new
☑️ new
Video
Props to
awetz583
westonruter
, and
blackstar1991
for review.
7-0
dev-notes
dev-notes-7-0
editor
WordPress 7.0 will introduce real-time collaboration in the
block
Block
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. Out of the box, the editor syncs changes between peers using an
HTTP
HTTP
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.
polling provider. However, an HTTP polling transport isn’t the only option and it may not be the best fit for your infrastructure, especially if you are a WordPress hosting provider.
The
sync.providers
client-side
filter
Filter
Filters are one of the two types of 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.
proposed for WordPress 7.0 lets you replace the default transport with your own. This post walks through why you’d want to use one, what a provider does, and how to build one.
Why build a custom provider?
The default HTTP polling provider is designed to work on any WordPress installation. It batches document and awareness updates into periodic HTTP requests: every four seconds when editing alone, every second when collaborators are present. (
These values are filterable.
It works reliably, but there can be good reasons to swap it out:
Lower latency.
Transports such as WebSockets deliver updates as they happen, not on a polling interval. For sites doing heavy collaborative editing, the difference can be noticeable.
Reduced server load.
Polling generates requests even when nothing has changed. A push-based transport only sends data when needed.
Infrastructure alignment.
If you already run WebSocket servers or other real-time transport, you can benefit from using familiar infrastructure with WordPress.
These benefits come with a substantial overhead. Building a custom provider is not trivial. It will require custom code. Most likely, it will also involve
deploying
Deploy
Launching code from a local development environment to the production web server, so that it's available to visitors.
and maintaining server resources.
What a sync provider does
Real-time collaboration in WordPress is powered by
Yjs
, a
Conflict
conflict
A conflict occurs when a patch changes code that was modified after the patch was created. These patches are considered
stale
, and will require a
refresh
of the changes before it can be applied, or the conflicts will need to be
resolved
-free Replicated Data Type (CRDT) library. WordPress content is represented by Yjs documents; syncing happens by exchanging updates to those documents.
The sync provider is the transport layer. It facilitates the exchange of Yjs document updates between peers.
Concretely, a provider needs to:
Receive local Yjs document updates
and send them to remote peers.
Receive remote updates
and apply them to the local Yjs document.
Report connection status
so the editor
UI
UI
User interface
can show whether the user is connected.
Gutenberg
Gutenberg
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.
’s sync manager orchestrates the syncing process. It creates a sync provider for each Yjs document that will be synced. Therefore, supplying a custom sync provider means supplying a provider creator function. A provider creator is an async function following this example:
async function myProviderCreator( options ) {
const objectType = options.objectType; // e.g., "postType/post"
const objectId = options.objectId; // e.g., "123"
const ydoc = options.ydoc; // Yjs document
const awareness = options.awareness; // Yjs awareness
// Create provider.
const room = `${ objectType }:${ objectId }`;
const provider = new MyYjsProvider( ydoc, awareness, room );
// Connect.
provider.connect();
return {
destroy: () => provider.destroy(),
on: ( event, callback ) => provider.on( event, callback ),
};
Note that the returned object has two function properties that the provider must implement:
destroy()
: The sync manager will call this function when it is time to close connections, remove listeners, and free resources.
on()
: This function allows the sync manager to subscribe to connection state changes. Emit
{ status: 'connecting' }
{ status: 'connected' }
, or
{ status: 'disconnected', error?: ConnectionError }
as appropriate.
A disconnected event can be accompanied by an error. Using specific error codes allows the editor to give specific feedback to the user. See
the list of error codes
and resulting messaging.
Existing Yjs providers
You don’t have to build a sync provider from scratch. Yjs has
a provider ecosystem
and several existing libraries can handle the heavy lifting.
y-websocket
is the most widely used Yjs provider and has been
deployed
Deploy
Launching code from a local development environment to the production web server, so that it's available to visitors.
by
WordPress VIP
and other WordPress hosts. It includes both a client and a simple Node.js server.
Note:
y-webrtc
is nominally a peer-to-peer provider that syncs via WebRTC, but in practice it
requires centralized servers to reliably connect peers
with each other. It is not recommended unless you are willing to invest in those servers.
Minimal client example with y-websocket
Wrapping a Yjs provider in a ProviderCreator function is straightforward, as seen in the following example. However, note that this example is missing essential authorization checks (discussed in the next section):
import { addFilter } from '@wordpress/hooks';
import { WebsocketProvider } from 'y-websocket';
addFilter( 'sync.providers', 'my-plugin/websocket', () => {
return [
async ( { objectType, objectId, ydoc, awareness } ) => {
const roomName = `${ objectType }-${ objectId ?? 'collection' }`;
const provider = new WebsocketProvider(
'wss://my-sync-server.example.com',
roomName,
ydoc,
{ awareness }
);
return {
destroy: () => provider.destroy(),
on: ( event, callback ) => provider.on( event, callback ),
};
},
];
} );
This code replaces the default HTTP polling provider entirely. The filter callback ignores the incoming providerCreators array and returns a new array containing a single WebSocket-based provider creator.
The WebSocket server (
wss://my-sync-server.example.com
in the example above) must be configured and deployed separately. The
y-websocket-server
library is the server companion to y-websocket.
Authorization and security
A custom sync provider connects to infrastructure that you own and operate, e.g., a WebSocket server. Because that infrastructure lives outside of WordPress, WordPress can’t authorize requests to it on your behalf.
Securing the connection between the editor and your sync server is your responsibility—a critical one. Without authorization checks, any user could connect to your WebSocket server and participate in a collaborative session with your WordPress users.
Token-based auth
A common pattern is to issue short-lived tokens via a WordPress
REST API
REST 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”)
endpoint, then pass the token when opening the WebSocket connection. The tokens assert that the user has permission to collaborate on a specific entity.
Here’s a simplified example of how the
WPVIP Real-Time Collaboration plugin
handles it:
// Fetch a short-lived token from a WordPress REST endpoint.
// This endpoint is provided by your plugin. Tokens encode the
// type and ID of the entity being edited, as well as the current
// WordPress user ID.
const data = await apiFetch( {
path: '/my-plugin/v1/sync/auth',
method: 'GET',
data: { objectType, objectId },
} );
// Pass the token as a query parameter when connecting.
provider.params = { auth: data.token };
provider.connect();
Key considerations
Validate on the server.
Never trust the client. The sync server should verify the token on every connection request. The token should encode information about the user, the entity being edited, and which actions are authorized. The sync server should validate each assertion and reject unauthorized connections before applying any document updates.
Authorize per-document.
It’s worth restating: Don’t just authenticate the user, additionally verify they have permission to edit the specific post or entity being synced. Your WebSocket server should validate this on every connection.
Rotate tokens.
WebSocket connections are long-lived. Use short-lived tokens and re-authenticate on reconnect so that revoked permissions take effect promptly.
Handle disconnects gracefully
. When authorization fails or a token is
invalid
invalid
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.
, emit a
{ status: 'disconnected', error }
event so the editor can inform the user. The WPVIP
plugin
Plugin
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
or can be cost-based plugin from a third-party.
maps WebSocket close codes to specific error types to give users actionable feedback.
The
WPVIP Real-Time Collaboration plugin
is a functional and secure example using WebSockets. It’s
open source
Open Source
Open Source denotes software for which the original source code is made freely available and may be redistributed and modified. Open Source **must be** delivered via a licensing model, see GPL.
and contributions are welcome.
Feedback
If you have questions or feedback about building a custom sync provider, please share them in a comment on this post or in the
hosting
channel of
Make WordPress Slack
Props to
jorbin
and
westonruter
for feedback and contributions.
7-0
dev-notes
dev-notes-7-0
feature-real-time-collaboration
WordPress 6.9 introduced the
Abilities API
. The
API
API
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.
provides a common interface that AI agents, workflow automation tools, and plugins can use to interact with WordPress. In WordPress 7.0 we continued that work and now provide a counterpart
JavaScript
JavaScript
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.
API that can be used to implement client-side abilities like navigating, or inserting blocks. This work is fundamental to integrate with browser agents/extensions and
WebMCP
Two packages
The client-side Abilities API is split into two packages:
@wordpress/abilities
: A pure state management package with no WordPress server dependencies. It provides the store, registration functions, querying, and execution logic. Use this when you only need the abilities store without loading server-registered abilities. This package could also be used in non-WordPress projects.
@wordpress/core-abilities
:The WordPress integration layer. When loaded, it automatically fetches all abilities and categories registered on the server via the
REST API
REST 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”)
/wp-abilities/v1/
) and registers them in the
@wordpress/abilities
store with appropriate callbacks.
Getting started
To use the Abilities API in your
plugin
Plugin
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
or can be cost-based plugin from a third-party.
, you need to enqueue the appropriate script module.
When your plugin needs server-registered abilities
If your plugin needs access to abilities registered on the server (e.g.,
core
Core
Core is the set of software required to run WordPress. The Core Development Team builds WordPress.
abilities), enqueue
@wordpress/core-abilities
. This is the most common case:
add_action( 'admin_enqueue_scripts', 'my_plugin_enqueue_abilities' );
function my_plugin_enqueue_abilities() {
wp_enqueue_script_module( '@wordpress/core-abilities' );
This will load both
@wordpress/core-abilities
and its dependency
@wordpress/abilities
, and automatically fetch and register all server-side abilities.
When your plugin only registers client-side abilities
If your plugin only needs to register and work with its own client-side abilities on a specific page, without needing server-registered abilities, you can enqueue just
@wordpress/abilities
add_action( 'admin_enqueue_scripts', 'my_plugin_enqueue_abilities' );
function my_plugin_enqueue_abilities( $hook_suffix ) {
if ( 'my-plugin-page' !== $hook_suffix ) {
return;
wp_enqueue_script_module( '@wordpress/abilities' );
Importing in JavaScript
Abilities API should be imported as a dynamic import, for example:
const {
registerAbility,
registerAbilityCategory,
getAbilities,
executeAbility,
} = await import( '@wordpress/abilities' );
If your client code is also a script module relying on
@wordpress/scripts
, you can just use the following code like any other import:
import {
registerAbility,
registerAbilityCategory,
getAbilities,
executeAbility,
} from '@wordpress/abilities';
Registering abilities
Register a
category
Category
The 'category' taxonomy lets you group posts / content together that share a common bond. Categories are pre-defined and broad ranging.
first
Abilities are organized into categories. Before registering an ability, its category must exist. Server-side categories are loaded automatically when
@wordpress/core-abilities
is enqueued. To register a client-side category:
const { registerAbilityCategory } = await import( '@wordpress/abilities' );
registerAbilityCategory( 'my-plugin-actions', {
label: 'My Plugin Actions',
description: 'Actions provided by My Plugin',
} );
Category slugs must be lowercase alphanumeric with dashes only (e.g.,
data-retrieval
user-management
).
Register an ability
const { registerAbility } = await import( '@wordpress/abilities' );
registerAbility( {
name: 'my-plugin/navigate-to-settings',
label: 'Navigate to Settings',
description: 'Navigates to the plugin settings page',
category: 'my-plugin-actions',
callback: async () => {
window.location.href = '/wp-admin/options-general.php?page=my-plugin';
return { success: true };
},
} );
Input and output schemas
Abilities should define
JSON
JSON
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 (draft-04) for input validation and output validation:
registerAbility( {
name: 'my-plugin/create-item',
label: 'Create Item',
description: 'Creates a new item with the given title and content',
category: 'my-plugin-actions',
input_schema: {
type: 'object',
properties: {
title: { type: 'string', description: 'The title of the item', minLength: 1 },
content: { type: 'string', description: 'The content of the item' },
status: { type: 'string', description: 'The publish status of the item', enum: [ 'draft', 'publish' ] },
},
required: [ 'title' ],
},
output_schema: {
type: 'object',
properties: {
id: { type: 'number', description: 'The unique identifier of the created item' },
title: { type: 'string', description: 'The title of the created item' },
},
required: [ 'id' ],
},
callback: async ( { title, content, status = 'draft' } ) => {
// Create the item...
return { id: 123, title };
},
} );
When
executeAbility
is called, the input is validated against
input_schema
before execution and the output is validated against
output_schema
after execution. If validation fails, an error is thrown with the code
ability_invalid_input
or
ability_invalid_output
Permission callbacks
Abilities can include a
permissionCallback
that is checked before execution:
registerAbility( {
name: 'my-plugin/admin-action',
label: 'Admin Action',
description: 'An action only available to administrators',
category: 'my-plugin-actions',
permissionCallback: () => {
return currentUserCan( 'manage_options' );
},
callback: async () => {
// Only runs if permissionCallback returns true
return { success: true };
},
} );
If the permission callback returns
false
, an error with code
ability_permission_denied
is thrown.
Querying abilities
Direct function calls
const {
getAbilities,
getAbility,
getAbilityCategories,
getAbilityCategory,
} = await import( '@wordpress/abilities' );
// Get all registered abilities
const abilities = getAbilities();
// Filter abilities by category
const dataAbilities = getAbilities( { category: 'data-retrieval' } );
// Get a specific ability by name
const ability = getAbility( 'my-plugin/create-item' );
// Get all categories
const categories = getAbilityCategories();
// Get a specific category
const category = getAbilityCategory( 'data-retrieval' );
Using with
React
React
React is a JavaScript library that makes it easy to reason about, construct, and maintain stateless and stateful user interfaces.
and
@wordpress/data
The abilities store (
core/abilities
) integrates with
@wordpress/data
, so you can use
useSelect
for reactive queries in React components:
import { useSelect } from '@wordpress/data';
import { store as abilitiesStore } from '@wordpress/abilities';
function AbilitiesList() {
// Get all abilities reactively
const abilities = useSelect(
( select ) => select( abilitiesStore ).getAbilities(),
[]
);
// Filter by category
const dataAbilities = useSelect(
( select ) =>
select( abilitiesStore ).getAbilities( {
category: 'data-retrieval',
} ),
[]
);
// abilities and dataAbilities update automatically when the store changes
Executing abilities
Use
executeAbility
to run any registered ability, whether client-side or server-side:
import { executeAbility } from '@wordpress/abilities';
try {
const result = await executeAbility( 'my-plugin/create-item', {
title: 'New Item',
content: 'Item content',
status: 'draft',
} );
console.log( 'Created item:', result.id );
} catch ( error ) {
switch ( error.code ) {
case 'ability_permission_denied':
console.error( 'You do not have permission to run this ability.' );
break;
case 'ability_invalid_input':
console.error( 'Invalid input:', error.message );
break;
case 'ability_invalid_output':
console.error( 'Unexpected output:', error.message );
break;
default:
console.error( 'Execution failed:', error.message );
For server-side abilities (those registered via
PHP
PHP
The web scripting language in which WordPress is primarily architected. WordPress requires PHP 7.4 or higher
and loaded by
@wordpress/core-abilities
), execution is handled automatically via the REST API. The
HTTP
HTTP
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.
method used depends on the ability’s annotations:
readonly: true
: uses
GET
destructive: true
idempotent: true
: uses
DELETE
All other cases
: uses
POST
Annotations
Abilities support metadata annotations that describe their behavior:
registerAbility( {
name: 'my-plugin/get-stats',
label: 'Get Stats',
description: 'Returns plugin statistics',
category: 'my-plugin-actions',
callback: async () => {
return { views: 100 };
},
meta: {
annotations: {
readonly: true,
},
},
} );
Available annotations:
Annotation
Type
Description
readonly
boolean
The ability only reads data, does not modify state
destructive
boolean
The ability performs destructive operations
idempotent
boolean
The ability can be called multiple times with the same result
Unregistering
Client-registered abilities and categories can be removed:
const { unregisterAbility, unregisterAbilityCategory } = await import( '@wordpress/abilities' );
unregisterAbility( 'my-plugin/navigate-to-settings' );
unregisterAbilityCategory( 'my-plugin-actions' );
Server-side abilities
Abilities registered on the server via the PHP API (
wp_register_ability()
wp_register_ability_category()
) are automatically made available on the client when
@wordpress/core-abilities
is loaded. WordPress core enqueues
@wordpress/core-abilities
on all
admin
admin
(and super admin)
pages, so server abilities are available by default in the admin.
Plugins that register server-side abilities do not need any additional client-side setup. The abilities will be fetched from the REST API and registered in the client store automatically.
7-0
dev-notes
dev-notes-7-0
WordPress 7.0 includes a built-in AI Client — a provider-agnostic
PHP
PHP
The web scripting language in which WordPress is primarily architected. WordPress requires PHP 7.4 or higher
API
API
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.
that lets plugins send prompts to AI models and receive results through a consistent interface. Your
plugin
Plugin
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
or can be cost-based plugin from a third-party.
describes
what
it needs and
how
it needs it. WordPress handles routing the request to a suitable model from a provider the site owner has configured.
This post explains the API surface, walks through code examples, and covers what plugin developers need to know.
The entry point:
wp_ai_client_prompt()
Every interaction starts with:
$builder = wp_ai_client_prompt();
This returns a
WP_AI_Client_Prompt_Builder
object, a fluent builder that offers a myriad of ways to customize your prompt. You chain configuration methods and then call a generation method to receive a result:
$text = wp_ai_client_prompt( 'Summarize the benefits of caching in WordPress.' )
->using_temperature( 0.7 )
->generate_text();
You can pass the prompt text directly as a parameter to
wp_ai_client_prompt()
for convenience, though alternatively the
with_text()
method is available for building the prompt incrementally.
Text generation
Here’s a basic text generation example:
$text = wp_ai_client_prompt( 'Write a haiku about WordPress.' )
->generate_text();
if ( is_wp_error( $text ) ) {
// Handle error.
return;
echo wp_kses_post( $text );
You can pass a
JSON
JSON
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 so that the model returns structured data as a JSON string:
$schema = array(
'type' => 'array',
'items' => array(
'type' => 'object',
'properties' => array(
'plugin_name' => array( 'type' => 'string' ),
'category' => array( 'type' => 'string' ),
),
'required' => array( 'plugin_name', 'category' ),
),
);
$json = wp_ai_client_prompt( 'List 5 popular WordPress plugins with their primary category.' )
->as_json_response( $schema )
->generate_text();
if ( is_wp_error( $json ) ) {
// Handle error.
return;
$data = json_decode( $json, true );
You can request multiple response candidates as variations for the same prompt:
$texts = wp_ai_client_prompt( 'Write a tagline for a photography blog.' )
->generate_texts( 4 );
Image generation
Here’s a basic image generation example:
use WordPress\AiClient\Files\DTO\File;
$image_file = wp_ai_client_prompt( 'A futuristic WordPress logo in neon style' )
->generate_image();
if ( is_wp_error( $image_file ) ) {
// Handle error.
return;
echo '';
generate_image()
returns a
File
DTO with access to the image data via
getDataUri()
Similar to text generation, you can request multiple variations of the same image:
$images = wp_ai_client_prompt( 'Aerial shot of snowy plains, cinematic.' )
->generate_images( 4 );
if ( is_wp_error( $images ) ) {
// Handle error.
return;
foreach ( $images as $image_file ) {
echo '';
Getting the full result object
For richer metadata, e.g. covering provider and model information, use
generate_*_result()
instead. For example, for image generation:
$result = wp_ai_client_prompt( 'A serene mountain landscape.' )
->generate_image_result();
This returns a
GenerativeAiResult
object that provides several pieces of additional information, including token usage and which provider and which model responded to the prompt. The most relevant methods for this additional metadata are:
getTokenUsage()
: Returns the token usage, broken down by input, output, and optionally thinking.
getProviderMetadata()
: Returns metadata about the provider that handled the request.
getModelMetadata()
: Returns metadata about the model that handled the request (through the provider).
The
GenerativeAiResult
object is serializable and can be passed directly to
rest_ensure_response()
, making it straightforward to expose AI features through the
REST API
REST 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”)
Available
generate_*_result()
methods:
generate_text_result()
generate_image_result()
convert_text_to_speech_result()
generate_speech_result()
generate_video_result()
Use the appropriate method for the modality you are working with. Each returns a
GenerativeAiResult
object with rich metadata.
Model preferences
The models available on each WordPress site depends on which AI providers the administrators of that site have configured in the
Settings > Connectors
screen.
Since your plugin doesn’t control which providers are available on each site, use
using_model_preference()
to indicate which models would be ideal. The AI Client will use the first model from that list that is available, falling back to any compatible model if none are available:
$text_result = wp_ai_client_prompt( 'Summarize the history of the printing press.' )
->using_temperature( 0.1 )
->using_model_preference(
'claude-sonnet-4-6',
'gemini-3.1-pro-preview',
'gpt-5.4'
->generate_text_result();
This is a preference, not a requirement. Your plugin should function without it. Keep in mind that you can test or verify which model was used by looking at the full result object, under the
providerMetadata
and
modelMetadata
properties.
If you don’t specify a model preference, the first model encountered across the configured providers that is suitable will be used. It is up to the individual provider implementations to sort the provider’s models in a reasonable manner, e.g. so that more recent models appear before older models of the same model family. The three initial
official provider plugins
(see below) organize models in that way, as recommended.
Feature detection
Not every WordPress site will have an AI provider configured, and not every provider supports every
capability
capability
capability
is permission to perform one or more types of task. Checking if a user has a capability is performed by the
current_user_can
function. Each user of a WordPress site might have some permissions but not others, depending on their role. For example, users who have the Author role usually have permission to edit their own posts (the “edit_posts” capability), but not permission to edit other users’ posts (the “edit_others_posts” capability).
and every option. Before showing AI-powered
UI
UI
User interface
, check whether the feature can work:
$builder = wp_ai_client_prompt( 'test' )
->using_temperature( 0.7 );
if ( $builder->is_supported_for_text_generation() ) {
// Safe to show text generation UI.
These checks do not make API calls. They use deterministic logic to match the builder’s configuration against the
capabilities
capability
capability
is permission to perform one or more types of task. Checking if a user has a capability is performed by the
current_user_can
function. Each user of a WordPress site might have some permissions but not others, depending on their role. For example, users who have the Author role usually have permission to edit their own posts (the “edit_posts” capability), but not permission to edit other users’ posts (the “edit_others_posts” capability).
of available models. As such, they are fast to run and there is no cost incurred by calling them.
Available support check methods:
is_supported_for_text_generation()
is_supported_for_image_generation()
is_supported_for_text_to_speech_conversion()
is_supported_for_speech_generation()
is_supported_for_video_generation()
Use these to conditionally load your UI, show a helpful notice when the feature is unavailable, or skip registering UI altogether. Never assume that AI features will be available just because WordPress 7.0 is installed.
Advanced configuration
System instructions
$text = wp_ai_client_prompt( 'Explain caching.' )
->using_system_instruction( 'You are a WordPress developer writing documentation.' )
->generate_text();
Max tokens
$text = wp_ai_client_prompt( 'Explain quantum computing in complicated terms.' )
->using_max_tokens( 8000 )
->generate_text();
Output file type and orientation for images
use WordPress\AiClient\Files\Enums\FileTypeEnum;
use WordPress\AiClient\Files\Enums\MediaOrientationEnum;
$result = wp_ai_client_prompt()
->with_text( 'A vibrant sunset over the ocean.' )
->as_output_file_type( FileTypeEnum::inline() )
->as_output_media_orientation( MediaOrientationEnum::from( 'landscape' ) )
->generate_image_result();
Multimodal output
use WordPress\AiClient\Messages\Enums\ModalityEnum;
$result = wp_ai_client_prompt( 'Create a recipe for a chocolate cake and include photos for the steps.' )
->as_output_modalities( ModalityEnum::text(), ModalityEnum::image() )
->generate_result();
if ( is_wp_error( $result ) ) {
// Handle error.
return;
foreach ( $result->toMessage()->getParts() as $part ) {
if ( $part->isText() ) {
echo wp_kses_post( $part->getText() );
} elseif ( $part->isFile() && $part->getFile()->isImage() ) {
echo '';
Additional builder methods
The full list of configuration methods is available via the
WP_AI_Client_Prompt_Builder
class. Key methods include:
Configuration
Method
Prompt text
with_text()
File input
with_file()
Conversation history (relevant for multi-turn / chats)
with_history()
System instruction
using_system_instruction()
Temperature
using_temperature()
Max tokens
using_max_tokens()
Top-p / Top-k
using_top_p(), using_top_k()
Stop sequences
using_stop_sequences()
Model preference
using_model_preference()
Output modalities
as_output_modalities()
Output file type
as_output_file_type()
JSON response
as_json_response()
Error handling
wp_ai_client_prompt()
generator methods return
WP_Error
on failure, following WordPress conventions:
$text = wp_ai_client_prompt( 'Hello' )
->generate_text();
if ( is_wp_error( $text ) ) {
// Handle the error.
When used in a REST API callback, both
GenerativeAiResult
and
WP_Error
can be passed to
rest_ensure_response()
directly:
function my_rest_callback( WP_REST_Request $request ) {
$result = wp_ai_client_prompt( $request->get_param( 'prompt' ) )
->generate_text_result();
return rest_ensure_response( $result );
If an error occurs, it will automatically have a semantically meaningful
HTTP
HTTP
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.
response code attached to it.
Controlling AI availability
For granular control, the
wp_ai_client_prevent_prompt
filter
Filter
Filters are one of the two types of 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.
allows preventing specific prompts from executing:
add_filter(
'wp_ai_client_prevent_prompt',
function ( bool $prevent, WP_AI_Client_Prompt_Builder $builder ): bool {
// Example: Block all prompts for non-admin users.
if ( ! current_user_can( 'manage_options' ) ) {
return true;
return $prevent;
},
10,
);
When a prompt is prevented:
No AI call is attempted.
is_supported_*()
methods return
false
, allowing plugins to gracefully hide their UI.
generate_*()
methods return a
WP_Error
Architecture
The AI Client in WordPress 7.0 consists of two layers:
PHP AI Client
wordpress/php-ai-client
) — A provider-agnostic PHP SDK bundled in
Core
Core
Core is the set of software required to run WordPress. The Core Development Team builds WordPress.
as an external library. This is the engine that handles provider communication, model selection, and response normalization. Since it is technically a WordPress agnostic PHP SDK which other PHP projects can use too, it uses camelCase method naming and makes use of exceptions.
WordPress wrapper
— Core’s
WP_AI_Client_Prompt_Builder
class wraps the PHP AI Client with WordPress conventions: snake_case methods,
WP_Error
returns, and integration with WordPress HTTP transport, the Abilities API, the Connectors/Settings infrastructure, and the WordPress
hooks
Hooks
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.
system.
The
wp_ai_client_prompt()
function is the recommended entry point. It returns a
WP_AI_Client_Prompt_Builder
instance that catches exceptions from the underlying SDK and converts them to
WP_Error
objects.
Credential management
API keys are managed through the
Connectors API
. AI provider plugins that register with the PHP AI Client’s provider registry get automatic connector integration — including the
Settings > Connectors
admin
admin
(and super admin)
UI for API key management. Plugin developers using the AI Client to build features do not need to handle credentials at all.
Official provider plugins
WordPress Core does not bundle any AI providers directly. Instead, they are developed and maintained as plugins, which allows for more flexible and rapid iteration speed, in accordance with how fast AI evolves. The AI Client in WordPress Core provides the stable foundation, and as an abstraction layer is sufficiently detached from provider specific requirements that may change overnight.
While anyone is able to implement new provider plugins, the WordPress project itself has developed three initial flagship implementations, to integrate with the most popular AI providers. These plugins are:
AI Provider for Anthropic
AI Provider for Google
AI Provider for OpenAI
Separately available: Client-side
JavaScript
JavaScript
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.
API
A JavaScript API with a similar fluent prompt builder is available via the
wp-ai-client
package. It uses REST endpoints under the hood to connect to the server-side infrastructure. This API is not part of Core, and it is still being evaluated whether this approach is scalable for general use. Because the API allows arbitrary prompt execution from the client-side, it requires a high-privilege capability check, which by default is only granted to administrators. This restriction is necessary to prevent untrusted users from sending any prompt to any configured AI provider. As such, using this approach in a distributed plugin is not recommended.
For now, the recommended approach is to implement individual REST API endpoints for each specific AI feature your plugin provides, and have your JavaScript functionality call those endpoints. This allows you to enforce granular permission checks and limit the scope of what can be executed from the client-side. It also keeps the actual AI prompt handling and configuration fully scoped to be server-side only.
Migration
Migration
Moving the code, database and media files for a website site from one server to another. Most typically done when changing hosting companies.
from php-ai-client and wp-ai-client
If you have been using these packages in your plugin(s) before, here’s what to know.
Recommended: require WordPress 7.0
The simplest path is to update your plugin’s Requires at least
header
Header
The header of your site is typically the first thing people will experience. The masthead or header art located across the top of your page is part of the look and feel of your website. It can influence a visitor’s opinion about your content and you/ your organization’s brand. It may also look different on different screen sizes.
to 7.0 and remove the Composer dependencies on
wordpress/php-ai-client
and its transitive dependencies.
Replace any
AI_Client::prompt()
calls with
wp_ai_client_prompt()
For the
wordpress/wp-ai-client
package, if you are not using the package’s REST API endpoints or JavaScript API, you can simply remove it as a dependency, since everything else it does is now part of WordPress Core.
If you must support WordPress < 7.0
PHP AI Client (
wordpress/php-ai-client
If your plugin still needs to run on WordPress versions before 7.0 while also bundling wordpress/php-ai-client, you will need a conditional autoloader workaround. The PHP AI Client and its dependencies are now loaded by Core on 7.0+, so loading them again via Composer will cause conflicts (duplicate class definitions).
The solution: only register your Composer autoloader for these dependencies when running on WordPress versions before 7.0:
if ( ! function_exists( 'wp_get_wp_version' ) || version_compare( wp_get_wp_version(), '7.0', '<' ) ) {
require_once __DIR__ . '/vendor/autoload.php';
Due to how Composer’s autoloader works — loading all dependencies at once rather than selectively — a more granular approach was not feasible. This means the conditional check needs to wrap the entire autoloader. Alternatively, break your PHP dependencies apart in two separate Composer setups, one that can always be autoloaded, and another one for the
wordpress/php-ai-client
package and its dependencies only, which would be conditionally autoloaded.
WP AI Client (
wordpress/wp-ai-client
The
wordpress/wp-ai-client
package handles the WordPress 7.0 transition automatically. On 7.0+, it disables its own PHP SDK infrastructure (since Core handles it natively) but keeps the REST API endpoints and JavaScript API active, as those aren’t in Core yet.
You can continue loading this package unconditionally. It detects the WordPress version and only activates the parts that aren’t already provided by Core. No conditional loading needed. However, make sure to stay up to date on this package, because it will likely be discontinued soon, in favor of moving the REST API endpoints and JavaScript API into
Gutenberg
Gutenberg
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.
. There are ongoing discussions on whether these should be merged into Core too, see
#64872
and
#64873
See the
WP AI Client upgrade guide
for additional migration details.
Additional resources
Trac
Trac
An open source project by Edgewall Software that serves as a bug tracker and project management tool for WordPress.
ticket
ticket
Created for both bug reports and feature development on the bug tracker.
#64591
PHP AI Client
(bundled library)
WP AI Client
(original package, now mostly merged into Core)
Original merge proposal
Props to
gziolo
nilambar
laurisaarni
justlevine
for reviewing this post.
core-ai
7-0
dev-notes
dev-notes-7-0
WordPress 7.0 introduces the
Connectors
API
API
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.
— a new framework for registering and managing connections to external services. The initial focus is on AI providers, giving WordPress a standardized way to handle API key management, provider discovery, and
admin
admin
(and super admin)
UI
UI
User interface
for configuring AI services.
This post walks through what the Connectors API does, how it works under the hood, and what
plugin
Plugin
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
or can be cost-based plugin from a third-party.
developers need to know.
Table of Contents
What is a connector?
How AI providers are auto-discovered
The Settings > Connectors admin screen
Authentication and API key management
Public API functions
Overriding connector metadata
The initialization lifecycle
Looking ahead
What is a connector?
A connector represents a connection to an external service. Each connector carries standardized metadata — a display name, description, logo, authentication configuration, and an optional association with a
WordPress.org
WordPress.org
The community site where WordPress code is created and shared by the users. This is where you can download the source code for WordPress core, plugins and themes as well as the central location for community conversations and organization.
plugin. The system currently focuses on providers that authenticate with an API key, but the architecture is designed to support additional connector types in future releases.
WordPress 7.0 comes with three featured connectors—Anthropic, Google, and OpenAI—accessible from the new
Settings → Connectors
screen, making installation seamless.
Each connector is stored as an associative array with the following shape:
array(
'name' => 'Anthropic',
'description' => 'Text generation with Claude.',
'logo_url' => 'https://example.com/anthropic-logo.svg',
'type' => 'ai_provider',
'authentication' => array(
'method' => 'api_key',
'credentials_url' => 'https://platform.claude.com/settings/keys',
'setting_name' => 'connectors_ai_anthropic_api_key',
),
'plugin' => array(
'file' => 'ai-provider-for-anthropic/plugin.php',
),
How AI providers are auto-discovered
If you’re building an AI provider plugin that integrates with the WP AI Client, you don’t need to register a connector manually. The Connectors API automatically discovers providers from the WP AI Client’s default registry and creates connectors with the correct metadata.
Here’s what happens during initialization:
Built-in connectors (Anthropic, Google, OpenAI) are registered with hardcoded defaults.
The system queries the
AiClient::defaultRegistry()
for all registered providers.
For each provider, metadata (name, description, logo, authentication method) is merged on top of the defaults, with provider registry values taking precedence.
The
wp_connectors_init
action fires so plugins can override metadata or register additional connectors.
In short:
if your AI provider plugin registers with the WP AI Client, the connector is created for you. No additional code is needed.
The Settings > Connectors admin screen
Registered connectors appear on a new
Settings > Connectors
admin screen. The screen renders each connector as a card, and the registry data drives what’s displayed:
name
description
, and
logo_url
are shown on the card.
plugin.file
— the value is the plugin’s main file path relative to the plugins directory (e.g.,
akismet/akismet.php
or
hello.php
). The screen uses it to check whether the associated plugin is installed and active, and shows the appropriate action button.
authentication.credentials_url
is rendered as a link directing users to the provider’s site to obtain API credentials.
For
api_key
connectors, the screen shows the current key source (environment variable,
PHP
PHP
The web scripting language in which WordPress is primarily architected. WordPress requires PHP 7.4 or higher
constant, or database) and connection status.
Connectors with other authentication methods are stored in the PHP registry and exposed via the script module data, but currently require a client-side
JavaScript
JavaScript
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.
registration for custom frontend UI.
Authentication and API key management
Connectors support two authentication methods:
api_key
— Requires an API key, which can be provided via environment variable, PHP constant, or the database (checked in that order).
none
— No authentication required.
The authentication method (
api_key
or
none
) is determined by the authentication metadata registered with the connector. For providers using
api_key
, a database setting name is automatically generated using the pattern
connectors_{$provider_type}_{$provider_id}_api_key
. It’s also possible to set a custom name using
setting_name
property. API keys stored in the database are not encrypted but are masked in the user interface. Encryption is being explored in a follow-up
ticket
ticket
Created for both bug reports and feature development on the bug tracker.
#64789
For AI providers, there is a specific naming convention in place for environment variables and PHP constants:
{PROVIDER_ID}_API_KEY
(e.g., the
anthropic
provider maps to
ANTHROPIC_API_KEY
). For other types of providers, an environment variable (
env_var_name
) and a PHP constant (
constant_name
) can be optionally set to any value.
API key source priority
For
api_key
connectors, the system looks for a setting value in this order:
Environment variable
— e.g.,
ANTHROPIC_API_KEY
PHP constant
— e.g.,
define( 'ANTHROPIC_API_KEY', 'sk-...' );
Database
— stored through the admin screen, e.g.
connectors_ai_anthropic_api_key
setting
Public API functions
The Connectors API provides three public functions for querying the registry. These are available after
init
wp_is_connector_registered()
Checks if a connector is registered:
if ( wp_is_connector_registered( 'anthropic' ) ) {
// The Anthropic connector is available.
wp_get_connector()
Retrieves a single connector’s data:
$connector = wp_get_connector( 'anthropic' );
if ( $connector ) {
echo $connector['name']; // 'Anthropic'
Returns an associative array with keys:
name
description
type
authentication
, and optionally
logo_url
and
plugin
. Returns
null
if the connector is not registered.
wp_get_connectors()
Retrieves all registered connectors, keyed by connector ID:
$connectors = wp_get_connectors();
foreach ( $connectors as $id => $connector ) {
printf( '%s: %s', $connector['name'], $connector['description'] );
Overriding connector metadata
The
wp_connectors_init
action fires after all built-in and auto-discovered connectors have been registered. Plugins can use this hook to override metadata on existing connectors.
Since the registry rejects duplicate IDs, overriding requires an unregister, modify, register sequence:
add_action( 'wp_connectors_init', function ( WP_Connector_Registry $registry ) {
if ( $registry->is_registered( 'anthropic' ) ) {
$connector = $registry->unregister( 'anthropic' );
$connector['description'] = __( 'Custom description for Anthropic.', 'my-plugin' );
$registry->register( 'anthropic', $connector );
} );
Key points about the override pattern:
Always check
is_registered()
before calling
unregister()
— calling
unregister()
on a non-existent connector triggers a
_doing_it_wrong()
notice.
unregister()
returns the connector data, which you can modify and pass back to
register()
Connector IDs must match the pattern
/^[a-z0-9_-]+$/
(lowercase alphanumeric, underscores, and hyphens only).
Registry methods
Within the
wp_connectors_init
callback, the
WP_Connector_Registry
instance provides these methods:
Method
Description
register( $id, $args )
Register a new connector. Returns the connector data or
null
on failure.
unregister( $id )
Remove a connector and return its data. Returns
null
if not found.
is_registered( $id )
Check if a connector exists.
get_registered( $id )
Retrieve a single connector’s data.
get_all_registered()
Retrieve all registered connectors.
Outside of the
wp_connectors_init
callback, use the public API functions (
wp_get_connector()
wp_get_connectors()
wp_is_connector_registered()
) instead of accessing the registry directly.
The initialization lifecycle
Understanding the initialization sequence helps when deciding where to hook in:
During the
init
action,
_wp_connectors_init()
runs and:
Creates the
WP_Connector_Registry
singleton.
Registers built-in connectors (Anthropic, Google, OpenAI) with hardcoded defaults.
Auto-discovers providers from the WP AI Client registry and merges their metadata on top of defaults.
Fires the
wp_connectors_init
action — this is where plugins override metadata or register additional connectors.
The
wp_connectors_init
action is the only supported entry point for modifying the registry. Attempting to set the registry instance outside of
init
triggers a
_doing_it_wrong()
notice.
Looking ahead
The Connectors API in WordPress 7.0 was optimized for AI providers, but the underlying architecture is designed to grow. Currently, only connectors with
api_key
authentication receive the full admin UI treatment. The PHP registry already accepts any connector type — what’s missing is the frontend integration for connectors with different authentication mechanisms.
Future releases are expected to:
Expand support for additional authentication methods beyond
api_key
and
none
Offer more built-in UI integrations beyond
api_key
Provide a client-side JavaScript registration API for custom connector UI.
When those
capabilities
capability
capability
is permission to perform one or more types of task. Checking if a user has a capability is performed by the
current_user_can
function. Each user of a WordPress site might have some permissions but not others, depending on their role. For example, users who have the Author role usually have permission to edit their own posts (the “edit_posts” capability), but not permission to edit other users’ posts (the “edit_others_posts” capability).
land, the
wp_connectors_init
action will be the primary hook for registering new connector types.
Props to
jorgefilipecosta
shaunandrews
flixos90
westonruter
justlevine
, and others for contributing to the Connectors screen and this
dev note
dev note
Each important change in WordPress Core is documented in a developers note, (usually called dev note). Good dev notes generally include a description of the change, the decision that led to this change, and a description of how developers are supposed to work with that change. Dev notes are published on Make/Core blog during the beta phase of WordPress release cycle. Publishing dev notes is particularly important when plugin/theme authors and WordPress developers need to be aware of those changes.In general, all dev notes are compiled into a Field Guide at the beginning of the release candidate phase.
7-0
dev-notes
dev-notes-7-0
As of WordPress 7.0, any
block
Block
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.
attribute that supports Block Bindings
also supports Pattern Overrides
. So now, you can use Pattern Overrides for any block you want — even custom blocks — the previous limit to a hardcoded set of
Core
Core
Core is the set of software required to run WordPress. The Core Development Team builds WordPress.
blocks no longer holds you back. To get started, opt in through the server-side
block_bindings_supported_attributes
filter(s)
The underlying Block Bindings mechanism will make sure that:
In dynamic blocks, the correct, bound attribute values will be passed to
render_callback()
In static blocks, the
HTML
HTML
HyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers.
API
API
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.
is used to locate
attributes sourced from
html
rich-text
, or
attribute
sources
via their selectors in the persisted markup, replacing their values with the respective bound attribute values.
Bound attribute values should appear correctly in the rendered blocks’ markup in these cases. You shouldn’t need any other modifications.
For static blocks with unsourced attributes, or with sourced attributes whose selectors are more complex than the HTML API currently understands, you might need to add a
render_callback()
or a
render_block
filter
Filter
Filters are one of the two types of 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.
to make sure bound attribute values are correctly handled. It’s best if you first try without (i.e. by only adding the attribute via
block_bindings_supported_attributes
filter). Then, if the bound attribute value doesn’t render, add the callback or the filter that guarantees the render.
Props to
fabiankaegy
and
marybaum
for reviewing this
dev note
dev note
Each important change in WordPress Core is documented in a developers note, (usually called dev note). Good dev notes generally include a description of the change, the decision that led to this change, and a description of how developers are supposed to work with that change. Dev notes are published on Make/Core blog during the beta phase of WordPress release cycle. Publishing dev notes is particularly important when plugin/theme authors and WordPress developers need to be aware of those changes.In general, all dev notes are compiled into a Field Guide at the beginning of the release candidate phase.
7-0
dev-notes
dev-notes-7-0
WordPress 7.0 expands
contentOnly
editing to unsynced patterns and template parts.
The key behavioral change is that unsynced patterns and template parts inserted into the editor now default to
contentOnly
mode, prioritizing the editing of text and media without exposing the deeper
block
Block
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.
structure or style controls.
Pattern-level editing modes
At times a user will want to make design changes to a pattern, and this works differently depending on the type of pattern.
Unsynced
— A user can click an ‘Edit pattern’ button or double click the body of a pattern, and a spotlight mode engages. In this mode users have full editing
capabilities
capability
capability
is permission to perform one or more types of task. Checking if a user has a capability is performed by the
current_user_can
function. Each user of a WordPress site might have some permissions but not others, depending on their role. For example, users who have the Author role usually have permission to edit their own posts (the “edit_posts” capability), but not permission to edit other users’ posts (the “edit_others_posts” capability).
Synced (synced patterns / template parts)
— Users can click the ‘Edit original’ button and are taken into an isolated editor when they can make any changes to the underlying pattern. The editor
header
Header
The header of your site is typically the first thing people will experience. The masthead or header art located across the top of your page is part of the look and feel of your website. It can influence a visitor’s opinion about your content and you/ your organization’s brand. It may also look different on different screen sizes.
provides navigation back to the originating document. Changes to synced patterns apply globally.
What developers need to do
Block authors
If your block is nested in a
contentOnly
pattern and should be editable, ensure attributes that represent a block’s content have
"role": "content"
set in
block.json
. This is unchanged from WordPress 6.7, but is now more important as
contentOnly
mode is applied more broadly by default.
"attributes": {
"url": {
"type": "string",
"role": "content"
},
"label": {
"type": "string",
"role": "content"
Blocks without any
"role": "content"
attributes will be hidden from List View and non-selectable inside a
contentOnly
container.
At times a block may not have an appropriate attribute to which to apply
"role": "content"
. A
"contentRole": true
property can be added to the block supports declaration, and this has the same effect as
"role": "content"
"supports": {
"contentRole": true
Developers should prefer
"role": "content"
where possible.
Parent / child contentOnly blocks
Many blocks are considered ‘content’, but consist of both parent and child block types. Some examples of
Core
Core
Core is the set of software required to run WordPress. The Core Development Team builds WordPress.
blocks are:
List and List Item
Gallery and Image
Buttons and Button
Whenever both a parent and child block have a
"role": "content"
attribute or
"contentRole": true
block supports,
contentOnly
mode allows insertion of child blocks. This behavior has been present since WordPress 6.9, but is now more prominent.
Block developers can take advantage of this behavior.
List View block support
New for WordPress 7.0, block developers can add a
"listView": true
block supports declaration. This adds a List View tab to the block inspector with a dedicated List View
UI
UI
User interface
for the block that allows users to easily rearrange and add inner blocks. This List View is also displayed in Patterns and is recommended for any block that acts as a container for a list of child blocks.
"supports": {
"listView": true
Theme / pattern authors
Patterns that previously relied on unrestricted editing of their inner blocks will now be presented to users in
contentOnly
mode by default. Review your registered patterns and consider:
Testing that the content users are expected to change is accessible in
contentOnly
mode.
Auditing patterns containing Buttons, List, Social Icons, and Navigation blocks specifically — these have had targeted
contentOnly
improvements and may behave differently than before.
Restrict the allowed blocks if users shouldn’t be able to insert blocks in a specific area of a pattern. If assembling a pattern in a block editor, this can be done using the ‘Manage allowed blocks’ feature in the Advanced section of the block inspector for any blocks that have
"allowedBlocks": true
block support. Through code, the
"allowedBlocks":[]
attribute can be added to prevent insertion of inner blocks.
Site admins
A new block editor setting,
disableContentOnlyForUnsyncedPatterns
, allows opting out of
contentOnly
mode for unsynced patterns. Via
PHP
PHP
The web scripting language in which WordPress is primarily architected. WordPress requires PHP 7.4 or higher
, use the
block_editor_settings_all
filter
Filter
Filters are one of the two types of 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.
add_filter( 'block_editor_settings_all', function( $settings ) {
$settings['disableContentOnlyForUnsyncedPatterns'] = true;
return $settings;
} );
Or via
JavaScript
JavaScript
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.
wp.data.dispatch( 'core/block-editor' ).updateSettings( {
disableContentOnlyForUnsyncedPatterns: true,
} );
When
disableContentOnlyForUnsyncedPatterns
is
true
, blocks with
patternName
metadata are no longer treated as section blocks and their children are not placed into
contentOnly
editing mode. Template parts and synced patterns (
core/block
) are unaffected — they remain section blocks regardless of this setting.
Plugin
Plugin
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
or can be cost-based plugin from a third-party.
developers
If your plugin interacts with pattern editing state — toolbar controls,
sidebar
Sidebar
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.
panels, List View visibility, or entity navigation — test against the new editing modes. The
contentOnly
state is now applied more broadly, and UI components that assume full block access inside patterns may not render as expected.
Props to
talldanwp
and
andrewserong
for helping to write this
dev note
dev note
Each important change in WordPress Core is documented in a developers note, (usually called dev note). Good dev notes generally include a description of the change, the decision that led to this change, and a description of how developers are supposed to work with that change. Dev notes are published on Make/Core blog during the beta phase of WordPress release cycle. Publishing dev notes is particularly important when plugin/theme authors and WordPress developers need to be aware of those changes.In general, all dev notes are compiled into a Field Guide at the beginning of the release candidate phase.
References
WordPress 7.0: iteration issue for Pattern Editing and contentOnly interactivity
#73775
Original feature issue
Pattern Editing and contentOnly interactivity #71517
Allow disabling content-only editing for unsynced patterns #75457
How to add content-only editing support to a block (developer.wordpress.org)
Miscellaneous Block Editor Changes in WordPress 6.7
7-0
dev-notes
dev-notes-7-0
As of WordPress 6.9, you can hide any
block
Block
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.
entirely with
blockVisibility: false
in block metadata. In WordPress 7.0, viewport-based visibility rules give your users the power to show or hide blocks per device type — desktop, tablet, or mobile — without affecting other viewports.
Controls are available in the block toolbar, block inspector
sidebar
Sidebar
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.
, and command palette to launch the block visibility options modal. In List View, blocks with active visibility rules show icons that indicate which viewports they are hidden on.
Note: Blocks hidden by viewport are
rendered in the DOM
. The hiding happens
in the
CSS
CSS
Cascading Style Sheets.
That’s different from
blockVisibility: false
. That keeps the block from rendering in the DOM, thus it can’t ever show on the front end.
Updated
blockVisibility
metadata structure
The existing hide-everywhere behavior has NOT changed:
"metadata": {
"blockVisibility": false
But in WordPress 7.0, a new
viewport
key gives you and your
JSON
JSON
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.
-literate users finer control, per breakpoint:
"metadata": {
"blockVisibility": {
"viewport": {
"mobile": false,
"tablet": true,
"desktop": true
The
viewport
key is deliberately nested, leaving room for more sources (e.g., user role, time-based rules) to come in 7.1 and beyond.
The three supported viewport keys are
mobile
tablet
, and
desktop
. In 7.0 these map to fixed breakpoints, but you can expect configurable breakpoints and
theme.json
integration in WordPress 7.1 — see
#75707
Here’s how this all looks in serialized block markup:
Hidden on mobile.
How to get your theme or
plugin
Plugin
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
or can be cost-based plugin from a third-party.
ready
Does your theme or plugin generate, transform, or parse block markup server-side? Then its
blockVisibility
metadata field might now contain a boolean (
false
) or an object (
{ viewport: { ... } }
). If your code assumes a scalar value, you’ll want to update it to handle both forms.
Blocks and patterns that include hardcoded
blockVisibility
metadata will work out of the box, and so will your reusable blocks that have visibility rules.
If your blocks don’t interact with markup on the server
Then you don’t have to do anything! Viewport visibility is part of the
blockVisibility
block support and applies automatically. You don’t need a separate opt-in in
block.json
Coming soon! To a future release near you
Current plans call for configurable breakpoints and
theme.json
integration for block visibility to land in WordPress 7.1. At that point, you’ll be able to let your themes and other products define almost any viewport labels and breakpoints you need, far beyond the fixed mobile/tablet/desktop defaults. Follow
#75707
for progress.
Props to
andrewserong
and
marybaum
for helping to write this
dev note
dev note
Each important change in WordPress Core is documented in a developers note, (usually called dev note). Good dev notes generally include a description of the change, the decision that led to this change, and a description of how developers are supposed to work with that change. Dev notes are published on Make/Core blog during the beta phase of WordPress release cycle. Publishing dev notes is particularly important when plugin/theme authors and WordPress developers need to be aware of those changes.In general, all dev notes are compiled into a Field Guide at the beginning of the release candidate phase.
References
Iteration issue: Block visibility based on screen size (WP 7.0)
Feature discussion: hide blocks based on screen size #72502
Original hide blocks feature (WP 6.9) #50756
7-0
dev-notes
dev-notes-7-0
WordPress 7.0 expands the Dimensions
block
Block
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.
supports system with three significant improvements:
width
and
height
are now available as standard block supports under
dimensions
, and themes can now define dimension size presets to give users a consistent set of size options across their site.
Background
Previously, blocks that needed width or height controls implemented them as custom block attributes with their own editor
UI
UI
User interface
. This led to duplicated code, inconsistent experiences across blocks, and no straightforward way to define width or height values through Global Styles or
theme.json
. The broader Block
API
API
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.
goal is to handle these concerns uniformly through block supports, the same system that already covers spacing, typography, color, and more.
Width Block Support
PR:
#71905
dimensions.width
is now a first-class block support. Block authors can opt in by adding
"width": true
under the
dimensions
key in
block.json
"supports": {
"dimensions": {
"width": true
Once opted in, the block gains a width input in the Dimensions panel of the block inspector and in the Styles panel of the Site Editor (under Styles > Blocks > Block Name). Theme authors can define default width values for specific block types via
theme.json
"styles": {
"blocks": {
"core/paragraph": {
"dimensions": {
"width": "300px"
Block-level values set in the editor will override the theme defaults, following the same cascade as other block supports.
Themes can also disable the width control globally using the settings API:
"settings": {
"dimensions": {
"width": false
The width support respects the full range of block support configuration options:
"supports": {
"dimensions": {
"width": true,
"__experimentalSkipSerialization": true,
"__experimentalDefaultControls": {
"width": false
Height Block Support
PR:
#71914
dimensions.height
follows the same pattern as width. Block authors opt in via
block.json
"supports": {
"dimensions": {
"height": true
Theme authors can set default height values per block in
theme.json
"styles": {
"blocks": {
"core/paragraph": {
"dimensions": {
"height": "300px"
And the support can be disabled theme-wide:
"settings": {
"dimensions": {
"height": false
Like the width support, height respects
__experimentalSkipSerialization
and
__experimentalDefaultControls
Dimension Size Presets
PR:
#73811
Alongside the new width and height supports, themes can now define a set of named dimension size presets via
theme.json
. These presets appear in the width and height controls, giving users a consistent palette of sizes to choose from rather than requiring manual entry of values each time.
Define presets under
settings.dimensions.dimensionSizes
"settings": {
"dimensions": {
"dimensionSizes": [
"name": "Small",
"slug": "small",
"size": "240px"
},
"name": "Medium",
"slug": "medium",
"size": "480px"
},
"name": "Large",
"slug": "large",
"size": "720px"
Each preset requires three fields:
Field
Description
name
Human-readable label shown in the UI
slug
Machine-readable identifier (used to generate a
CSS
CSS
Cascading Style Sheets.
custom property)
size
Any valid CSS length value (
px
em
rem
vw
vh
, etc.)
The presets generate CSS custom properties following the
--wp--preset--dimension-size--{slug}
naming convention, consistent with other
theme.json
presets.
Control rendering:
The number of presets defined affects how the control is rendered:
Fewer than 8 presets:
A slider control is shown, allowing users to step through the preset values.
8 or more presets:
A select list (dropdown) is shown instead to keep the UI manageable.
In both cases, users can still enter a custom value directly.
Backwards Compatibility
These are additive changes. No existing blocks are broken. Blocks that do not opt in to
dimensions.width
or
dimensions.height
in their
block.json
are unaffected.
Blocks that currently implement custom width or height controls as attributes are encouraged to evaluate migrating to the new block supports, but this is not required in WordPress 7.0.
The
dimensionSizes
preset key is new; themes without it simply have no presets defined, which is the default behavior — users can still enter free-form values in the width and height controls.
Summary
Feature
block.json
key
theme.json
settings key
theme.json
styles key
Width block support
supports.dimensions.width
settings.dimensions.width
styles.blocks.{name}.dimensions.width
Height block support
supports.dimensions.height
settings.dimensions.height
styles.blocks.{name}.dimensions.height
Dimension size presets
settings.dimensions.dimensionSizes
Further Reading
PR #71905: Add width block support
PR #71914: Add height block support
PR #73811: Add dimension presets
PR #71227: Remove custom width/height controls in favor of block supports
(broader context)
Block Supports API documentation
theme.json reference
Props to
aaronrobertshaw
and @ryanwelcher for the width and height block support implementations,
aaronrobertshaw
for dimension presets, and
andrewserong
and
ramonopoly
for technical review and proofreading.
7-0
dev-notes
dev-notes-7-0
WordPress 7.0 introduces the ability to add custom
CSS
CSS
Cascading Style Sheets.
directly to individual
block
Block
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.
instances from within the post and site editors. This closes a long-standing gap in the block styling system: while Global Styles has supported block-type-level custom CSS since WordPress 6.2, there was no built-in way to target a single specific block on a specific page without a multi-step workaround.
GitHub
GitHub
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.
issue:
#56127
PR:
#73959
The Problem
Previously, applying one-off CSS to a specific block instance required a workaround: add a custom class name to the block, then write a matching rule in the Site Editor’s global Custom CSS field. This two-step process was not obvious to most users, and was entirely unavailable to content editors who lack access to the Site Editor.
Plugins emerged to fill this gap, confirming genuine demand for the feature.
What Changed
A new
customCSS
block support is registered. It provides a
Custom CSS
input inside the
Advanced
panel of the block inspector — the same panel that already contains the “Additional CSS Class(es)” field.
The panel behaves the same way as the block-type custom CSS field in Global Styles:
Only CSS declarations are needed — no selector is required.
Nested selectors can be written using
(e.g.,
& a { color: red; }
targets anchor tags inside the block).
HTML
HTML
HyperText Markup Language. The semantic scripting language primarily used for outputting content in web browsers.
markup in the CSS field is rejected.
The field is only visible to users with the
edit_css
capability
capability
capability
is permission to perform one or more types of task. Checking if a user has a capability is performed by the
current_user_can
function. Each user of a WordPress site might have some permissions but not others, depending on their role. For example, users who have the Author role usually have permission to edit their own posts (the “edit_posts” capability), but not permission to edit other users’ posts (the “edit_others_posts” capability).
How It Works
Storage
Custom CSS is stored in the block’s existing
style
attribute, under the
css
key — the same attribute that stores other block-level style overrides:
Heading
Frontend Output
At render time, a unique class is generated for the block instance using a hash of the block’s content and attributes. The class is applied to the block’s outermost HTML element alongside a
has-custom-css
marker class:
Heading
The generated stylesheet is registered with a dependency on
global-styles
, ensuring block instance CSS loads
after
— and can therefore override — both WordPress defaults and Global Styles block-type CSS.
Editor Preview
The custom CSS is also applied live in the editor using a scoped style override, so changes are reflected immediately without saving.
Opt-Out
The
customCSS
support is
enabled by default for all blocks
. Block authors who need to opt out — for example, blocks that render raw content or have no meaningful outer element — can disable it in
block.json
"supports": {
"customCSS": false
The following
core
Core
Core is the set of software required to run WordPress. The Core Development Team builds WordPress.
blocks opt out by default:
core/freeform
core/html
core/missing
core/more
core/nextpage
core/shortcode
, and
core/block
(the Reusable Block wrapper).
Capability Check
The Custom CSS panel is gated by the
edit_css
capability. Users without it will not see the field in the block inspector. This is the same capability used to control access to the Custom CSS field in the
Customizer
Customizer
Tool built into WordPress core that hooks into most modern themes. You can use it to preview and modify many of your site’s appearance settings.
and in Global Styles.
For
Plugin
Plugin
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
or can be cost-based plugin from a third-party.
and Theme Developers
No action is required
for most blocks and themes. The support is enabled automatically.
If you maintain a block that should not expose a custom CSS input — because it wraps raw or opaque content, or because adding a class to its root element would break its rendering — add
"customCSS": false
to your block’s
supports
in
block.json
If you render blocks server-side using
render_callback
or
render
in
block.json
, the class will be injected into the first HTML element in the rendered output via
WP_HTML_Tag_Processor
. Ensure your block renders a standard HTML element as its outermost
tag
tag
A directory in Subversion. WordPress uses tags to store a single snapshot of a version (3.6, 3.6.1, etc.), the common convention of tags in version control systems. (Not to be confused with post tags.)
Further Reading
Issue #56127: Block styles — add block instance custom CSS
PR #73959: Add custom CSS support for individual block instances
Block Supports API reference
Props to
mtias
and
glendaviesnz
for the implementation,
aaronrobertshaw
and
scruffian
for technical review and proofreading.
7-0
dev-notes
dev-notes-7-0
Site resources
Email Updates
Enter your email address to subscribe to this blog and receive notifications of new posts by email.
Join 6,694 other subscribers
Recent Updates
Recent Comments
No Replies
Current Release
The current release in progress is
WordPress 7.0
. Planned future releases are listed on
the Project Roadmap
. Feature projects not tied to specific releases can be found on
the Features page.
Regular Chats
Note:
All chats happen on
Slack
Weekly Developer Meetings
: [time relative]Wednesday 15:00 UTC[/time] in
#core
About the Dev Chat
Agendas
Summaries
Performance Weekly Chat
[time relative]Tuesday 15:00 UTC[/time] in
#core-performance
New Contributors Chat
The 2nd and 4th Wednesday of every month at 17:00 UTC in
#core
See all meetings →
Recent Posts and Comments
Team Pledges
2664 people
have pledged time to contribute to Core Team efforts! When looking for help on a project or program, try starting by reaching out to them!
compose new post
reply
edit
go to top
go to the next post or comment
go to the previous post or comment
toggle comment visibility
esc
cancel edit post or comment