Skip to content

Latest commit

 

History

History
465 lines (349 loc) · 17.4 KB

File metadata and controls

465 lines (349 loc) · 17.4 KB

Meta Description

Summary

The Meta Description experiment adds AI-powered meta description generation to the WordPress post editor. It provides a "Meta Description" sidebar panel with a modal workflow for generating, selecting, editing, and applying meta descriptions. The experiment automatically detects active SEO plugins (Yoast SEO, Rank Math, All in One SEO, SEOPress) and writes to the correct meta field. It registers a WordPress Ability (ai/meta-description) that can be used both through the admin UI and directly via REST API requests.

Overview

For End Users

When enabled, the Meta Description experiment adds a "Meta Description" panel to the post editor sidebar. Users can generate AI-powered meta description suggestions optimized for search engines, select or edit a suggestion, and apply it to their post.

Key Features:

  • Generates a meta description suggestion from post content and title
  • Suggestions target the optimal 140–160 character range for search engine display
  • Editable textarea allows fine-tuning the suggestion before applying
  • Live character count with color-coded indicator (green for 140–160, yellow outside range)
  • Automatic SEO plugin detection — writes to the correct meta field for Yoast SEO, Rank Math, All in One SEO, and SEOPress
  • Falls back to a standard post meta field (wpai_meta_description) when no SEO plugin is active
  • Copy to clipboard functionality for use with unsupported SEO plugins or external tools
  • Works with any post type that has show_in_rest enabled

Workflow:

  1. Open or create a post in the editor
  2. Find the "Meta Description" panel in the sidebar
  3. Click "Generate meta description" to open the modal
  4. Review the AI-generated suggestion in the textarea and edit as needed
  5. Click "Apply" to save the description to the appropriate meta field
  6. Save/update the post as usual

For Developers

The experiment consists of three main components:

  1. Experiment Class (WordPress\AI\Experiments\Meta_Description\Meta_Description): Handles registration, asset enqueuing, post meta registration, and SEO plugin detection
  2. Ability Class (WordPress\AI\Abilities\Meta_Description\Meta_Description): Implements the core meta description generation logic via the WordPress Abilities API
  3. SEO Integration (WordPress\AI\Abilities\Meta_Description\SEO_Integration): Utility class for detecting active SEO plugins and resolving the correct meta key

The ability can be called directly via REST API, making it useful for automation, bulk processing, or custom integrations.

Architecture & Implementation

Key Hooks & Entry Points

  • WordPress\AI\Experiments\Meta_Description\Meta_Description::register() wires everything once the experiment is enabled:
    • wp_abilities_api_init → registers the ai/meta-description ability (includes/Abilities/Meta_Description/Meta_Description.php)
    • admin_enqueue_scripts → enqueues the React bundle and styles on post.php and post-new.php screens for REST-enabled post types
    • init → registers the fallback post meta key for REST API access (only when no SEO plugin is active)

Assets & Data Flow

  1. PHP Side:

    • enqueue_assets() loads experiments/meta-description (src/experiments/meta-description/index.tsx) and localizes window.aiMetaDescriptionData with:
      • enabled: Whether the experiment is enabled
      • metaKey: The resolved meta key for the active SEO plugin (or fallback)
      • seoPlugin: The slug of the detected SEO plugin, or null
  2. React Side:

    • The React entry point (index.tsx) registers a PluginDocumentSettingPanel in the editor sidebar
    • MetaDescriptionPanel component shows the current description with edit/regenerate actions, or a generate button if none exists
    • Clicking generate or edit opens MetaDescriptionModal which displays an editable textarea populated with the generated suggestion
    • useMetaDescription hook:
      • Gets current post ID, content, title, and existing meta description from the editor store
      • Calls the ability via runAbility() when generation is triggered
      • Updates the post meta via editPost() when a description is applied
      • Copy to clipboard uses WordPress's useCopyToClipboard from @wordpress/compose
  3. Ability Execution:

    • Accepts content (string), title (string), and post_id (integer) as input
    • If post_id is provided, fetches post content and context using get_post_context()
    • Normalizes content using normalize_content() helper
    • Sends content to AI client with system instruction targeting 140–160 character descriptions
    • Returns an object with a single description suggestion, including the text and character count

Input Schema

The ability accepts the following input parameters:

array(
    'content' => array(
        'type'        => 'string',
        'description' => 'Post content to generate a meta description for.',
    ),
    'title'   => array(
        'type'        => 'string',
        'description' => 'The post title, used to avoid duplication in the generated description.',
    ),
    'post_id' => array(
        'type'        => 'integer',
        'description' => 'The post ID to generate a meta description for. If provided without content, the post content will be used.',
    ),
)

Output Schema

The ability returns an object containing a single description suggestion:

array(
    'type'       => 'object',
    'properties' => array(
        'description' => array(
            'type'       => 'object',
            'properties' => array(
                'text'            => array( 'type' => 'string' ),
                'character_count' => array( 'type' => 'integer' ),
            ),
        ),
    ),
)

Permissions

