Tech 13 min read

WordPress 7.0: wp_ai_client_prompt(), PHP-only blocks, and why RTC was removed

IkesanContents

WordPress 7.0 is still on track for a May 20, 2026 release.
But real-time collaboration — what many saw as the headline feature — was pulled from the release on May 8.

What remains: AI Client, Connectors API, PHP-only block registration, and incremental editor refinements.
WordPress 7.0 is less “Google Docs-style co-editing arrives” and more “AI integration and block development scaffolding lands.”

May 20 target, but RC3 was effectively a restart beta

The WordPress 7.0 development page originally listed April 9, 2026 as the general release date.
Testing feedback on the real-time collaboration implementation pushed it back to May 20.

The confusing part: the May 8 RC3 was an RC in name only — it was treated as “new Beta 1.”
The updated release schedule reflects this mid-cycle adjustment.
As of May 12, the timeline is RC4 on May 14, dry run and 24-hour code freeze on May 19, general release on May 20.

The Path Forward for WordPress 7.0 was strict about scope during the delay.
No new features or enhancements — only bug fixes for issues introduced in the current release cycle.
The exceptions: stabilizing real-time collaboration and improving the Connectors admin experience.

AI Client is a shared calling layer, not an “AI writes for you” feature

The AI Client developer note clarifies that WordPress 7.0 introduces a common PHP API for plugins and themes to call AI providers.

Internally it has two layers.
One is a provider-agnostic PHP AI Client bundled with Core.
The other is a set of WordPress-flavored wrappers like wp_ai_client_prompt().

Plugin code can check whether text generation, image generation, speech, or video are available through methods like is_supported_for_text_generation().
The official note explicitly warns against assuming AI features work just because WordPress 7.0 is installed.
API keys and models depend on Connectors and provider plugins, covered below.

This connects to the earlier ACF 6.8 making WordPress an AI agent operation target.
ACF 6.8 used the WordPress 6.9 Abilities API to expose custom post types and field group operations to AI agents.
The 7.0 AI Client standardizes the layer below that — how to call AI providers from Core.

Connectors API centralizes API key management in Core

The Connectors API is a system for registering and managing external service connections.
The initial focus is AI providers — WordPress 7.0 ships three featured connectors: Anthropic, Google, and OpenAI.
A new Settings → Connectors screen standardizes API key storage and provider discovery.

Each Connector carries a display name, description, logo, authentication config, and associated plugin info.
If a provider plugin integrates with the WP AI Client, it gets auto-discovered through the Connectors API.
The goal: stop plugin authors from each building their own API key storage UI.

This is characteristically WordPress.
Rather than shipping a massive AI feature directly in Core, it builds the common registry and settings surface for plugins to hook into.
With Abilities API, AI Client, and Connectors API together, WordPress moves toward being a CMS that AI can natively understand and invoke.

PHP-only block registration without JavaScript

The most immediately useful developer change is PHP-only block registration.
Adding 'supports' => array( 'autoRegister' => true ) to register_block_type() with a render_callback lets you put a simple server-rendered block in the editor — no block.json, no JavaScript registration file.

This does not move all Gutenberg block development back to PHP.
The official note is clear: it is not meant to replace interactive blocks or rich editing experiences.
But for classic themes or server-driven sites where you just want to blockify a small display component, it removes the need for a build pipeline.

If attribute types are supported, Inspector Controls (the sidebar editing panel) are auto-generated.
For legacy WordPress projects gradually migrating shortcodes to blocks, this is a direct fit.

Iframed editor changes in 7.0 are not forced

Iframed Editor Changes in WordPress 7.0 is a subtle but significant change for plugin authors.
Currently, the post editor checks the API version of all registered blocks to decide whether to iframe.
In 7.0, it only looks at blocks actually inserted in the post.

If all blocks in a post are Block API v3 or above, the post editor iframes. If an old block is present, it does not.
”Just installed” old blocks no longer prevent the entire post editor from iframing.

That said, WordPress 7.0 Core does not force iframing.
The Gutenberg plugin is testing forced iframing even for classic themes, but Core takes a gradual migration approach.
For sites carrying older blocks, this difference matters.

New blocks ship, but the center of gravity is AI integration

WordPress 7.0 adds blocks including Accordion, Breadcrumbs, Icon, Math, Post Time to Read, and Term Query.
The 7.0 design tools roster also covers the Poetry block rename and Accordion child blocks.

Visible changes for site builders, but the release’s center of gravity is AI infrastructure and external integration.
WordPress 6.9 advanced Abilities API, Block Bindings, and DataViews. 7.0 stacks AI Client and Connectors on top.
The bigger shift is how WordPress connects external services, AI providers, and CMS-internal capabilities — not individual block additions.

This trajectory puts WordPress on similar ground to concepts like Cloudflare’s EmDash, where AI and MCP are architectural primitives.
But WordPress carries the weight of its existing plugin ecosystem and diverse hosting environments.
The 7.0 delay and feature cuts are that constraint made visible.

Real-time collaboration was removed from 7.0

