The Content Resizing experiment lets editors transform the content of an individual block in three ways — Shorten, Expand, or Rephrase — directly from the block toolbar. The experiment registers a WordPress Ability (ai/content-resizing) that returns the transformed text while preserving inline HTML (links, emphasis, code, etc.). The ability can be called both through the in-editor UI and directly via REST API for automation.
When enabled, the Content Resizing experiment adds a dropdown to the block toolbar of every selected paragraph block. Users pick Shorten, Expand, or Rephrase, and the experiment opens a modal showing the original text alongside the AI-generated replacement, with a word-count delta badge. Users can Accept the suggestion (which replaces the block content and visually flags the block as AI-resized), Regenerate for another pass, or close the modal to discard.
Key Features:
- Toolbar control on every
core/paragraphblock - Three actions: shorten (~50% of original), expand (~150–200% of original), rephrase (same length)
- Side-by-side original vs. suggested preview with word-count delta
- Inline HTML preservation — links,
<strong>,<em>, etc. survive the round-trip - Visual flag (
aiResizedblock attribute) on accepted suggestions - Shorten action requires the block to contain at least 5 words
The experiment consists of two main components:
- Experiment Class (
WordPress\AI\Experiments\Content_Resizing\Content_Resizing): handles registration, asset enqueuing, and UI integration. - Ability Class (
WordPress\AI\Abilities\Content_Resizing\Content_Resizing): implements the resizing logic via the WordPress Abilities API.
The ability can be called directly via REST API, making it useful for batch transforms or custom integrations outside the editor.
array(
'type' => 'object',
'properties' => array(
'post_id' => array(
'type' => 'integer',
'description' => 'The ID of the post to resize content for.',
),
'content' => array(
'type' => 'string',
'description' => 'The block content to resize.',
),
'action' => array(
'type' => 'string',
'enum' => array( 'shorten', 'expand', 'rephrase' ),
'default' => 'rephrase',
'description' => 'The resizing action to perform.',
),
),
)The ability returns a plain text string (with inline HTML preserved):
array(
'type' => 'string',
'description' => 'The resized content.',
)-
If
post_idis provided:- Verifies the post exists; returns
post_not_foundotherwise. - Checks
current_user_can( 'edit_post', $post_id ). - Note: unlike most other AI abilities, content resizing does not require the post type to have
show_in_restenabled — the check is purely capability-based.
- Verifies the post exists; returns
-
If
post_idis not provided:- Checks
current_user_can( 'edit_posts' ).
- Checks
POST /wp-json/wp-abilities/v1/abilities/ai/content-resizing/run
You can authenticate using either:
- Application Password (Recommended)
- Cookie Authentication with Nonce
See TESTING_REST_API.md for detailed authentication instructions.
curl -X POST "https://yoursite.com/wp-json/wp-abilities/v1/abilities/ai/content-resizing/run" \
-u "username:application-password" \
-H "Content-Type: application/json" \
-d '{
"input": {
"content": "Our new platform helps teams collaborate more effectively, share files securely, and track progress in real time.",
"action": "rephrase",
"post_id": 123
}
}'Response:
"Teams can work together more efficiently with our latest platform, exchanging files safely and monitoring progress as it happens."curl -X POST "https://yoursite.com/wp-json/wp-abilities/v1/abilities/ai/content-resizing/run" \
-u "username:application-password" \
-H "Content-Type: application/json" \
-d '{
"input": {
"content": "We are pleased to announce the <a href=\"https://example.com\">launch of our brand new product</a>, which represents months of careful planning and engineering work by our entire team.",
"action": "shorten"
}
}'The returned string preserves the <a> tag.
curl -X POST "https://yoursite.com/wp-json/wp-abilities/v1/abilities/ai/content-resizing/run" \
-u "username:application-password" \
-H "Content-Type: application/json" \
-d '{
"input": {
"content": "We launched today.",
"action": "expand"
}
}'Note: the shorten action requires at least 5 words (HTML stripped) in the input. Shorter inputs return
content_too_short. The 5-word floor does not apply to expand or rephrase.
import { runAbility } from '../../utils/run-ability';
const resized = await runAbility< string >( 'ai/content-resizing', {
content: blockContent,
action: 'shorten',
post_id: postId,
} );The ability may return the following error codes:
content_not_provided—contentwas missing or empty.content_too_short—action: 'shorten'was requested on input shorter than 5 words.post_not_found— Apost_idwas supplied but the post doesn't exist.insufficient_capabilities— Caller lacksedit_post(withpost_id) oredit_posts(without).no_results— The AI client did not return any text.- A WP_Error from
ensure_text_generation_supported()if no connected provider supports text generation.
Example:
{
"code": "content_too_short",
"message": "A minimum of 5 words is required to shorten the content.",
"data": { "status": 400 }
}Each action selects a different goal paragraph in includes/Abilities/Content_Resizing/system-instruction.php (the $action variable is passed through Abstract_Ability::get_system_instruction()'s extract() mechanism). Modify this file to change tone, length targets, or per-action behavior.
To customize site-wide — without forking — register a wpai_system_instruction filter:
add_filter( 'wpai_system_instruction', function ( string $instruction, string $name, array $data ): string {
if ( 'ai/content-resizing' !== $name ) {
return $instruction;
}
return $instruction . "\nAlways match the brand tone described in <site-context>.";
}, 10, 3 );The ability uses WordPress\AI\get_preferred_models_for_text_generation(). Use the cross-cutting wpai_preferred_text_models filter to override:
add_filter( 'wpai_preferred_text_models', function ( array $models ): array {
return array(
array( 'anthropic', 'claude-sonnet-4-6' ),
array( 'openai', 'gpt-5.4-mini' ),
);
} );The shipping experiment only adds the toolbar to core/paragraph (and only registers the aiResized attribute on that block type). To target other text-bearing blocks, fork the React entry or write a companion plugin that hooks into editor.BlockEdit for additional block names and calls the same ai/content-resizing ability — the ability itself is block-agnostic and just resizes whatever string you send in.
-
Enable the experiment:
- Go to
Settings → AI - Toggle Content Resizing to enabled
- Ensure you have valid AI credentials configured
- Go to
-
Test in the editor:
- Create or edit a post and add a paragraph block with at least one full sentence
- Select the block; the AI dropdown appears in the block toolbar
- Try each of Shorten, Expand, Rephrase
- Verify the modal shows original vs. suggested with the correct word-delta badge
- Click Accept and verify the block content updates
- Click Regenerate and verify a fresh suggestion replaces the previous one
- Add a
<a>link or<strong>to the block and verify they survive a rephrase
-
Test the 5-word floor:
- With a paragraph of fewer than 5 words, click Shorten
- Verify a "Text is too short to shorten further" notice appears and no API call is made
-
Test REST API:
- Use curl or Postman to test the REST endpoint
- Verify authentication works
- Test with each of the three actions
- Verify
content_too_shortis returned forshortenon inputs with fewer than 5 words
- The experiment requires valid AI credentials to be configured.
- The toolbar only appears on
core/paragraphblocks. - Users must have
edit_post(when invoked with apost_id) oredit_posts(without) to call the ability.
- Content is not normalized before being sent to the AI — this is intentional, so inline HTML survives the round-trip.
- The system instruction tells the model to preserve any inline HTML and match the original language.
- The returned string is filtered through
wp_kses_post()before leaving the ability.
- The ability uses
get_preferred_models_for_text_generation()to choose a model. - Models are tried in order until one succeeds.
- Temperature is set to 0.7 for some natural variation across regenerations.
The action-specific goals encoded in system-instruction.php:
- Rephrase: different wording, same meaning, tone, detail, and approximate length.
- Shorten: condense to roughly half the original length while preserving core meaning and tone.
- Expand: grow to roughly 1.5–2× the original length with consistent supporting detail.
All three share these requirements: return only the transformed text (no preamble), preserve inline HTML, match the original language, and maintain perspective and voice.
- One block per request — there is no batch endpoint.
- Suggestions are generated in real time and not cached.
- The toolbar is hard-coded to
core/paragraph; other blocks need a custom integration (see "Extending to Other Block Types" above). - The
aiResizedflag is purely informational — it doesn't change how the block renders on the front end.