Skip to content

WPShout Newsletter

Sign up for news, tips, and insights to help you build better websites.

Newsletter - Top banner

WordPress AI Connectors: A Developer’s Guide to the 7.0 AI Client

WordPress 7.0 did not ship an AI feature. It shipped AI plumbing, and that is the more interesting story for anyone who builds on WordPress.

Instead of bolting a chatbot onto the dashboard, core now includes a Connectors screen for managing API keys, a Connectors API for registering connections to external services, and wp_ai_client_prompt(), a single provider-agnostic PHP function that lets any plugin send a prompt to an LLM. Which LLM? That is the site owner’s choice, configured once, and your code never has to care which one it is.

WPShout covered the release as a whole in the WordPress 7.0 overview, so this guide will not re-report it. Instead, it goes deeper on the developer side: what the WordPress AI connectors actually are, where the credentials live, how the AI Client works, and a complete, runnable example plugin at the end.

Architecture diagram: plugins connect through the WordPress Connectors API hub to AI providers OpenAI, Claude, and Gemini

What WordPress 7.0 actually shipped

The AI layer in 7.0 is two things stacked on top of each other. Underneath sits wordpress/php-ai-client, a provider-agnostic PHP SDK bundled into core as an external library. On top of it sits a WordPress wrapper, the WP_AI_Client_Prompt_Builder class, which translates the SDK into WordPress conventions: snake_case methods, WP_Error returns, and integration with the HTTP transport, hooks, and the Connectors infrastructure.

The piece site owners will actually see is the new Settings > Connectors screen:

The Settings, Connectors screen in WordPress 7.0 showing connector cards for Anthropic, Google, and OpenAI, with OpenAI marked as Connected
The new Settings > Connectors screen. OpenAI is connected; Anthropic and Google are one install away.

A few facts worth internalizing before writing any code:

  • Core bundles zero providers. The three official implementations, AI Provider for Anthropic, AI Provider for Google, and AI Provider for OpenAI, ship as separate plugins. Anyone can build a provider plugin for another service.
  • Provider plugins are auto-discovered. If a plugin registers with the WP AI Client’s provider registry, the Connectors API creates its connector entry automatically, with the correct metadata. No extra registration code needed.
  • Plugins never touch credentials. A plugin using the AI Client describes what it needs; WordPress routes the request to a suitable model from whatever provider the admin configured.

☝️ Worth knowing: nothing AI-related happens on a fresh 7.0 install. Until someone installs a provider plugin and adds a key, every AI call simply returns a WP_Error. Build for that case from line one.

Where the credentials live (and how to query them)

For connectors that authenticate with an API key, WordPress resolves the key in a fixed priority order:

  1. Environment variable, following the pattern {PROVIDER_ID}_API_KEY, so the Anthropic provider maps to ANTHROPIC_API_KEY.
  2. PHP constant, for example define( 'ANTHROPIC_API_KEY', 'sk-...' ); in wp-config.php.
  3. Database, stored through the Connectors screen in an auto-generated setting like connectors_ai_anthropic_api_key.