On May 8, Real-time collaboration will not ship in WordPress 7.0 was published.
Matt Mullenweg determined the current approach was not robust enough for Core.
The cited issues: surface area, race conditions, server load, memory efficiency, and bugs repeatedly found through fuzz testing.

Real-time collaboration was meant to let multiple users simultaneously edit the same post.
A Google Docs-like experience in the block editor — heavily anticipated as the 7.0 headline.

The direct cause of removal was hosting environment diversity.
Where to store sync data, how far HTTP polling scales across different hosts, how it degrades on shared servers without object caching.
The bottleneck was not UI progress but WordPress’s uniquely broad execution environment.

A same-day performance testing analysis compared four storage strategies: the RC2 post-meta implementation, a dedicated table, post meta with transients, and a dedicated table with transients.

Across eight hosting environments, custom-table-with-transients was recommended.
It averaged roughly 52% faster than the RC2 post-meta approach, and the pure dedicated table was about 37% faster.
Even so, the decision was to defer — not ship in 7.0.

Pulling the feature despite those numbers looks like a sound call.
WordPress runs on everything from shared hosting to large-scale managed environments; winning on the fastest tier is not enough.
If real-time collaboration breaks, the damage hits post data directly.

If you’re updating on May 20, it’s not for co-editing

The case for deploying WordPress 7.0 on May 20 rests on AI Client and Connectors API plugin validation, PHP-only block registration, and verifying iframed editor behavior.
Sites that were waiting for real-time co-editing get nothing from 7.0 itself.

For existing sites, the checkpoints are: whether your blocks are moving toward Block API v3, whether AI provider plugins start adopting the Connectors API, and where API key management migrates.
For setups that use WordPress as an AI agent target — ACF, MCP Adapter, and similar — the permission boundaries of AI Client and Connectors become relevant alongside the Abilities API.

wp_ai_client_prompt() code examples

The entry point for AI Client is wp_ai_client_prompt(), using a fluent builder pattern.
Text generation ends with generate_text(), image generation with generate_image().

$text = wp_ai_client_prompt( 'WordPressのキャッシュ戦略を要約して' )
    ->using_temperature( 0.7 )
    ->generate_text();

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

echo wp_kses_post( $text );

Whether to show AI features in your plugin UI depends on is_supported_for_text_generation().
WordPress 7.0 alone does not enable AI — a provider plugin and API key must be configured for it to return true.

$builder = wp_ai_client_prompt( 'test' );

if ( $builder->is_supported_for_text_generation() ) {
    // Show text generation UI
}

is_supported_for_image_generation(), is_supported_for_speech_generation(), and similar methods exist — modality availability is provider-dependent.

For structured JSON responses, pass a schema to as_json_response().

$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( 'プラグイン5つとカテゴリを挙げて' )
    ->as_json_response( $schema )
    ->generate_text();

In a REST API callback:

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

generate_text_result() returns a GenerativeAiResult object.
getTokenUsage() gives token consumption, getProviderMetadata() gives provider info.

When multiple providers are registered via Connectors, model priority can be specified:

$result = wp_ai_client_prompt( '活版印刷の歴史を要約して' )
    ->using_model_preference(
        'claude-sonnet-4-6',
        'gemini-3.1-pro-preview',
        'gpt-5.4'
    )
    ->generate_text_result();

A filter hook to block prompt execution for non-admins:

add_filter(
    'wp_ai_client_prevent_prompt',
    function ( bool $prevent, WP_AI_Client_Prompt_Builder $builder ): bool {
        if ( ! current_user_can( 'manage_options' ) ) {
            return true;
        }
        return $prevent;
    },
    10,
    2
);

Connectors API plugin-side code

The data structure for a Connector registered by a provider plugin:

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',
    ),
)

Theme or plugin code checks for a connector before branching:

if ( wp_is_connector_registered( 'anthropic' ) ) {
    $connector = wp_get_connector( 'anthropic' );
    echo $connector['name']; // 'Anthropic'
}

Iterating over all registered connectors uses wp_get_connectors():

$connectors = wp_get_connectors();
foreach ( $connectors as $id => $connector ) {
    printf( '%s: %s', $connector['name'], $connector['description'] );
}

To override an existing connector’s description, unregister and re-register during wp_connectors_init:

add_action( 'wp_connectors_init', function ( WP_Connector_Registry $registry ) {
    if ( $registry->is_registered( 'anthropic' ) ) {
        $connector = $registry->unregister( 'anthropic' );
        $connector['description'] = __( 'Custom description.', 'my-plugin' );
        $registry->register( 'anthropic', $connector );
    }
} );

PHP-only block registration code

Adding 'supports' => array( 'autoRegister' => true ) to register_block_type() puts a block in the editor without block.json or a JavaScript registration file.

