From 338ac441774cafc24ca07593028011cdf98f74ce Mon Sep 17 00:00:00 2001 From: Tim Carr Date: Wed, 24 Jun 2026 12:13:34 +0800 Subject: [PATCH 1/2] Abilities API: Plugin Settings: Broadcasts --- ...ss-convertkit-admin-section-broadcasts.php | 4 +- .../class-convertkit-settings-broadcasts.php | 102 ++++++++ includes/mcp/class-convertkit-mcp.php | 1 + .../Integration/MCPSettingsBroadcastsTest.php | 233 ++++++++++++++++++ 4 files changed, 338 insertions(+), 2 deletions(-) create mode 100644 tests/Integration/MCPSettingsBroadcastsTest.php diff --git a/admin/section/class-convertkit-admin-section-broadcasts.php b/admin/section/class-convertkit-admin-section-broadcasts.php index 387c0f7bd..b3e57cbbb 100644 --- a/admin/section/class-convertkit-admin-section-broadcasts.php +++ b/admin/section/class-convertkit-admin-section-broadcasts.php @@ -28,8 +28,8 @@ public function __construct() { $this->settings_key = $this->settings::SETTINGS_NAME; // Define the programmatic name, Title and Tab Text. - $this->name = 'broadcasts'; - $this->title = __( 'Broadcasts', 'convertkit' ); + $this->name = $this->settings->get_name(); + $this->title = $this->settings->get_title(); $this->tab_text = __( 'Broadcasts', 'convertkit' ); // Identify that this is beta functionality. diff --git a/includes/class-convertkit-settings-broadcasts.php b/includes/class-convertkit-settings-broadcasts.php index 9d743a0d2..d0edd87cc 100644 --- a/includes/class-convertkit-settings-broadcasts.php +++ b/includes/class-convertkit-settings-broadcasts.php @@ -190,6 +190,108 @@ public function no_styles() { } + /** + * Returns this settings group's programmatic name. + * + * @since 3.4.0 + * + * @return string + */ + public function get_name() { + + return 'broadcasts'; + + } + + /** + * Returns the title of this settings group. + * + * @since 3.4.0 + * + * @return string + */ + public function get_title() { + + return __( 'Broadcasts Settings', 'convertkit' ); + + } + + /** + * Returns the keys in this settings group that hold credentials or other + * sensitive values. + * + * @since 3.4.0 + * + * @return string[] + */ + public function get_secret_keys() { + + return array(); + + } + + /** + * Returns the JSON Schema describing this settings group, in the shape + * stored by save() / returned by get(), excluding secret keys. + * + * @since 3.4.0 + * + * @return array + */ + public function get_schema() { + + return array( + 'type' => 'object', + 'additionalProperties' => false, + 'properties' => array( + 'enabled' => array( + 'type' => 'string', + 'enum' => array( '', 'on' ), + 'description' => __( 'Whether importing Broadcasts from Kit to WordPress Posts is enabled.', 'convertkit' ), + ), + 'author_id' => array( + 'type' => 'integer', + 'minimum' => 1, + 'description' => __( 'WordPress User ID to assign as the Post author when importing Broadcasts.', 'convertkit' ), + ), + 'post_status' => array( + 'type' => 'string', + 'description' => __( 'WordPress Post status to assign to Posts created from imported Broadcasts (e.g. publish, draft).', 'convertkit' ), + ), + 'category_id' => array( + 'type' => array( 'integer', 'string' ), + 'description' => __( 'WordPress Category ID to assign to Posts created from imported Broadcasts. Blank for none.', 'convertkit' ), + ), + 'import_thumbnail' => array( + 'type' => 'string', + 'enum' => array( '', 'on' ), + 'description' => __( 'Whether to import the Broadcast thumbnail as the Post\'s Featured Image.', 'convertkit' ), + ), + 'import_images' => array( + 'type' => 'string', + 'enum' => array( '', 'on' ), + 'description' => __( 'Whether to import images referenced in the Broadcast\'s content into the WordPress Media Library.', 'convertkit' ), + ), + 'published_at_min_date' => array( + 'type' => 'string', + 'format' => 'date', + 'description' => __( 'Earliest published_at date (YYYY-MM-DD) of Broadcasts to import.', 'convertkit' ), + ), + 'enabled_export' => array( + 'type' => 'string', + 'enum' => array( '', 'on' ), + 'description' => __( 'Whether exporting WordPress Posts to Kit Broadcasts is enabled.', 'convertkit' ), + ), + 'no_styles' => array( + 'type' => 'string', + 'enum' => array( '', 'on' ), + 'description' => __( 'Whether inline styles on imported Broadcast content should be stripped.', 'convertkit' ), + ), + ), + ); + + } + /** * The default settings, used when the ConvertKit Broadcasts Settings haven't been saved * e.g. on a new installation. diff --git a/includes/mcp/class-convertkit-mcp.php b/includes/mcp/class-convertkit-mcp.php index 5a736a38f..a20e0009a 100644 --- a/includes/mcp/class-convertkit-mcp.php +++ b/includes/mcp/class-convertkit-mcp.php @@ -100,6 +100,7 @@ public function register_settings_abilities( $abilities ) { // Settings instances to register with MCP. $groups = array( new ConvertKit_Settings(), + new ConvertKit_Settings_Broadcasts(), ); // Iterate through settings groups, registering the get and update abilities. diff --git a/tests/Integration/MCPSettingsBroadcastsTest.php b/tests/Integration/MCPSettingsBroadcastsTest.php new file mode 100644 index 000000000..6e17dd885 --- /dev/null +++ b/tests/Integration/MCPSettingsBroadcastsTest.php @@ -0,0 +1,233 @@ + \ConvertKit_MCP_Ability_Settings_Get::class, + 'kit/settings-broadcasts-update' => \ConvertKit_MCP_Ability_Settings_Update::class, + ); + + // Assert that the abilities are registered and are instances of the expected classes. + foreach ( $expected as $name => $class ) { + $this->assertArrayHasKey($name, $abilities); + $this->assertInstanceOf($class, $abilities[ $name ]); + } + } + + /** + * Test that the permission_callback() rejects a user who cannot manage options. + * + * @since 3.4.0 + */ + public function testPermissionCallbackDeniesWithoutManageOptionsCapability() + { + // Become a Subscriber (no manage_options capability). + $subscriber_id = static::factory()->user->create([ 'role' => 'subscriber' ]); + wp_set_current_user($subscriber_id); + + // Resolve the abilities array via the same helper the MCP server uses. + $abilities = convertkit_get_abilities(); + + // Assert that the abilities are permission denied. + foreach ( self::ABILITY_NAMES as $name ) { + // Execute the ability. + $result = $abilities[ $name ]->permission_callback([]); + + // Assert that the result is a WP_Error. + $this->assertInstanceOf(\WP_Error::class, $result); + } + } + + /** + * Test that kit/settings-broadcasts-get returns the current settings. + * + * @since 3.4.0 + */ + public function testGetSettings() + { + // Populate settings. + $this->populateSettings(); + + // Resolve the abilities array via the same helper the MCP server uses. + $abilities = convertkit_get_abilities(); + + // Execute the ability. + $result = $abilities['kit/settings-broadcasts-get']->execute_callback([]); + + // Confirm expected settings are returned. + $this->assertArrayHasKey('enabled', $result); + $this->assertEquals('on', $result['enabled']); + $this->assertArrayHasKey('author_id', $result); + $this->assertArrayHasKey('post_status', $result); + $this->assertEquals('draft', $result['post_status']); + $this->assertArrayHasKey('category_id', $result); + $this->assertArrayHasKey('import_thumbnail', $result); + $this->assertArrayHasKey('import_images', $result); + $this->assertArrayHasKey('published_at_min_date', $result); + $this->assertArrayHasKey('enabled_export', $result); + $this->assertArrayHasKey('no_styles', $result); + } + + /** + * Test that kit/settings-broadcasts-update updates the settings. + * + * @since 3.4.0 + */ + public function testUpdateSettings() + { + // Resolve the abilities array via the same helper the MCP server uses. + $abilities = convertkit_get_abilities(); + + // Execute the ability. + $result = $abilities['kit/settings-broadcasts-update']->execute_callback( + [ + 'enabled' => 'on', + 'post_status' => 'draft', + 'import_thumbnail' => '', + 'import_images' => 'on', + 'enabled_export' => 'on', + 'no_styles' => 'on', + ] + ); + + // Confirm expected settings are returned. + $this->assertArrayHasKey('enabled', $result); + $this->assertArrayHasKey('author_id', $result); + $this->assertArrayHasKey('post_status', $result); + $this->assertArrayHasKey('category_id', $result); + $this->assertArrayHasKey('import_thumbnail', $result); + $this->assertArrayHasKey('import_images', $result); + $this->assertArrayHasKey('published_at_min_date', $result); + $this->assertArrayHasKey('enabled_export', $result); + $this->assertArrayHasKey('no_styles', $result); + + // Confirm settings are updated. + $this->assertEquals('on', $result['enabled']); + $this->assertEquals('draft', $result['post_status']); + $this->assertEquals('', $result['import_thumbnail']); + $this->assertEquals('on', $result['import_images']); + $this->assertEquals('on', $result['enabled_export']); + $this->assertEquals('on', $result['no_styles']); + } + + /** + * Test that kit/settings-broadcasts-update returns an error if an invalid key is provided. + * + * @since 3.4.0 + */ + public function testUpdateSettingsWithInvalidKeyReturnsError() + { + // Resolve the abilities array via the same helper the MCP server uses. + $abilities = convertkit_get_abilities(); + + // Execute the ability. + $result = $abilities['kit/settings-broadcasts-update']->execute_callback([ 'invalid_key' => 'invalid_value' ]); + } + + /** + * Populate the settings with some sensible values for testing. + * + * @since 3.4.0 + */ + private function populateSettings() + { + update_option( + self::SETTINGS_NAME, + [ + 'enabled' => 'on', + 'author_id' => 1, + 'post_status' => 'draft', + 'category_id' => '', + 'import_thumbnail' => 'on', + 'import_images' => '', + 'published_at_min_date' => gmdate( 'Y-m-d', strtotime( '-30 days' ) ), + 'enabled_export' => '', + 'no_styles' => '', + ] + ); + } +} \ No newline at end of file From a57cddf35eb2d31cae65b1985ca228f3f0cd7708 Mon Sep 17 00:00:00 2001 From: Tim Carr Date: Wed, 24 Jun 2026 12:52:23 +0800 Subject: [PATCH 2/2] Coding standards --- tests/Integration/MCPSettingsBroadcastsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Integration/MCPSettingsBroadcastsTest.php b/tests/Integration/MCPSettingsBroadcastsTest.php index 6e17dd885..d00089f59 100644 --- a/tests/Integration/MCPSettingsBroadcastsTest.php +++ b/tests/Integration/MCPSettingsBroadcastsTest.php @@ -230,4 +230,4 @@ private function populateSettings() ] ); } -} \ No newline at end of file +}