One honest caveat: keys stored in the database are not encrypted, only masked in the UI. Encryption is being explored in a follow-up ticket (#64789). On production sites, the environment variable route is the sensible default, and the Connectors screen helpfully shows which source a key came from.

The Connectors API itself is small. Three public functions query the registry after init:

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

$all = wp_get_connectors(); // Every registered connector, keyed by ID.Code language: PHP (php)

Overriding connector metadata (say, a custom description for a built-in provider) happens on the wp_connectors_init action, with an unregister, modify, register sequence against the WP_Connector_Registry instance. The registry rejects duplicate IDs, so the dance is mandatory. For most plugin developers this is trivia, since AI provider plugins get their connectors auto-created. It matters more for what the API becomes next: the architecture was designed for external services in general, not only AI.

Building with the WordPress AI connectors: wp_ai_client_prompt()

Every interaction starts the same way. wp_ai_client_prompt() returns a fluent builder; you chain configuration methods, then call a generation method:

$text = wp_ai_client_prompt( 'Write a haiku about WordPress.' )
	->generate_text();

if ( is_wp_error( $text ) ) {
	// No provider configured, invalid key, rate limited, and so on.
	return;
}

echo wp_kses_post( $text );Code language: PHP (php)

Notice the error handling. Generation methods return WP_Error on failure, following WordPress convention, and failure is a normal state here, not an edge case. The site might have no provider at all.

The builder surface covers the usual knobs: using_temperature(), using_max_tokens(), using_system_instruction(), top-p/top-k, stop sequences, and conversation history via with_history(). Beyond plain text, generate_texts( 4 ) returns variations, generate_image() returns a file DTO, and as_json_response( $schema ) constrains the model to a JSON schema for structured output.

Because your plugin cannot know which providers a given site has configured, model selection works by preference, not demand:

$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();Code language: PHP (php)

The AI Client walks the list and uses the first available model, falling back to any compatible one if none match. Treat the preference as a hint and write code that works without it. The generate_*_result() variants return a full GenerativeAiResult object with token usage and provider/model metadata, handy for logging costs, and it serializes straight into rest_ensure_response() if you are exposing the feature over the REST API.

Finally, feature detection. Support checks make no API calls and cost nothing, so gate your UI with them:

$probe = wp_ai_client_prompt( 'test' );

if ( $probe->is_supported_for_text_generation() ) {
	// Safe to show the AI-powered UI.
}Code language: PHP (php)

The full API surface is documented in the official AI Client dev note and the Connectors API dev note on Make/Core. Now for something runnable.

Example: a plugin that summarizes posts through the AI Client

This is a complete, working plugin. Drop it in wp-content/plugins/ai-post-summarizer.php, activate it, and a new Tools > AI Summary page lets you pick any published post and get a three-sentence summary from whatever provider the site has configured:

<?php
/**
 * Plugin Name:       AI Post Summarizer
 * Description:       Summarizes any published post with the WordPress 7.0 AI Client. Find it under Tools > AI Summary.
 * Version:           1.0.0
 * Requires at least: 7.0
 * License:           GPL-2.0-or-later
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

add_action( 'admin_menu', 'wpshout_aisum_add_menu' );

function wpshout_aisum_add_menu() {
	add_management_page(
		'AI Post Summary',
		'AI Summary',
		'manage_options',
		'wpshout-ai-summary',
		'wpshout_aisum_render_page'
	);
}

function wpshout_aisum_render_page() {
	if ( ! current_user_can( 'manage_options' ) ) {
		return;
	}

	echo '<div class="wrap"><h1>AI Post Summary</h1>';

	// The AI Client only exists on WordPress 7.0+.
	if ( ! function_exists( 'wp_ai_client_prompt' ) ) {
		echo '<p>This plugin requires WordPress 7.0 or newer.</p></div>';
		return;
	}

	// Feature detection: is any provider configured for text generation?
	$probe = wp_ai_client_prompt( 'test' );
	if ( ! $probe->is_supported_for_text_generation() ) {
		echo '<p>No AI provider is configured yet. Install a provider plugin and add an API key under Settings &gt; Connectors.</p></div>';
		return;
	}

	// Handle the form submission.
	$summary = null;
	if (
		isset( $_POST['wpshout_aisum_post_id'], $_POST['wpshout_aisum_nonce'] ) &&
		wp_verify_nonce( sanitize_key( $_POST['wpshout_aisum_nonce'] ), 'wpshout_aisum_summarize' )
	) {
		$post = get_post( absint( $_POST['wpshout_aisum_post_id'] ) );

		if ( $post ) {
			$content = wp_strip_all_tags( $post->post_content );

			$summary = wp_ai_client_prompt(
				"Summarize the following blog post in three sentences:\n\n" . $content
			)
				->using_temperature( 0.4 )
				->using_max_tokens( 300 )
				->generate_text();
		}
	}

	// Show the result, or the error if something went wrong.
	if ( null !== $summary ) {
		if ( is_wp_error( $summary ) ) {
			echo '<div class="notice notice-error"><p>' . esc_html( $summary->get_error_message() ) . '</p></div>';
		} else {
			echo '<div class="notice notice-success"><p>' . esc_html( $summary ) . '</p></div>';
		}
	}

	// A simple picker over the most recent published posts.
	$posts = get_posts(
		array(
			'post_type'      => 'post',
			'post_status'    => 'publish',
			'posts_per_page' => 50,
		)
	);

	echo '<form method="post">';
	wp_nonce_field( 'wpshout_aisum_summarize', 'wpshout_aisum_nonce' );
	echo '<select name="wpshout_aisum_post_id">';
	foreach ( $posts as $post ) {
		echo '<option value="' . esc_attr( $post->ID ) . '">' . esc_html( $post->post_title ) . '</option>';
	}
	echo '</select> ';
	submit_button( 'Summarize', 'primary', 'submit', false );
	echo '</form></div>';
}Code language: HTML, XML (xml)

Notice how little of that code is about AI. Most of it is standard wp-admin plumbing: a menu page, a nonce, a form. The actual AI work is five lines, and none of them mention OpenAI, Anthropic, or Google. A few details worth a second look:

  • The function_exists() guard keeps the plugin from fataling on pre-7.0 sites, even though the Requires at least header should already prevent activation there.
  • Feature detection runs before the form, so a site with no configured provider gets a helpful pointer to Settings > Connectors instead of a confusing error after submitting.
  • No credentials anywhere. The plugin does not know, and cannot know, which provider answered. Swapping providers is the site owner’s decision, zero code changes required.
  • WP_Error is a first-class outcome, rendered as a normal admin notice rather than a white screen.

Gotchas worth knowing before you ship

  • Never assume AI is available. Not every site has a provider, and not every provider supports every modality. Gate every AI-powered UI behind the is_supported_for_*() checks.
  • There is no spend limit in core. Any plugin can burn through the site owner’s API credits once a key is configured. The wp_ai_client_prevent_prompt filter is the escape hatch: it can block specific prompts (say, for non-admin users), and prevented prompts make the support checks return false, so well-behaved plugins hide their UI automatically.
  • Keep prompts server-side. A client-side JavaScript API exists as the separate wp-ai-client package, but it is not in core, requires admin-level capability, and is explicitly not recommended for distributed plugins. The recommended pattern is a small REST endpoint per feature, with your own permission checks, calling wp_ai_client_prompt() on the server.
  • Model preferences are wishes, not contracts. Always verify what actually answered via the result object’s provider and model metadata if your feature depends on a specific capability.
  • Migrating an existing plugin? Bump Requires at least to 7.0, drop the wordpress/php-ai-client Composer dependency, and replace AI_Client::prompt() calls with wp_ai_client_prompt(). Supporting older versions too means a conditional autoloader, since core now loads those classes itself.

Who is already building on this

The clearest real-world consumer so far is Otter, the block plugin from the same family behind WPShout. Since version 3.2, Otter’s AI features (its content generator and writing toolbar) run through the WordPress 7.0 native AI connectors: one provider configured at the WordPress level powers all of Otter’s AI features, with an OpenAI key in Otter’s own settings kept as a backward-compatible fallback. That is exactly the pattern core intended, and it is a useful reference for how a distributed plugin should behave.

Last word 💬

The WordPress AI connectors are easy to underestimate because nothing flashy happens when you update to 7.0. But the shape of the thing is right: credentials in one place, a provider-agnostic API, errors and detection that follow WordPress conventions. The plugin above took longer to lay out in this article than it did to write, and that is the point.

Already building something on the AI Client? What are you making it do?

Yay! 🎉 You made it to the end of the article!
Team WPShout
Share:

0 Comments
Most Voted
Newest Oldest