function my_register_php_only_blocks() {
    register_block_type(
        'my-plugin/example',
        array(
            'title'           => __( 'My Example Block', 'myplugin' ),
            'attributes'      => array(
                'title'   => array(
                    'label'   => __( 'Title', 'myplugin' ),
                    'type'    => 'string',
                    'default' => 'Hello World',
                ),
                'count'   => array(
                    'label'   => __( 'Count', 'myplugin' ),
                    'type'    => 'integer',
                    'default' => 5,
                ),
                'size'    => array(
                    'label'   => __( 'Size', 'myplugin' ),
                    'type'    => 'string',
                    'enum'    => array( 'small', 'medium', 'large' ),
                    'default' => 'medium',
                ),
            ),
            'render_callback' => function ( $attributes ) {
                return sprintf(
                    '<p>%s: %d items (%s)</p>',
                    esc_html( $attributes['title'] ),
                    $attributes['count'],
                    $attributes['size']
                );
            },
            'supports'        => array(
                'autoRegister' => true,
            ),
        )
    );
}

add_action( 'init', 'my_register_php_only_blocks' );

Attributes with a label get auto-generated Inspector Controls (the sidebar panel).
Supported types are string, number, integer, and boolean; adding enum produces a select box.
For “display-only” blocks migrated from shortcodes, this format is sufficient.

functions.php integration patterns

AI Client works not just standalone but embedded in hooks and shortcodes within existing WordPress workflows.
Several implementation patterns for functions.php or plugin files:

Auto-generate excerpt on publish

add_action( 'transition_post_status', function ( string $new, string $old, WP_Post $post ) {
    if ( 'publish' !== $new || ! empty( $post->post_excerpt ) ) {
        return;
    }

    $builder = wp_ai_client_prompt( 'test' );
    if ( ! $builder->is_supported_for_text_generation() ) {
        return;
    }

    $body = wp_strip_all_tags( $post->post_content );
    if ( mb_strlen( $body ) < 200 ) {
        return;
    }

    $excerpt = wp_ai_client_prompt(
        sprintf( "以下の記事を120文字以内で要約:\n\n%s", mb_substr( $body, 0, 3000 ) )
    )
        ->using_temperature( 0.3 )
        ->generate_text();

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

    remove_action( 'transition_post_status', __FUNCTION__ );
    wp_update_post( array(
        'ID'           => $post->ID,
        'post_excerpt' => sanitize_text_field( $excerpt ),
    ) );
}, 10, 3 );

This fires only when publishing a post with an empty excerpt.
transition_post_status is used instead of save_post to catch only draft-to-publish transitions — save_post would fire on every autosave, wasting API calls.
The hook removes itself before wp_update_post() to prevent recursion.

Shortcode for AI-generated summaries

add_shortcode( 'ai_summary', function ( $atts, $content = '' ) {
    if ( empty( $content ) ) {
        return '';
    }

    $cache_key = 'ai_sum_' . md5( $content );
    $cached    = get_transient( $cache_key );
    if ( false !== $cached ) {
        return $cached;
    }

    $builder = wp_ai_client_prompt( 'test' );
    if ( ! $builder->is_supported_for_text_generation() ) {
        return wp_kses_post( $content );
    }

    $summary = wp_ai_client_prompt( "以下を3行で要約:\n\n" . $content )
        ->using_temperature( 0.3 )
        ->generate_text();

    if ( is_wp_error( $summary ) ) {
        return wp_kses_post( $content );
    }

    $html = '<div class="ai-summary">' . wp_kses_post( $summary ) . '</div>';
    set_transient( $cache_key, $html, DAY_IN_SECONDS );
    return $html;
} );

Wrap content with [ai_summary]long text[/ai_summary] to get an AI summary.
Results are cached in a transient for one day, so the API is hit only once.
When no provider is configured, it returns the original content unchanged — no breakage.

WP-Cron batch processing for existing posts

For bulk AI processing of existing posts, pair with wp_schedule_event():

add_action( 'my_ai_batch_tags', function () {
    $builder = wp_ai_client_prompt( 'test' );
    if ( ! $builder->is_supported_for_text_generation() ) {
        return;
    }

    $posts = get_posts( array(
        'post_type'      => 'post',
        'post_status'    => 'publish',
        'posts_per_page' => 5,
        'meta_query'     => array(
            array(
                'key'     => '_ai_tagged',
                'compare' => 'NOT EXISTS',
            ),
        ),
    ) );

    foreach ( $posts as $post ) {
        $body = wp_strip_all_tags( $post->post_content );

        $result = wp_ai_client_prompt(
            sprintf( "以下の記事にタグを3〜5個、カンマ区切りで返して:\n\n%s", mb_substr( $body, 0, 3000 ) )
        )
            ->using_temperature( 0.2 )
            ->generate_text();

        if ( ! is_wp_error( $result ) ) {
            $tag_array = array_map( 'trim', explode( ',', $result ) );
            wp_set_post_tags( $post->ID, $tag_array, true );
        }

        update_post_meta( $post->ID, '_ai_tagged', time() );
    }
} );

if ( ! wp_next_scheduled( 'my_ai_batch_tags' ) ) {
    wp_schedule_event( time(), 'hourly', 'my_ai_batch_tags' );
}

posts_per_page is set to 5 for API rate limit and timeout safety.
_ai_tagged meta marks processed posts, advancing 5 per hour.
The same structure applies to category assignment, description generation, or other AI-driven batch tasks.