The ability checks permissions based on the input:

  • If post_id is provided:

    • Verifies the post exists
    • Checks current_user_can( 'edit_post', $post_id )
    • Ensures the post type has show_in_rest enabled
  • If post_id is not provided:

    • Checks current_user_can( 'edit_posts' )

SEO Plugin Detection

The SEO_Integration utility class detects active SEO plugins and resolves the correct meta key:

Plugin Slug Meta Key
Yoast SEO yoast-seo _yoast_wpseo_metadesc
Rank Math rank-math rank_math_description
All in One SEO all-in-one-seo _aioseo_description
SEOPress seopress _seopress_titles_desc
None (fallback) wpai_meta_description

When no SEO plugin is active, the experiment registers the fallback wpai_meta_description meta key for REST-enabled post types so it can be read and written through the WordPress data layer.

Using the Ability via REST API

The meta description ability can be called directly via REST API, making it useful for automation, bulk processing, or custom integrations.

Endpoint

POST /wp-json/wp-abilities/v1/abilities/ai/meta-description/run

Authentication

You can authenticate using either:

  1. Application Password (Recommended)
  2. Cookie Authentication with Nonce

See TESTING_REST_API.md for detailed authentication instructions.

Request Examples

Example 1: Generate from Content and Title

curl -X POST "https://yoursite.com/wp-json/wp-abilities/v1/abilities/ai/meta-description/run" \
  -u "username:application-password" \
  -H "Content-Type: application/json" \
  -d '{
    "input": {
      "content": "This is a comprehensive article about artificial intelligence and machine learning. AI has revolutionized many industries including healthcare, finance, and transportation.",
      "title": "How AI is Transforming Industries"
    }
  }'

Response:

{
  "description": {
    "text": "Discover how artificial intelligence and machine learning are revolutionizing healthcare, finance, and transportation with data-driven insights and automation.",
    "character_count": 156
  }
}

Example 2: Generate from Post ID

curl -X POST "https://yoursite.com/wp-json/wp-abilities/v1/abilities/ai/meta-description/run" \
  -u "username:application-password" \
  -H "Content-Type: application/json" \
  -d '{
    "input": {
      "post_id": 123
    }
  }'

This will automatically fetch the content and title from post ID 123 and generate a meta description suggestion.

Example 3: Using WordPress API Fetch (in Gutenberg/Admin)

import apiFetch from '@wordpress/api-fetch';

async function generateMetaDescription(content, title, postId = null) {
  const input = { content, title };
  if (postId) {
    input.post_id = postId;
  }

  try {
    const result = await apiFetch({
      path: '/wp-abilities/v1/abilities/ai/meta-description/run',
      method: 'POST',
      data: { input },
    });
    return result.description; // { text, character_count }
  } catch (error) {
    console.error('Error generating meta description:', error);
    throw error;
  }
}

Error Responses

The ability may return the following error codes:

  • post_not_found: The provided post ID does not exist
  • content_not_provided: No content was provided and no valid post ID was found
  • no_results: The AI client did not return any results
  • insufficient_capabilities: The current user does not have permission to generate meta descriptions

Example error response:

{
  "code": "content_not_provided",
  "message": "Content is required to generate a meta description.",
  "data": {
    "status": 400
  }
}

Extending the Experiment

Customizing the System Instruction

The system instruction that guides the AI can be customized by modifying:

includes/Abilities/Meta_Description/system-instruction.php

This file returns a string that instructs the AI on how to generate meta descriptions. You can modify the character length requirements, tone, style, or other parameters.

Filtering the Prompt Content

You can filter the assembled prompt before it is sent to the AI model:

add_filter( 'wpai_meta_description_prompt', function( $prompt, $content, $title ) {
    // Append custom instructions to the prompt
    $prompt .= "\n\n<instruction>Focus on the environmental impact angle.</instruction>";
    return $prompt;
}, 10, 3 );

Filtering the Result Temperature

You can adjust the AI temperature for more creative or more consistent results:

add_filter( 'wpai_meta_description_result_temperature', function( $temperature ) {
    return 0.3; // Lower temperature for more consistent output
} );

Registering Additional SEO Plugins

You can add support for additional SEO plugins:

add_filter( 'wpai_meta_description_seo_plugins', function( $plugins ) {
    $plugins['my-seo-plugin'] = array(
        'file'     => 'my-seo-plugin/my-seo-plugin.php',
        'meta_key' => '_my_seo_meta_description',
    );
    return $plugins;
} );

Overriding the Meta Key

You can override the resolved meta key regardless of which SEO plugin is detected:

add_filter( 'wpai_meta_description_meta_key', function( $key, $plugin_slug ) {
    return '_custom_meta_description_key';
}, 10, 2 );

Customizing the Meta Description Output

If no SEO plugin is detected the Meta Description experiment will output the generated meta description into the <head> of single posts. This output can be filtered using the wpai_meta_description filter. You can prevent the output by returning false or an empty string.

// Output a custom meta description
add_filter( 'wpai_meta_description', function( $description ) {
    return 'My custom meta description.';
} );

// Prevent meta description output
add_filter( 'wpai_meta_description', '__return_false' );

