From 8bb53a3e58650f75f97882e7f6c409f23b8d0458 Mon Sep 17 00:00:00 2001 From: Tim Carr Date: Wed, 22 Jul 2026 16:45:39 +0800 Subject: [PATCH] Abilities API: Post Settings --- ...nvertkit-mcp-ability-post-settings-get.php | 139 +++++++ ...rtkit-mcp-ability-post-settings-update.php | 172 ++++++++ ...s-convertkit-mcp-ability-post-settings.php | 146 +++++++ includes/mcp/class-convertkit-mcp.php | 27 +- tests/Integration/MCPPostSettingsGetTest.php | 218 +++++++++++ .../Integration/MCPPostSettingsUpdateTest.php | 368 ++++++++++++++++++ wp-convertkit.php | 3 + 7 files changed, 1072 insertions(+), 1 deletion(-) create mode 100644 includes/mcp/abilities/post-settings/class-convertkit-mcp-ability-post-settings-get.php create mode 100644 includes/mcp/abilities/post-settings/class-convertkit-mcp-ability-post-settings-update.php create mode 100644 includes/mcp/abilities/post-settings/class-convertkit-mcp-ability-post-settings.php create mode 100644 tests/Integration/MCPPostSettingsGetTest.php create mode 100644 tests/Integration/MCPPostSettingsUpdateTest.php diff --git a/includes/mcp/abilities/post-settings/class-convertkit-mcp-ability-post-settings-get.php b/includes/mcp/abilities/post-settings/class-convertkit-mcp-ability-post-settings-get.php new file mode 100644 index 000000000..537b5ed2a --- /dev/null +++ b/includes/mcp/abilities/post-settings/class-convertkit-mcp-ability-post-settings-get.php @@ -0,0 +1,139 @@ + 'object', + 'required' => array( 'post_id' ), + 'properties' => array( + 'post_id' => array( + 'type' => 'integer', + 'description' => __( 'The Post/Page/Custom Post Type ID to read Kit settings for.', 'convertkit' ), + 'minimum' => 1, + ), + ), + ); + + } + + /** + * Executes the ability. + * + * @since 3.4.0 + * + * @param array $input Ability input. + * @return array|WP_Error + */ + public function execute_callback( $input ) { + + $post_id = isset( $input['post_id'] ) ? absint( $input['post_id'] ) : 0; + + // Bail if the Post does not exist. + if ( ! get_post( $post_id ) ) { + return new WP_Error( + 'convertkit_mcp_post_not_found', + sprintf( + /* translators: %d: Post ID. */ + __( 'Post %d does not exist.', 'convertkit' ), + $post_id + ) + ); + } + + // Load the Post's settings. + $post_settings = new ConvertKit_Post( $post_id ); + $settings = $post_settings->get(); + + // Cast values to string so they match the output schema (Post storage + // keeps them as strings, but defense-in-depth for numeric coercion). + return array( + 'post_id' => $post_id, + 'form' => (string) $settings['form'], + 'landing_page' => (string) $settings['landing_page'], + 'tag' => (string) $settings['tag'], + 'restrict_content' => (string) $settings['restrict_content'], + ); + + } + +} diff --git a/includes/mcp/abilities/post-settings/class-convertkit-mcp-ability-post-settings-update.php b/includes/mcp/abilities/post-settings/class-convertkit-mcp-ability-post-settings-update.php new file mode 100644 index 000000000..f871549bd --- /dev/null +++ b/includes/mcp/abilities/post-settings/class-convertkit-mcp-ability-post-settings-update.php @@ -0,0 +1,172 @@ + 'object', + 'required' => array( 'post_id' ), + 'properties' => array_merge( + array( + 'post_id' => array( + 'type' => 'integer', + 'description' => __( 'The Post/Page/Custom Post Type ID to update Kit settings for.', 'convertkit' ), + 'minimum' => 1, + ), + ), + $this->get_settings_schema_properties() + ), + ); + + } + + /** + * Executes the ability. + * + * @since 3.4.0 + * + * @param array $input Ability input. + * @return array|WP_Error + */ + public function execute_callback( $input ) { + + $post_id = isset( $input['post_id'] ) ? absint( $input['post_id'] ) : 0; + + // Bail if the Post does not exist. + if ( ! get_post( $post_id ) ) { + return new WP_Error( + 'convertkit_mcp_post_not_found', + sprintf( + /* translators: %d: Post ID. */ + __( 'Post %d does not exist.', 'convertkit' ), + $post_id + ) + ); + } + + // Reject unknown keys. + $properties = $this->get_settings_schema_properties(); + $allowed_keys = array_merge( array( 'post_id' ), array_keys( $properties ) ); + $unknown_keys = array_diff( array_keys( $input ), $allowed_keys ); + if ( ! empty( $unknown_keys ) ) { + return new WP_Error( + 'convertkit_mcp_post_settings_unknown_keys', + sprintf( + /* translators: %s: Comma-separated list of unknown keys. */ + __( 'The following settings keys are not recognised: %s.', 'convertkit' ), + implode( ', ', $unknown_keys ) + ) + ); + } + + // Validate each provided setting against its declared schema. + $validated = array(); + foreach ( $properties as $key => $property_schema ) { + if ( ! array_key_exists( $key, $input ) ) { + continue; + } + + $valid = rest_validate_value_from_schema( $input[ $key ], $property_schema, $key ); + + // Bail if the value is invalid. + if ( is_wp_error( $valid ) ) { + return $valid; + } + + $validated[ $key ] = rest_sanitize_value_from_schema( $input[ $key ], $property_schema, $key ); + } + + // Bail if no settings were provided. + if ( empty( $validated ) ) { + return new WP_Error( + 'convertkit_mcp_post_settings_no_input', + __( 'At least one setting (form, landing_page, tag or restrict_content) must be provided.', 'convertkit' ) + ); + } + + // Merge into the Post's existing settings so this is a partial update. + $post_settings = new ConvertKit_Post( $post_id ); + $merged = array_merge( $post_settings->get(), $validated ); + + // Save. This fires updated_post_meta, which the Restrict Content + // cache class listens for; nothing extra required here. + $post_settings->save( $merged ); + + // Return the post-save state, using the get ability so the shape + // exactly matches kit/post-settings-get. + $get_ability = new ConvertKit_MCP_Ability_Post_Settings_Get(); + return $get_ability->execute_callback( array( 'post_id' => $post_id ) ); + + } + +} diff --git a/includes/mcp/abilities/post-settings/class-convertkit-mcp-ability-post-settings.php b/includes/mcp/abilities/post-settings/class-convertkit-mcp-ability-post-settings.php new file mode 100644 index 000000000..7bb97b249 --- /dev/null +++ b/includes/mcp/abilities/post-settings/class-convertkit-mcp-ability-post-settings.php @@ -0,0 +1,146 @@ +`. + * + * @package ConvertKit + * @author ConvertKit + */ +abstract class ConvertKit_MCP_Ability_Post_Settings extends ConvertKit_MCP_Ability { + + /** + * Returns the operation suffix used in the ability name (e.g. 'get', + * 'update'). + * + * @since 3.4.0 + * + * @return string + */ + abstract protected function get_operation(); + + /** + * Returns the ability name. + * + * @since 3.4.0 + * + * @return string + */ + public function get_name() { + + return 'kit/post-settings-' . $this->get_operation(); + + } + + /** + * Only permit an ability to be executed if the current user can edit + * the given post. + * + * @since 3.4.0 + * + * @param array $input Ability input. + * @return bool|WP_Error + */ + public function permission_callback( $input ) { + + // Get Post ID. + $post_id = isset( $input['post_id'] ) ? absint( $input['post_id'] ) : 0; + + // Bail if no Post ID is provided. + if ( ! $post_id ) { + return new WP_Error( + 'convertkit_mcp_missing_post_id', + __( 'A post_id is required.', 'convertkit' ) + ); + } + + // Bail if the current user does not have permission to edit the post. + if ( ! current_user_can( 'edit_post', $post_id ) ) { + return new WP_Error( + 'convertkit_mcp_cannot_edit_post', + __( 'You do not have permission to edit this post.', 'convertkit' ) + ); + } + + return true; + + } + + /** + * Returns the JSON Schema properties that describe the four Kit post + * settings, shared by both the input and output schemas. + * + * Values are stored by the Plugin as strings (matching what the metabox + * submits), so the schemas expose them as strings with format constraints. + * + * @since 3.4.0 + * + * @return array + */ + protected function get_settings_schema_properties() { + + return array( + 'form' => array( + 'type' => 'string', + 'description' => __( 'Form to display for the Post. `-1` = use the Plugin Default Form for this Post Type; `0` = display no form; any other positive integer is a specific Kit Form ID.', 'convertkit' ), + 'pattern' => '^(-1|0|[1-9][0-9]*)$', + ), + 'landing_page' => array( + 'type' => 'string', + 'description' => __( 'Kit Landing Page ID to display instead of the Post content. Empty string for none.', 'convertkit' ), + 'pattern' => '^([0-9]+)?$', + ), + 'tag' => array( + 'type' => 'string', + 'description' => __( 'Kit Tag ID to apply when the Post is viewed by a Kit subscriber. Empty string for none.', 'convertkit' ), + 'pattern' => '^([0-9]+)?$', + ), + 'restrict_content' => array( + 'type' => 'string', + 'description' => __( 'Restrict Post content to Kit subscribers. Empty string for no restriction, or one of `form_`, `tag_`, `product_` to require subscription to that resource.', 'convertkit' ), + 'pattern' => '^$|^(form|tag|product)_[1-9][0-9]*$', + ), + ); + + } + + /** + * Returns the JSON Schema for the ability's output. + * + * The output shape is the same for get and update: the four settings + * plus the post_id, so a caller can chain update -> confirm without a + * follow-up get. + * + * @since 3.4.0 + * + * @return array + */ + public function get_output_schema() { + + return array( + 'type' => 'object', + 'required' => array( 'post_id', 'form', 'landing_page', 'tag', 'restrict_content' ), + 'properties' => array_merge( + array( + 'post_id' => array( + 'type' => 'integer', + 'description' => __( 'The Post/Page/Custom Post Type ID.', 'convertkit' ), + ), + ), + $this->get_settings_schema_properties() + ), + ); + + } + +} diff --git a/includes/mcp/class-convertkit-mcp.php b/includes/mcp/class-convertkit-mcp.php index df5db04ed..f79ab3be0 100644 --- a/includes/mcp/class-convertkit-mcp.php +++ b/includes/mcp/class-convertkit-mcp.php @@ -66,7 +66,7 @@ class ConvertKit_MCP { */ public static function get_server_url() { - return rest_url( self::SERVER_NAMESPACE . '/' . self::SERVER_ROUTE . '/mcp' ); + return rest_url( self::SERVER_NAMESPACE . '/' . self::SERVER_ROUTE ); } @@ -93,6 +93,12 @@ public function __construct() { // so they're added here rather than via a per-class register_abilities(). add_filter( 'convertkit_abilities', array( $this, 'register_settings_abilities' ) ); + // Register the per-Post Kit settings get / update abilities. These + // operate on the `_wp_convertkit_post_meta` post meta (form, + // landing_page, tag, restrict_content) rather than any Plugin-wide + // settings group. + add_filter( 'convertkit_abilities', array( $this, 'register_post_settings_abilities' ) ); + // Register the MCP server. add_action( 'mcp_adapter_init', array( $this, 'register_mcp_server' ) ); @@ -130,6 +136,25 @@ public function register_settings_abilities( $abilities ) { } + /** + * Appends the per-Post Kit settings abilities to the convertkit_abilities + * filter, so they are registered with the Abilities API and exposed via + * the MCP server. + * + * @since 3.4.0 + * + * @param array $abilities Abilities to register. + * @return array + */ + public function register_post_settings_abilities( $abilities ) { + + $abilities['kit/post-settings-get'] = new ConvertKit_MCP_Ability_Post_Settings_Get(); + $abilities['kit/post-settings-update'] = new ConvertKit_MCP_Ability_Post_Settings_Update(); + + return $abilities; + + } + /** * Appends the resource-list abilities (Forms, Tags, Landing Pages, * Products) to the convertkit_abilities filter, so they are registered diff --git a/tests/Integration/MCPPostSettingsGetTest.php b/tests/Integration/MCPPostSettingsGetTest.php new file mode 100644 index 000000000..9b53696dd --- /dev/null +++ b/tests/Integration/MCPPostSettingsGetTest.php @@ -0,0 +1,218 @@ +assertArrayHasKey(self::ABILITY_NAME, $abilities); + $this->assertInstanceOf(\ConvertKit_MCP_Ability_Post_Settings_Get::class, $abilities[ self::ABILITY_NAME ]); + } + + /** + * Test that permission_callback() rejects an input with no post_id. + * + * @since 3.4.0 + */ + public function testPermissionCallbackRejectsMissingPostId() + { + $abilities = convertkit_get_abilities(); + + $result = $abilities[ self::ABILITY_NAME ]->permission_callback([]); + + $this->assertInstanceOf(\WP_Error::class, $result); + $this->assertSame('convertkit_mcp_missing_post_id', $result->get_error_code()); + } + + /** + * Test that permission_callback() rejects a user who cannot edit the given post. + * + * @since 3.4.0 + */ + public function testPermissionCallbackDeniesWithoutEditPostCapability() + { + // Create a Post by an admin. + $admin_id = static::factory()->user->create([ 'role' => 'administrator' ]); + $post_id = static::factory()->post->create([ 'post_author' => $admin_id ]); + + // Switch to a subscriber. + $subscriber_id = static::factory()->user->create([ 'role' => 'subscriber' ]); + wp_set_current_user($subscriber_id); + + $abilities = convertkit_get_abilities(); + + $result = $abilities[ self::ABILITY_NAME ]->permission_callback([ 'post_id' => $post_id ]); + + $this->assertInstanceOf(\WP_Error::class, $result); + $this->assertSame('convertkit_mcp_cannot_edit_post', $result->get_error_code()); + } + + /** + * Test that get returns the default settings when the Post has no + * Kit post meta stored. + * + * @since 3.4.0 + */ + public function testGetReturnsDefaultsWhenNoMetaExists() + { + $admin_id = static::factory()->user->create([ 'role' => 'administrator' ]); + wp_set_current_user($admin_id); + + $post_id = static::factory()->post->create(); + + $abilities = convertkit_get_abilities(); + + $result = $abilities[ self::ABILITY_NAME ]->execute_callback([ 'post_id' => $post_id ]); + + $this->assertIsArray($result); + $this->assertSame($post_id, $result['post_id']); + $this->assertSame('-1', $result['form']); + $this->assertSame('', $result['landing_page']); + $this->assertSame('', $result['tag']); + $this->assertSame('', $result['restrict_content']); + } + + /** + * Test that get returns the stored Kit settings for a Post that has + * post meta saved. + * + * @since 3.4.0 + */ + public function testGetReturnsStoredSettings() + { + $admin_id = static::factory()->user->create([ 'role' => 'administrator' ]); + wp_set_current_user($admin_id); + + $post_id = static::factory()->post->create(); + + update_post_meta( + $post_id, + '_wp_convertkit_post_meta', + [ + 'form' => '123', + 'landing_page' => '456', + 'tag' => '789', + 'restrict_content' => 'product_101', + ] + ); + + $abilities = convertkit_get_abilities(); + + $result = $abilities[ self::ABILITY_NAME ]->execute_callback([ 'post_id' => $post_id ]); + + $this->assertSame($post_id, $result['post_id']); + $this->assertSame('123', $result['form']); + $this->assertSame('456', $result['landing_page']); + $this->assertSame('789', $result['tag']); + $this->assertSame('product_101', $result['restrict_content']); + } + + /** + * Test that get returns settings for a Page (not just Posts) — confirms + * the ability isn't coupled to any single post type. + * + * @since 3.4.0 + */ + public function testGetWorksForPages() + { + $admin_id = static::factory()->user->create([ 'role' => 'administrator' ]); + wp_set_current_user($admin_id); + + $page_id = static::factory()->post->create([ 'post_type' => 'page' ]); + + update_post_meta( + $page_id, + '_wp_convertkit_post_meta', + [ + 'form' => '0', + 'landing_page' => '999', + 'tag' => '', + 'restrict_content' => '', + ] + ); + + $abilities = convertkit_get_abilities(); + + $result = $abilities[ self::ABILITY_NAME ]->execute_callback([ 'post_id' => $page_id ]); + + $this->assertSame('0', $result['form']); + $this->assertSame('999', $result['landing_page']); + } + + /** + * Test that get returns a WP_Error when the given post_id does not exist. + * + * @since 3.4.0 + */ + public function testGetReturnsErrorForNonExistentPost() + { + $admin_id = static::factory()->user->create([ 'role' => 'administrator' ]); + wp_set_current_user($admin_id); + + $abilities = convertkit_get_abilities(); + + $result = $abilities[ self::ABILITY_NAME ]->execute_callback([ 'post_id' => 999999 ]); + + $this->assertInstanceOf(\WP_Error::class, $result); + $this->assertSame('convertkit_mcp_post_not_found', $result->get_error_code()); + } +} diff --git a/tests/Integration/MCPPostSettingsUpdateTest.php b/tests/Integration/MCPPostSettingsUpdateTest.php new file mode 100644 index 000000000..eb2a72e61 --- /dev/null +++ b/tests/Integration/MCPPostSettingsUpdateTest.php @@ -0,0 +1,368 @@ +assertArrayHasKey(self::ABILITY_NAME, $abilities); + $this->assertInstanceOf(\ConvertKit_MCP_Ability_Post_Settings_Update::class, $abilities[ self::ABILITY_NAME ]); + } + + /** + * Test that update writes all four settings and returns the post-save state. + * + * @since 3.4.0 + */ + public function testUpdateWritesAllFourSettings() + { + $post_id = $this->createPostAsAdmin(); + + $abilities = convertkit_get_abilities(); + + $result = $abilities[ self::ABILITY_NAME ]->execute_callback( + [ + 'post_id' => $post_id, + 'form' => '123', + 'landing_page' => '456', + 'tag' => '789', + 'restrict_content' => 'product_101', + ] + ); + + $this->assertIsArray($result); + $this->assertSame($post_id, $result['post_id']); + $this->assertSame('123', $result['form']); + $this->assertSame('456', $result['landing_page']); + $this->assertSame('789', $result['tag']); + $this->assertSame('product_101', $result['restrict_content']); + + // Confirm persisted to the DB. + $stored = get_post_meta($post_id, '_wp_convertkit_post_meta', true); + $this->assertSame('123', $stored['form']); + $this->assertSame('456', $stored['landing_page']); + $this->assertSame('789', $stored['tag']); + $this->assertSame('product_101', $stored['restrict_content']); + } + + /** + * Test that a partial update writes only the provided keys and preserves + * the other stored settings. + * + * @since 3.4.0 + */ + public function testUpdatePartialUpdatePreservesOtherKeys() + { + $post_id = $this->createPostAsAdmin(); + + // Seed existing settings. + update_post_meta( + $post_id, + '_wp_convertkit_post_meta', + [ + 'form' => '111', + 'landing_page' => '222', + 'tag' => '333', + 'restrict_content' => 'form_444', + ] + ); + + $abilities = convertkit_get_abilities(); + + // Update only the form. + $result = $abilities[ self::ABILITY_NAME ]->execute_callback( + [ + 'post_id' => $post_id, + 'form' => '999', + ] + ); + + $this->assertSame('999', $result['form']); + $this->assertSame('222', $result['landing_page']); + $this->assertSame('333', $result['tag']); + $this->assertSame('form_444', $result['restrict_content']); + } + + /** + * Test that update rejects unknown keys in the input. + * + * @since 3.4.0 + */ + public function testUpdateRejectsUnknownKeys() + { + $post_id = $this->createPostAsAdmin(); + + $abilities = convertkit_get_abilities(); + + $result = $abilities[ self::ABILITY_NAME ]->execute_callback( + [ + 'post_id' => $post_id, + 'form' => '123', + 'not_a_field' => 'garbage', + ] + ); + + $this->assertInstanceOf(\WP_Error::class, $result); + $this->assertSame('convertkit_mcp_post_settings_unknown_keys', $result->get_error_code()); + } + + /** + * Test that update rejects a malformed form value (e.g. `abc`). + * + * @since 3.4.0 + */ + public function testUpdateRejectsInvalidFormValue() + { + $post_id = $this->createPostAsAdmin(); + + $abilities = convertkit_get_abilities(); + + $result = $abilities[ self::ABILITY_NAME ]->execute_callback( + [ + 'post_id' => $post_id, + 'form' => 'abc', + ] + ); + + $this->assertInstanceOf(\WP_Error::class, $result); + } + + /** + * Test that update rejects a malformed restrict_content prefix + * (must be form_, tag_ or product_). + * + * @since 3.4.0 + */ + public function testUpdateRejectsInvalidRestrictContentFormat() + { + $post_id = $this->createPostAsAdmin(); + + $abilities = convertkit_get_abilities(); + + $result = $abilities[ self::ABILITY_NAME ]->execute_callback( + [ + 'post_id' => $post_id, + 'restrict_content' => 'sequence_123', + ] + ); + + $this->assertInstanceOf(\WP_Error::class, $result); + } + + /** + * Test that update rejects a call with only post_id and no settings. + * + * @since 3.4.0 + */ + public function testUpdateRejectsWhenNoSettingsProvided() + { + $post_id = $this->createPostAsAdmin(); + + $abilities = convertkit_get_abilities(); + + $result = $abilities[ self::ABILITY_NAME ]->execute_callback([ 'post_id' => $post_id ]); + + $this->assertInstanceOf(\WP_Error::class, $result); + $this->assertSame('convertkit_mcp_post_settings_no_input', $result->get_error_code()); + } + + /** + * Test that update returns a WP_Error when the given post_id does not exist. + * + * @since 3.4.0 + */ + public function testUpdateReturnsErrorForNonExistentPost() + { + $admin_id = static::factory()->user->create([ 'role' => 'administrator' ]); + wp_set_current_user($admin_id); + + $abilities = convertkit_get_abilities(); + + $result = $abilities[ self::ABILITY_NAME ]->execute_callback( + [ + 'post_id' => 999999, + 'form' => '123', + ] + ); + + $this->assertInstanceOf(\WP_Error::class, $result); + $this->assertSame('convertkit_mcp_post_not_found', $result->get_error_code()); + } + + /** + * Test that update -> get round-trip returns the updated values. + * + * @since 3.4.0 + */ + public function testUpdateThenGetRoundTrip() + { + $post_id = $this->createPostAsAdmin(); + + $abilities = convertkit_get_abilities(); + + $abilities[ self::ABILITY_NAME ]->execute_callback( + [ + 'post_id' => $post_id, + 'form' => '555', + 'tag' => '666', + ] + ); + + $get_result = $abilities['kit/post-settings-get']->execute_callback([ 'post_id' => $post_id ]); + + $this->assertSame('555', $get_result['form']); + $this->assertSame('666', $get_result['tag']); + } + + /** + * Test that setting restrict_content on a published Post populates + * the Restrict Content cache option. Proves integration with the + * ConvertKit_Restrict_Content_Cache class. + * + * @since 3.4.0 + */ + public function testUpdateRestrictContentPopulatesCache() + { + $admin_id = static::factory()->user->create([ 'role' => 'administrator' ]); + wp_set_current_user($admin_id); + + $post_id = static::factory()->post->create( + [ + 'post_type' => 'page', + 'post_status' => 'publish', + ] + ); + + $abilities = convertkit_get_abilities(); + + $abilities[ self::ABILITY_NAME ]->execute_callback( + [ + 'post_id' => $post_id, + 'restrict_content' => 'product_101', + ] + ); + + $cache = get_option(\ConvertKit_Restrict_Content_Cache::OPTION_NAME); + + $this->assertIsArray($cache); + $this->assertArrayHasKey($post_id, $cache); + } + + /** + * Test that clearing restrict_content removes the Post from the + * Restrict Content cache option. + * + * @since 3.4.0 + */ + public function testUpdateClearingRestrictContentRemovesFromCache() + { + $admin_id = static::factory()->user->create([ 'role' => 'administrator' ]); + wp_set_current_user($admin_id); + + $post_id = static::factory()->post->create( + [ + 'post_type' => 'page', + 'post_status' => 'publish', + ] + ); + + $abilities = convertkit_get_abilities(); + + // Enable. + $abilities[ self::ABILITY_NAME ]->execute_callback( + [ + 'post_id' => $post_id, + 'restrict_content' => 'tag_123', + ] + ); + $this->assertArrayHasKey($post_id, get_option(\ConvertKit_Restrict_Content_Cache::OPTION_NAME)); + + // Clear. + $abilities[ self::ABILITY_NAME ]->execute_callback( + [ + 'post_id' => $post_id, + 'restrict_content' => '', + ] + ); + $this->assertArrayNotHasKey($post_id, get_option(\ConvertKit_Restrict_Content_Cache::OPTION_NAME)); + } + + /** + * Helper: creates an administrator user, switches to them, and returns + * a new Post ID. + * + * @since 3.4.0 + * + * @return int + */ + private function createPostAsAdmin() + { + $admin_id = static::factory()->user->create([ 'role' => 'administrator' ]); + wp_set_current_user($admin_id); + + return static::factory()->post->create(); + } +} diff --git a/wp-convertkit.php b/wp-convertkit.php index cd78b8b60..53faac153 100644 --- a/wp-convertkit.php +++ b/wp-convertkit.php @@ -119,6 +119,9 @@ require_once CONVERTKIT_PLUGIN_PATH . '/includes/mcp/abilities/settings/class-convertkit-mcp-ability-settings.php'; require_once CONVERTKIT_PLUGIN_PATH . '/includes/mcp/abilities/settings/class-convertkit-mcp-ability-settings-get.php'; require_once CONVERTKIT_PLUGIN_PATH . '/includes/mcp/abilities/settings/class-convertkit-mcp-ability-settings-update.php'; +require_once CONVERTKIT_PLUGIN_PATH . '/includes/mcp/abilities/post-settings/class-convertkit-mcp-ability-post-settings.php'; +require_once CONVERTKIT_PLUGIN_PATH . '/includes/mcp/abilities/post-settings/class-convertkit-mcp-ability-post-settings-get.php'; +require_once CONVERTKIT_PLUGIN_PATH . '/includes/mcp/abilities/post-settings/class-convertkit-mcp-ability-post-settings-update.php'; require_once CONVERTKIT_PLUGIN_PATH . '/includes/plugin-sidebars/class-convertkit-plugin-sidebar.php'; require_once CONVERTKIT_PLUGIN_PATH . '/includes/plugin-sidebars/class-convertkit-plugin-sidebar-post-settings.php'; require_once CONVERTKIT_PLUGIN_PATH . '/includes/pre-publish-actions/class-convertkit-pre-publish-action.php';