diff --git a/docs/experiments/editorial-notes.md b/docs/experiments/editorial-notes.md
index 33d5aaf40..33b93deec 100644
--- a/docs/experiments/editorial-notes.md
+++ b/docs/experiments/editorial-notes.md
@@ -119,7 +119,7 @@ Notes are `WP_Comment` objects with `comment_type = 'note'` and `status = 'hold'
- **New thread**: `POST /wp/v2/comments` with `parent: 0` → response `id` stored in `block.attributes.metadata.noteId` via `updateBlockAttributes`
- **Reply**: `POST /wp/v2/comments` with `parent: existingNoteId` → block metadata unchanged (association already set)
-- **AI author**: All Notes created by this experiment include `meta: { ai_note: true }`. The `rest_pre_insert_comment` filter intercepts this and sets the author to "WordPress AI" with no email, URL, or user ID, so Notes are not attributed to the authenticated user's account.
+- **AI author**: All Notes created by this experiment include `meta: { wpai_note: true }`. The `rest_pre_insert_comment` filter intercepts this and sets the author to "WordPress AI" with no email, URL, or user ID, so Notes are not attributed to the authenticated user's account.
- **Resolved Notes**: Notes with `status = 'approve'` (resolved) cause their associated block to be skipped entirely on the next review run.
## Using the Ability via REST API
diff --git a/docs/experiments/summarization.md b/docs/experiments/summarization.md
index 7515703f1..376cd2589 100644
--- a/docs/experiments/summarization.md
+++ b/docs/experiments/summarization.md
@@ -15,7 +15,7 @@ When enabled, the Content Summarization experiment adds a "Generate AI Summary"
- One-click summary generation from post content
- Automatically creates a group variation block with the summary
- Summary block can be regenerated from block toolbar
-- Summary is saved to post meta (`ai_generated_summary`)
+- Summary is saved to post meta (`wpai_generated_summary`)
- Works with any post type that supports the editor
### For Developers
@@ -330,7 +330,7 @@ The system instruction guides the AI to:
### Post Meta Storage
-- The summary is stored in post meta as `ai_generated_summary`
+- The summary is stored in post meta as `wpai_generated_summary`
- This meta is registered for the `post` post type and is available in REST API
- The meta is updated each time a summary is generated
- The meta can be accessed programmatically for custom use cases
diff --git a/docs/features/image-generation.md b/docs/features/image-generation.md
index e19463fbf..d177222aa 100644
--- a/docs/features/image-generation.md
+++ b/docs/features/image-generation.md
@@ -43,7 +43,7 @@ All three abilities can be called directly via REST API, making them useful for
### Key Hooks & Entry Points
- `WordPress\AI\Features\Image_Generation\Image_Generation::register()` wires everything once the feature is enabled:
- - `register_post_meta()` → registers `ai_generated` post meta for attachment post type
+ - `register_post_meta()` → registers `wpai_generated` post meta for attachment post type
- `wp_abilities_api_init` → registers the `ai/image-generation`, `ai/image-import`, and `ai/image-prompt-generation` abilities
- `admin_enqueue_scripts` → `enqueue_assets()` loads assets on `post.php` and `post-new.php` screens for post types that support featured images
- `enqueue_block_editor_assets` → `enqueue_inline_assets()` loads the same assets in the block editor for inline image generation
@@ -73,7 +73,7 @@ All three abilities can be called directly via REST API, making them useful for
- Updates the editor store to set the imported image as featured image
- Shows a loading state on the button and a progress message (with spinner) under the button while generating; clears both on success or error
- Handles error notifications via the notices store
- - `AILabel` component displays a label for AI-generated images by checking the `ai_generated` meta
+ - `AILabel` component displays a label for AI-generated images by checking the `wpai_generated` meta
3. **React Side (Inline Image Generation):**
- `inline.tsx` registers two filters for supported blocks (`core/image`, `core/cover`, `core/media-text`, `core/gallery`):
@@ -103,7 +103,7 @@ All three abilities can be called directly via REST API, making them useful for
- Accepts base64 image data and metadata (filename, title, description, alt_text, mime_type, meta)
- Decodes base64 data and creates temporary file
- Uses WordPress `media_handle_sideload()` to import into media library
- - Sets attachment metadata and custom meta (like `ai_generated`)
+ - Sets attachment metadata and custom meta (like `wpai_generated`)
- Returns attachment data (id, url, filename, title, description, alt_text)
### Input Schemas
@@ -837,7 +837,7 @@ npm run test:php
### Image Metadata
-- Imported images are marked with `ai_generated` post meta (set to `1`)
+- Imported images are marked with `wpai_generated` post meta (set to `1`)
- This meta is registered for the `attachment` post type and is available in REST API
- The `AILabel` component checks this meta to display the AI-generated label
- Additional custom meta can be passed via the `meta` parameter in the import ability
diff --git a/includes/Abilities/Image/Import_Base64_Image.php b/includes/Abilities/Image/Import_Base64_Image.php
index edab42c97..df28f195a 100644
--- a/includes/Abilities/Image/Import_Base64_Image.php
+++ b/includes/Abilities/Image/Import_Base64_Image.php
@@ -295,7 +295,7 @@ protected function import_image( string $data, array $args = array() ) {
);
if ( $args['ai_generated'] ) {
- $post_data['meta_input']['ai_generated'] = 1;
+ $post_data['meta_input']['wpai_generated'] = 1;
}
$attachment_id = media_handle_sideload( $file_array, 0, $args['description'], $post_data );
diff --git a/includes/Admin/Upgrades.php b/includes/Admin/Upgrades.php
index 56cd5bced..a3cad8fce 100644
--- a/includes/Admin/Upgrades.php
+++ b/includes/Admin/Upgrades.php
@@ -13,6 +13,7 @@
use WordPress\AI\Admin\Upgrades\V0_5_0;
use WordPress\AI\Admin\Upgrades\V0_6_0;
use WordPress\AI\Admin\Upgrades\V1_0_0;
+use WordPress\AI\Admin\Upgrades\V1_3_0;
// Exit if accessed directly.
defined( 'ABSPATH' ) || exit;
@@ -52,6 +53,7 @@ final class Upgrades {
V0_5_0::class,
V0_6_0::class,
V1_0_0::class,
+ V1_3_0::class,
);
/**
diff --git a/includes/Admin/Upgrades/V1_3_0.php b/includes/Admin/Upgrades/V1_3_0.php
new file mode 100644
index 000000000..009b05c7e
--- /dev/null
+++ b/includes/Admin/Upgrades/V1_3_0.php
@@ -0,0 +1,121 @@
+rename_post_meta_key( 'ai_generated', 'wpai_generated' );
+ $this->rename_post_meta_key( 'ai_generated_summary', 'wpai_generated_summary' );
+ $this->rename_comment_meta_key( 'ai_note', 'wpai_note' );
+
+ // Cache flush to update any stale data.
+ wp_cache_flush();
+ }
+
+ /**
+ * Renames a post meta key for every row that uses it.
+ *
+ * @since x.x.x
+ *
+ * @param string $old_key The existing meta key.
+ * @param string $new_key The meta key to migrate to.
+ */
+ private function rename_post_meta_key( string $old_key, string $new_key ): void {
+ global $wpdb;
+
+ // Rename the old key to the new key, but only for posts that don't already
+ // have the new key set. This avoids creating duplicate meta if new data was
+ // written under the new key before this migration ran.
+ $wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
+ $wpdb->prepare(
+ "UPDATE {$wpdb->postmeta} AS pm
+ LEFT JOIN {$wpdb->postmeta} AS existing
+ ON existing.post_id = pm.post_id AND existing.meta_key = %s
+ SET pm.meta_key = %s
+ WHERE pm.meta_key = %s AND existing.meta_id IS NULL",
+ $new_key,
+ $new_key,
+ $old_key
+ )
+ );
+
+ // Any rows still using the old key are duplicates of a pre-existing new key.
+ // The new value is authoritative, so remove the redundant old rows.
+ $wpdb->delete( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
+ $wpdb->postmeta,
+ array( 'meta_key' => $old_key )
+ );
+ }
+
+ /**
+ * Renames a comment meta key for every row that uses it.
+ *
+ * @since x.x.x
+ *
+ * @param string $old_key The existing meta key.
+ * @param string $new_key The meta key to migrate to.
+ */
+ private function rename_comment_meta_key( string $old_key, string $new_key ): void {
+ global $wpdb;
+
+ // Rename the old key to the new key, but only for comments that don't already
+ // have the new key set. This avoids creating duplicate meta if new data was
+ // written under the new key before this migration ran.
+ $wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
+ $wpdb->prepare(
+ "UPDATE {$wpdb->commentmeta} AS cm
+ LEFT JOIN {$wpdb->commentmeta} AS existing
+ ON existing.comment_id = cm.comment_id AND existing.meta_key = %s
+ SET cm.meta_key = %s
+ WHERE cm.meta_key = %s AND existing.meta_id IS NULL",
+ $new_key,
+ $new_key,
+ $old_key
+ )
+ );
+
+ // Any rows still using the old key are duplicates of a pre-existing new key.
+ // The new value is authoritative, so remove the redundant old rows.
+ $wpdb->delete( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
+ $wpdb->commentmeta,
+ array( 'meta_key' => $old_key )
+ );
+ }
+}
diff --git a/includes/Experiments/Editorial_Notes/Editorial_Notes.php b/includes/Experiments/Editorial_Notes/Editorial_Notes.php
index c5f4504b3..002c50ec9 100644
--- a/includes/Experiments/Editorial_Notes/Editorial_Notes.php
+++ b/includes/Experiments/Editorial_Notes/Editorial_Notes.php
@@ -59,7 +59,7 @@ public function register(): void {
register_meta(
'comment',
- 'ai_note',
+ 'wpai_note',
array(
'type' => 'boolean',
'single' => true,
@@ -97,7 +97,7 @@ public function register_abilities(): void {
* Overrides the author fields for AI-generated Notes before they are inserted.
*
* Fires via the rest_pre_insert_comment filter. When the REST request includes
- * meta.ai_note = true on a Note (comment_type "note") created by a user who can
+ * meta.wpai_note = true on a Note (comment_type "note") created by a user who can
* edit the target post, replaces the authenticated user's identity with a generic
* "AI" author so Notes are not attributed to a personal account.
*
@@ -114,7 +114,7 @@ public function maybe_set_ai_author( $prepared_comment, \WP_REST_Request $reques
$meta = $request->get_param( 'meta' );
- if ( ! is_array( $meta ) || empty( $meta['ai_note'] ) ) {
+ if ( ! is_array( $meta ) || empty( $meta['wpai_note'] ) ) {
return $prepared_comment;
}
diff --git a/includes/Experiments/Summarization/Summarization.php b/includes/Experiments/Summarization/Summarization.php
index 55381d988..e6cdfe08d 100644
--- a/includes/Experiments/Summarization/Summarization.php
+++ b/includes/Experiments/Summarization/Summarization.php
@@ -89,7 +89,7 @@ public function register_bulk_action_hooks_for_screen(): void {
public function register_post_meta(): void {
register_meta(
'post',
- 'ai_generated_summary',
+ 'wpai_generated_summary',
array(
'type' => 'string',
'single' => true,
diff --git a/includes/Features/Image_Generation/Image_Generation.php b/includes/Features/Image_Generation/Image_Generation.php
index 002ca6ec0..84b4abada 100644
--- a/includes/Features/Image_Generation/Image_Generation.php
+++ b/includes/Features/Image_Generation/Image_Generation.php
@@ -134,7 +134,7 @@ public function inject_generate_image_button(): void {
public function register_post_meta(): void {
register_post_meta(
'attachment',
- 'ai_generated',
+ 'wpai_generated',
array(
'type' => 'integer',
'single' => true,
diff --git a/src/experiments/editorial-notes/hooks/useEditorialNotes.ts b/src/experiments/editorial-notes/hooks/useEditorialNotes.ts
index 8cee1f7d1..94d5db56f 100644
--- a/src/experiments/editorial-notes/hooks/useEditorialNotes.ts
+++ b/src/experiments/editorial-notes/hooks/useEditorialNotes.ts
@@ -471,7 +471,7 @@ async function createNote(
type: 'note',
status: 'hold',
parent: existingNoteId ?? 0,
- meta: { ai_note: true },
+ meta: { wpai_note: true },
}
) ) as NoteRecord | undefined;
diff --git a/src/experiments/summarization/bulk.ts b/src/experiments/summarization/bulk.ts
index 912212799..029028ce3 100644
--- a/src/experiments/summarization/bulk.ts
+++ b/src/experiments/summarization/bulk.ts
@@ -167,7 +167,7 @@ async function processBulkSummary(): Promise< void > {
method: 'POST',
data: {
content: newContent,
- meta: { ai_generated_summary: summary },
+ meta: { wpai_generated_summary: summary },
},
} );
} catch {
diff --git a/src/experiments/summarization/functions/useSummaryGeneration.ts b/src/experiments/summarization/functions/useSummaryGeneration.ts
index c84876787..d783ed0d5 100644
--- a/src/experiments/summarization/functions/useSummaryGeneration.ts
+++ b/src/experiments/summarization/functions/useSummaryGeneration.ts
@@ -129,7 +129,7 @@ export function useSummaryGeneration() {
editPost( {
meta: {
...meta,
- ai_generated_summary: generatedSummary,
+ wpai_generated_summary: generatedSummary,
},
} );
diff --git a/src/features/image-generation/components/AILabel.tsx b/src/features/image-generation/components/AILabel.tsx
index 1ae0f2d47..f388c19bc 100644
--- a/src/features/image-generation/components/AILabel.tsx
+++ b/src/features/image-generation/components/AILabel.tsx
@@ -48,7 +48,7 @@ export default function AILabel( { label }: AILabelProps ): React.JSX.Element {
return (
<>
- { image && image?.meta?.ai_generated === 1 && (
+ { image && image?.meta?.wpai_generated === 1 && (
assertEquals( 'Custom Test Image Alt Text', get_post_meta( $result['image']['id'], '_wp_attachment_image_alt', true ), 'Attachment alt text should match' );
// Verify the AI-generated flag was saved.
- $this->assertSame( '1', get_post_meta( $result['image']['id'], 'ai_generated', true ), 'AI-generated flag should be saved' );
+ $this->assertSame( '1', get_post_meta( $result['image']['id'], 'wpai_generated', true ), 'AI-generated flag should be saved' );
}
/**
diff --git a/tests/Integration/Includes/Admin/Upgrades/V1_3_0Test.php b/tests/Integration/Includes/Admin/Upgrades/V1_3_0Test.php
new file mode 100644
index 000000000..ed80134d8
--- /dev/null
+++ b/tests/Integration/Includes/Admin/Upgrades/V1_3_0Test.php
@@ -0,0 +1,137 @@
+post->create( array( 'post_type' => 'attachment' ) );
+ update_post_meta( $attachment_id, 'ai_generated', 1 );
+
+ ( new V1_3_0( '1.2.0' ) )->run();
+
+ // Direct SQL updates bypass the in-request meta cache.
+ wp_cache_flush();
+
+ $this->assertSame( '1', get_post_meta( $attachment_id, 'wpai_generated', true ), 'ai_generated should migrate to wpai_generated.' );
+ $this->assertSame( '', get_post_meta( $attachment_id, 'ai_generated', true ), 'Old ai_generated meta should be removed.' );
+ }
+
+ /**
+ * Tests that run() renames the ai_generated_summary post meta key.
+ *
+ * @since x.x.x
+ */
+ public function test_run_renames_summary_meta(): void {
+ $post_id = self::factory()->post->create();
+ update_post_meta( $post_id, 'ai_generated_summary', 'A summary.' );
+
+ ( new V1_3_0( '1.2.0' ) )->run();
+
+ wp_cache_flush();
+
+ $this->assertSame( 'A summary.', get_post_meta( $post_id, 'wpai_generated_summary', true ), 'ai_generated_summary should migrate to wpai_generated_summary.' );
+ $this->assertSame( '', get_post_meta( $post_id, 'ai_generated_summary', true ), 'Old ai_generated_summary meta should be removed.' );
+ }
+
+ /**
+ * Tests that run() renames the ai_note comment meta key.
+ *
+ * @since x.x.x
+ */
+ public function test_run_renames_note_comment_meta(): void {
+ $comment_id = self::factory()->comment->create();
+ update_comment_meta( $comment_id, 'ai_note', true );
+
+ ( new V1_3_0( '1.2.0' ) )->run();
+
+ wp_cache_flush();
+
+ $this->assertSame( '1', get_comment_meta( $comment_id, 'wpai_note', true ), 'ai_note should migrate to wpai_note.' );
+ $this->assertSame( '', get_comment_meta( $comment_id, 'ai_note', true ), 'Old ai_note comment meta should be removed.' );
+ }
+
+ /**
+ * Tests that run() returns true on success.
+ *
+ * @since x.x.x
+ */
+ public function test_run_returns_success(): void {
+ $this->assertTrue( ( new V1_3_0( '1.2.0' ) )->run() );
+ }
+
+ /**
+ * Tests that run() skips migration when the version is already current.
+ *
+ * @since x.x.x
+ */
+ public function test_run_skips_when_version_already_current(): void {
+ $post_id = self::factory()->post->create();
+ update_post_meta( $post_id, 'ai_generated_summary', 'A summary.' );
+
+ ( new V1_3_0( '1.3.0' ) )->run();
+
+ wp_cache_flush();
+
+ $this->assertSame( 'A summary.', get_post_meta( $post_id, 'ai_generated_summary', true ), 'Old meta should be untouched when the upgrade is skipped.' );
+ $this->assertSame( '', get_post_meta( $post_id, 'wpai_generated_summary', true ), 'New meta should not be written when the upgrade is skipped.' );
+ }
+
+ /**
+ * Tests that run() does not create duplicate post meta when the new key
+ * already exists, keeping the new value and removing the legacy row.
+ *
+ * @since x.x.x
+ */
+ public function test_run_does_not_duplicate_post_meta_when_new_key_exists(): void {
+ $post_id = self::factory()->post->create();
+ update_post_meta( $post_id, 'ai_generated_summary', 'Legacy summary.' );
+ update_post_meta( $post_id, 'wpai_generated_summary', 'New summary.' );
+
+ ( new V1_3_0( '1.2.0' ) )->run();
+
+ wp_cache_flush();
+
+ $this->assertSame( array( 'New summary.' ), get_post_meta( $post_id, 'wpai_generated_summary', false ), 'The new key should keep its value with no duplicate row.' );
+ $this->assertSame( '', get_post_meta( $post_id, 'ai_generated_summary', true ), 'The legacy post meta row should be removed.' );
+ }
+
+ /**
+ * Tests that run() does not create duplicate comment meta when the new key
+ * already exists, keeping the new value and removing the legacy row.
+ *
+ * @since x.x.x
+ */
+ public function test_run_does_not_duplicate_comment_meta_when_new_key_exists(): void {
+ $comment_id = self::factory()->comment->create();
+ update_comment_meta( $comment_id, 'ai_note', 'Legacy note.' );
+ update_comment_meta( $comment_id, 'wpai_note', 'New note.' );
+
+ ( new V1_3_0( '1.2.0' ) )->run();
+
+ wp_cache_flush();
+
+ $this->assertSame( array( 'New note.' ), get_comment_meta( $comment_id, 'wpai_note', false ), 'The new key should keep its value with no duplicate row.' );
+ $this->assertSame( '', get_comment_meta( $comment_id, 'ai_note', true ), 'The legacy comment meta row should be removed.' );
+ }
+}
diff --git a/tests/Integration/Includes/Experiments/Editorial_Notes/Editorial_NotesTest.php b/tests/Integration/Includes/Experiments/Editorial_Notes/Editorial_NotesTest.php
index b9255362e..8159e173a 100644
--- a/tests/Integration/Includes/Experiments/Editorial_Notes/Editorial_NotesTest.php
+++ b/tests/Integration/Includes/Experiments/Editorial_Notes/Editorial_NotesTest.php
@@ -116,14 +116,15 @@ public function test_register_abilities_registers_editorial_notes_ability() {
}
/**
- * Tests that the ai_note comment meta is registered with show_in_rest.
+ * Tests that the wpai_note comment meta is registered with show_in_rest.
*
* @since 0.4.0
+ * @since x.x.x Renamed test method name from `test_ai_note_comment_meta_is_registered`.
*/
- public function test_ai_note_comment_meta_is_registered() {
+ public function test_wpai_note_comment_meta_is_registered() {
$registered = get_registered_meta_keys( 'comment' );
- $this->assertArrayHasKey( 'ai_note', $registered, 'ai_note meta should be registered for comments' );
- $this->assertTrue( $registered['ai_note']['show_in_rest'], 'ai_note meta should have show_in_rest enabled' );
+ $this->assertArrayHasKey( 'wpai_note', $registered, 'wpai_note meta should be registered for comments' );
+ $this->assertTrue( $registered['wpai_note']['show_in_rest'], 'wpai_note meta should have show_in_rest enabled' );
}
/**
@@ -168,7 +169,7 @@ public function test_enqueue_assets_localizes_filtered_min_content_length() {
// -------------------------------------------------------------------------
/**
- * Tests that maybe_set_ai_author() overrides author fields when meta.ai_note is true,
+ * Tests that maybe_set_ai_author() overrides author fields when meta.wpai_note is true,
* the comment is a Note, and the current user can edit posts.
*
* @since 0.4.0
@@ -188,7 +189,7 @@ public function test_maybe_set_ai_author_overrides_author_when_ai_note_true() {
);
$request = new \WP_REST_Request( 'POST', '/wp/v2/comments' );
- $request->set_param( 'meta', array( 'ai_note' => true ) );
+ $request->set_param( 'meta', array( 'wpai_note' => true ) );
$result = $this->experiment->maybe_set_ai_author( $prepared, $request );
@@ -200,10 +201,10 @@ public function test_maybe_set_ai_author_overrides_author_when_ai_note_true() {
}
/**
- * Tests that maybe_set_ai_author() returns a WP_Error when meta.ai_note is true
+ * Tests that maybe_set_ai_author() returns a WP_Error when meta.wpai_note is true
* but the current user cannot edit posts.
*
- * Guards against identity spoofing: the author override and the ai_note meta
+ * Guards against identity spoofing: the author override and the wpai_note meta
* auth_callback must enforce the same edit_posts capability, otherwise a
* low-privileged user could create a comment attributed to the "WordPress AI"
* identity (the comment is committed before the later meta save is rejected).
@@ -220,7 +221,7 @@ public function test_maybe_set_ai_author_returns_error_for_unauthorized_user() {
);
$request = new \WP_REST_Request( 'POST', '/wp/v2/comments' );
- $request->set_param( 'meta', array( 'ai_note' => true ) );
+ $request->set_param( 'meta', array( 'wpai_note' => true ) );
$result = $this->experiment->maybe_set_ai_author( $prepared, $request );
@@ -230,7 +231,7 @@ public function test_maybe_set_ai_author_returns_error_for_unauthorized_user() {
/**
* Tests that maybe_set_ai_author() does not override the author for a non-Note
- * comment, even when meta.ai_note is true and the user can edit posts.
+ * comment, even when meta.wpai_note is true and the user can edit posts.
*
* The AI identity is reserved for Notes; a regular comment must remain attributed
* to its actual author.
@@ -250,7 +251,7 @@ public function test_maybe_set_ai_author_passes_through_non_note_comment() {
);
$request = new \WP_REST_Request( 'POST', '/wp/v2/comments' );
- $request->set_param( 'meta', array( 'ai_note' => true ) );
+ $request->set_param( 'meta', array( 'wpai_note' => true ) );
$result = $this->experiment->maybe_set_ai_author( $prepared, $request );
@@ -260,7 +261,7 @@ public function test_maybe_set_ai_author_passes_through_non_note_comment() {
}
/**
- * Tests that maybe_set_ai_author() leaves data unchanged when meta.ai_note is absent.
+ * Tests that maybe_set_ai_author() leaves data unchanged when meta.wpai_note is absent.
*
* @since 0.4.0
*/
@@ -281,7 +282,7 @@ public function test_maybe_set_ai_author_passes_through_without_ai_note() {
}
/**
- * Tests that maybe_set_ai_author() passes through when meta.ai_note is false.
+ * Tests that maybe_set_ai_author() passes through when meta.wpai_note is false.
*
* @since 0.4.0
*/
@@ -292,7 +293,7 @@ public function test_maybe_set_ai_author_passes_through_when_ai_note_false() {
);
$request = new \WP_REST_Request( 'POST', '/wp/v2/comments' );
- $request->set_param( 'meta', array( 'ai_note' => false ) );
+ $request->set_param( 'meta', array( 'wpai_note' => false ) );
$result = $this->experiment->maybe_set_ai_author( $prepared, $request );
@@ -308,7 +309,7 @@ public function test_maybe_set_ai_author_passes_through_when_ai_note_false() {
public function test_maybe_set_ai_author_returns_wp_error_unchanged() {
$error = new \WP_Error( 'test_error', 'Test error message' );
$request = new \WP_REST_Request( 'POST', '/wp/v2/comments' );
- $request->set_param( 'meta', array( 'ai_note' => true ) );
+ $request->set_param( 'meta', array( 'wpai_note' => true ) );
$result = $this->experiment->maybe_set_ai_author( $error, $request );
@@ -321,17 +322,18 @@ public function test_maybe_set_ai_author_returns_wp_error_unchanged() {
// -------------------------------------------------------------------------
/**
- * Tests that a subscriber posting a comment with meta.ai_note = true is rejected
+ * Tests that a subscriber posting a comment with meta.wpai_note = true is rejected
* and that no comment row is persisted.
*
* This is the regression guard for the spoofing report: because WordPress core
- * commits the comment before the ai_note meta auth_callback runs, a fix that only
+ * commits the comment before the wpai_note meta auth_callback runs, a fix that only
* gated the meta would still leave an orphaned, spoofed comment in the database.
* Aborting in the rest_pre_insert_comment filter must prevent the row entirely.
*
* @since 1.1.0
+ * @since x.x.x Renamed test method name from `test_subscriber_ai_note_request_is_rejected_and_persists_no_comment`
*/
- public function test_subscriber_ai_note_request_is_rejected_and_persists_no_comment() {
+ public function test_subscriber_wpai_note_request_is_rejected_and_persists_no_comment() {
do_action( 'rest_api_init', rest_get_server() );
$author_id = self::factory()->user->create( array( 'role' => 'author' ) );
@@ -343,7 +345,7 @@ public function test_subscriber_ai_note_request_is_rejected_and_persists_no_comm
$request = new \WP_REST_Request( 'POST', '/wp/v2/comments' );
$request->set_param( 'post', $post_id );
$request->set_param( 'content', 'This paragraph has accessibility issues and should be rewritten.' );
- $request->set_param( 'meta', array( 'ai_note' => true ) );
+ $request->set_param( 'meta', array( 'wpai_note' => true ) );
$response = rest_get_server()->dispatch( $request );
@@ -355,7 +357,7 @@ public function test_subscriber_ai_note_request_is_rejected_and_persists_no_comm
}
/**
- * Tests that an editor posting a comment with meta.ai_note = true succeeds and the
+ * Tests that an editor posting a comment with meta.wpai_note = true succeeds and the
* persisted comment is attributed to the AI identity rather than the editor.
*
* @since 1.1.0
@@ -371,7 +373,7 @@ public function test_editor_ai_note_request_creates_ai_attributed_comment() {
$request->set_param( 'post', $post_id );
$request->set_param( 'content', 'AI editorial suggestion.' );
$request->set_param( 'type', 'note' );
- $request->set_param( 'meta', array( 'ai_note' => true ) );
+ $request->set_param( 'meta', array( 'wpai_note' => true ) );
$response = rest_get_server()->dispatch( $request );
@@ -407,7 +409,7 @@ public function test_enqueue_assets_runs_without_error() {
// -------------------------------------------------------------------------
/**
- * Tests that the ai_note meta auth_callback checks whether the user can edit the
+ * Tests that the wpai_note meta auth_callback checks whether the user can edit the
* comment's post.
*
* @since 1.1.0
@@ -419,14 +421,14 @@ public function test_ai_note_meta_auth_callback_returns_true_when_user_can_edit_
wp_set_current_user( $user_id );
$registered = get_registered_meta_keys( 'comment' );
- $callback = $registered['ai_note']['auth_callback'] ?? null;
+ $callback = $registered['wpai_note']['auth_callback'] ?? null;
$this->assertIsCallable( $callback, 'auth_callback should be callable' );
- $this->assertTrue( $callback( true, 'ai_note', $comment_id ), 'auth_callback should return true when the user can edit the comment post.' );
+ $this->assertTrue( $callback( true, 'wpai_note', $comment_id ), 'auth_callback should return true when the user can edit the comment post.' );
}
/**
- * Tests that the ai_note meta auth_callback returns false when the user cannot
+ * Tests that the wpai_note meta auth_callback returns false when the user cannot
* edit the comment's post.
*
* @since 1.1.0
@@ -440,9 +442,9 @@ public function test_ai_note_meta_auth_callback_returns_false_when_user_cannot_e
wp_set_current_user( $other_author_id );
$registered = get_registered_meta_keys( 'comment' );
- $callback = $registered['ai_note']['auth_callback'] ?? null;
+ $callback = $registered['wpai_note']['auth_callback'] ?? null;
$this->assertIsCallable( $callback, 'auth_callback should be callable' );
- $this->assertFalse( $callback( true, 'ai_note', $comment_id ), 'auth_callback should return false when the user cannot edit the comment post.' );
+ $this->assertFalse( $callback( true, 'wpai_note', $comment_id ), 'auth_callback should return false when the user cannot edit the comment post.' );
}
}
diff --git a/tests/Integration/Includes/Features/Image_Generation/Image_GenerationTest.php b/tests/Integration/Includes/Features/Image_Generation/Image_GenerationTest.php
index 030b64e9e..7d84712f7 100644
--- a/tests/Integration/Includes/Features/Image_Generation/Image_GenerationTest.php
+++ b/tests/Integration/Includes/Features/Image_Generation/Image_GenerationTest.php
@@ -127,9 +127,9 @@ public function test_feature_registers_post_meta() {
// Verify post meta is registered for attachment post type.
$meta = get_registered_meta_keys( 'post', 'attachment' );
- $this->assertArrayHasKey( 'ai_generated', $meta, 'ai_generated meta should be registered for attachment post type' );
- $this->assertEquals( 'integer', $meta['ai_generated']['type'], 'ai_generated meta type should be integer' );
- $this->assertTrue( $meta['ai_generated']['show_in_rest'], 'ai_generated meta should be available in REST API' );
+ $this->assertArrayHasKey( 'wpai_generated', $meta, 'wpai_generated meta should be registered for attachment post type' );
+ $this->assertEquals( 'integer', $meta['wpai_generated']['type'], 'wpai_generated meta type should be integer' );
+ $this->assertTrue( $meta['wpai_generated']['show_in_rest'], 'wpai_generated meta should be available in REST API' );
}
/**
diff --git a/tests/e2e/specs/experiments/editorial-updates.spec.js b/tests/e2e/specs/experiments/editorial-updates.spec.js
index 0a3b4fa24..ff8b9b070 100644
--- a/tests/e2e/specs/experiments/editorial-updates.spec.js
+++ b/tests/e2e/specs/experiments/editorial-updates.spec.js
@@ -82,7 +82,7 @@ test.describe( 'Editorial Updates Experiment', () => {
type: 'note',
status: 'hold',
meta: {
- ai_note: true,
+ wpai_note: true,
},
},
} );
@@ -107,7 +107,7 @@ test.describe( 'Editorial Updates Experiment', () => {
id: noteId,
parent: 0,
content: { rendered: 'Make this better.
' },
- meta: { ai_note: true },
+ meta: { wpai_note: true },
};
// Intercept all /wp/v2/comments requests to guarantee stable results.
@@ -279,7 +279,7 @@ test.describe( 'Editorial Updates Experiment', () => {
type: 'note',
status: 'hold',
meta: {
- ai_note: true,
+ wpai_note: true,
},
},
} );
@@ -291,7 +291,7 @@ test.describe( 'Editorial Updates Experiment', () => {
id: noteId,
parent: 0,
content: { rendered: 'Make this clearer.
' },
- meta: { ai_note: true },
+ meta: { wpai_note: true },
};
await page.route( /\/wp\/v2\/comments/, async ( route ) => {
@@ -433,7 +433,7 @@ test.describe( 'Editorial Updates Experiment', () => {
content: 'Fix this.',
type: 'note',
status: 'hold',
- meta: { ai_note: true },
+ meta: { wpai_note: true },
},
} );
@@ -453,7 +453,7 @@ test.describe( 'Editorial Updates Experiment', () => {
id: noteId,
parent: 0,
content: { rendered: 'Fix this.
' },
- meta: { ai_note: true },
+ meta: { wpai_note: true },
};
// Intercept note queries — always return the note so the button stays visible.