Filtering Preferred Models

You can filter which AI models are used for meta description generation using the wpai_experiments_preferred_models_for_text_generation filter:

add_filter( 'wpai_experiments_preferred_models_for_text_generation', function( $models ) {
    return array(
        array( 'openai', 'gpt-4' ),
        array( 'anthropic', 'claude-haiku-4-5' ),
    );
} );

Customizing Content Normalization

The normalize_content() helper function processes content before sending it to the AI. You can filter the normalized content:

// Filter content before normalization
add_filter( 'wpai_experiments_pre_normalize_content', function( $content ) {
    // Custom preprocessing
    return $content;
} );

// Filter content after normalization
add_filter( 'wpai_experiments_normalize_content', function( $content ) {
    // Custom post-processing
    return $content;
} );

Testing

Manual Testing

  1. Enable the experiment:

    • Go to Settings → AI Experiments
    • Toggle Meta Description to enabled
    • Ensure you have valid AI credentials configured
  2. Test in the editor:

    • Create or edit a post with content
    • Find the "Meta Description" panel in the editor sidebar
    • Click "Generate meta description" to open the modal
    • Verify that a suggestion is generated and populates the textarea with a character count
    • Edit the text and verify the character count updates live
    • Click "Apply" and verify the description appears in the sidebar panel
    • Click "Edit description" and verify the modal opens with the current text
    • Click the regenerate icon and verify a new suggestion is generated
    • Test "Copy to clipboard" and verify the text is copied
  3. Test SEO plugin integration:

    • With Yoast SEO active, verify the description is saved to _yoast_wpseo_metadesc
    • Without any SEO plugin, verify the description is saved to wpai_meta_description
    • Verify the correct meta key is displayed in the localized data
  4. Test with different post types:

    • The experiment loads for any REST-enabled post type except attachments
    • Test with posts, pages, and custom post types
  5. Test REST API:

    • Use curl or Postman to test the REST endpoint
    • Verify authentication works
    • Test with different input combinations
    • Verify error handling for invalid inputs
  6. Test meta description output:

    • Apply an AI generated meta description to a post
    • Navigate to that post on the frontend
    • Confirm the AI generated meta description is output into the <head> component.

Automated Testing

Tests are located in:

  • tests/Integration/Includes/Abilities/Meta_DescriptionTest.php
  • tests/Integration/Includes/Abilities/Meta_Description/SEO_IntegrationTest.php
  • tests/Integration/Includes/Experiments/Meta_Description/Meta_DescriptionTest.php

Run tests with:

npm run test:php

Notes & Considerations

Requirements

  • The experiment requires valid AI credentials to be configured
  • The experiment loads for any post type with show_in_rest enabled, except attachments
  • Users must have edit_posts capability (or edit_post for specific posts when using post ID)

Performance

  • Meta description generation is an AI operation and may take several seconds
  • The UI shows a loading state (busy button) while generation is in progress
  • A single description is generated per API call

Content Processing

  • Content is normalized before being sent to the AI (HTML stripped, shortcodes removed, etc.)
  • The normalize_content() function handles this processing
  • Additional context from post metadata (title, categories, tags) can be included when using post ID
  • The post title is passed separately to prevent duplication in the generated description

AI Model Selection

  • The ability uses get_preferred_models_for_text_generation() to determine which AI models to use
  • Models are tried in order until one succeeds
  • Temperature defaults to 0.7 for balanced creativity and consistency (filterable via wpai_meta_description_result_temperature)

System Instruction

The system instruction guides the AI to:

  • Generate descriptions between 140 and 160 characters
  • Use plain text only (no markdown, HTML, or special formatting)
  • Avoid duplicating or closely mirroring the post title
  • Avoid keyword stuffing or repetitive terms
  • Use active, action-oriented language that encourages click-through
  • Accurately reflect the actual content

Limitations

  • Descriptions are generated in real-time and not cached
  • The ability does not support batch processing (one request generates a single description for a single post)
  • Generated descriptions are suggestions and should be reviewed before publishing
  • SEO plugin integration is read/write only for supported plugins — unsupported plugins require the wpai_meta_description_seo_plugins filter or copy-to-clipboard
  • The experiment requires JavaScript to be enabled in the admin

Related Files

  • Experiment: includes/Experiments/Meta_Description/Meta_Description.php
  • Ability: includes/Abilities/Meta_Description/Meta_Description.php
  • SEO Integration: includes/Abilities/Meta_Description/SEO_Integration.php
  • System Instruction: includes/Abilities/Meta_Description/system-instruction.php
  • React Entry: src/experiments/meta-description/index.tsx
  • React Components: src/experiments/meta-description/components/
  • Styles: src/experiments/meta-description/index.scss
  • Types: src/experiments/meta-description/types.ts
  • Tests: tests/Integration/Includes/Abilities/Meta_DescriptionTest.php
  • Tests: tests/Integration/Includes/Abilities/Meta_Description/SEO_IntegrationTest.php
  • Tests: tests/Integration/Includes/Experiments/Meta_Description/Meta_DescriptionTest.php