Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: patch
Type: fixed

Agents Manager: Allow plugins to enable the agents manager unified experience via filter.
Original file line number Diff line number Diff line change
Expand Up @@ -566,9 +566,10 @@ public function register_rest_api() {
/**
* Determine if user should see unified experience.
*
* @param bool $use_unified_experience Whether to use unified experience.
* @return bool
*/
public function should_use_unified_experience() {
public function should_use_unified_experience( $use_unified_experience = false ) {
// Early return for non-proxied/dev mode requests.
// This feature is currently only available to Automattic employees testing via proxy.
if ( ! self::is_dev_mode() ) {
Expand Down Expand Up @@ -598,9 +599,9 @@ public function should_use_unified_experience() {
return true;
}

// False, for now.
// Default to false, for now.
// In the future: users with a big sky site (similar to https://github.a8c.com/Automattic/wpcom/pull/196449/files), a big-sky free trial or a paid plan.
return false;
return $use_unified_experience;
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Significance: minor
Type: other

Image Studio: Only enable when AI features are available
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@

namespace Automattic\Jetpack\Extensions\ImageStudio;

use Automattic\Jetpack\Connection\Manager as Connection_Manager;
use Automattic\Jetpack\Status;
use Automattic\Jetpack\Status\Host;

if ( ! defined( 'ABSPATH' ) ) {
exit( 0 );
}
Expand All @@ -25,16 +29,43 @@
/**
* Check if Image Studio is enabled.
*
* Returns true if either the unified chat experience or the
* jetpack_image_studio_enabled filter is active.
* Requires AI features (Big Sky or AI Assistant) plus at least one of:
* - The unified chat experience (agents_manager_use_unified_experience).
* - The jetpack_image_studio_enabled filter.
*
* @return bool
*/
function is_image_studio_enabled() {
if ( ! has_ai_features() ) {
return false;
}

return apply_filters( 'agents_manager_use_unified_experience', false )
|| apply_filters( 'jetpack_image_studio_enabled', false );
}

/**
* Check whether AI features are available.
*
* - wpcom simple: always available.
* - Atomic: requires Big Sky or AI Assistant feature flags.
* - Self-hosted: requires a connected owner with AI not disabled
* (same conditions the AI Assistant plugin uses to register).
*
* @return bool
*/
function has_ai_features() {
$host = new Host();

if ( $host->is_wpcom_simple() ) {
return true;
}

return ( new Connection_Manager( 'jetpack' ) )->has_connected_owner()
&& ! ( new Status() )->is_offline_mode()
&& apply_filters( 'jetpack_ai_enabled', true );
}

/**
* Check if the current screen is a block editor (Post Editor or Site Editor).
*
Expand Down Expand Up @@ -332,7 +363,7 @@ function disable_jetpack_ai_image_extensions() {

/**
* Enable the agents manager unified experience on self-hosted sites
* when jetpack_image_studio_enabled is true.
* when Image Studio is enabled with AI capabilities.
*
* This ensures the agents manager loads and can host the headless agent
* even when the unified chat experience is not otherwise enabled.
Expand All @@ -345,7 +376,7 @@ function enable_agents_manager_for_image_studio( $use_unified_experience ) {
return true;
}

return (bool) apply_filters( 'jetpack_image_studio_enabled', false );
return has_ai_features() && (bool) apply_filters( 'jetpack_image_studio_enabled', false );
}
add_filter( 'agents_manager_use_unified_experience', __NAMESPACE__ . '\enable_agents_manager_for_image_studio' );

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use PHPUnit\Framework\Attributes\DataProvider;

require_once JETPACK__PLUGIN_DIR . '/extensions/plugins/image-studio/image-studio.php';
require_once JETPACK__PLUGIN_DIR . '/extensions/plugins/ai-assistant-plugin/ai-assistant-plugin.php';

/**
* Image Studio extension tests.
Expand Down Expand Up @@ -59,6 +60,7 @@ public function set_up() {
$GLOBALS['wp_scripts'] = new WP_Scripts();
$GLOBALS['wp_styles'] = new WP_Styles();
$this->reset_availability();
$this->simulate_connected_owner();
unset( $_GET['enable_image_studio'] );
$this->saved_screen = $GLOBALS['current_screen'] ?? null;
}
Expand All @@ -73,6 +75,8 @@ public function tear_down() {
remove_all_filters( 'agents_manager_agent_providers' );
remove_all_filters( 'pre_http_request' );
remove_all_filters( 'locale' );
remove_all_filters( 'jetpack_ai_enabled' );
( new \Automattic\Jetpack\Connection\Manager( 'jetpack' ) )->reset_connection_status();
unset( $_GET['enable_image_studio'] );
$GLOBALS['current_screen'] = $this->saved_screen;
$GLOBALS['wp_scripts'] = $this->saved_wp_scripts;
Expand All @@ -90,13 +94,33 @@ private function reset_availability() {
$property->setValue( null, array() );
}

/**
* Simulate a connected Jetpack owner so has_ai_features() returns true.
*
* Called in set_up() so every test starts with AI features available.
* Tests that need AI features off should use disable_ai_features() instead.
*/
private function simulate_connected_owner() {
$user_id = self::factory()->user->create( array( 'role' => 'administrator' ) );
\Jetpack_Options::update_option( 'master_user', $user_id );
\Jetpack_Options::update_option( 'user_tokens', array( $user_id => 'token.secret.' . $user_id ) );
( new \Automattic\Jetpack\Connection\Manager( 'jetpack' ) )->reset_connection_status();
}

/**
* Enable Image Studio via jetpack_image_studio_enabled filter.
*/
private function enable_image_studio() {
add_filter( 'jetpack_image_studio_enabled', '__return_true' );
}

/**
* Disable AI features via the jetpack_ai_enabled kill switch.
*/
private function disable_ai_features() {
add_filter( 'jetpack_ai_enabled', '__return_false' );
}

/**
* Disable Image Studio via filter.
*/
Expand Down Expand Up @@ -223,42 +247,94 @@ function () use ( $status_code, $body, $content_type ) {
);
}

// -------------------------------------------------------------------------
// has_ai_features() tests
// -------------------------------------------------------------------------

/**
* AI features available by default in the test environment.
*/
public function test_has_ai_features_true_by_default() {
$this->assertTrue( ImageStudio\has_ai_features() );
}

/**
* AI features disabled via jetpack_ai_enabled kill switch.
*/
public function test_has_ai_features_false_when_ai_disabled() {
$this->disable_ai_features();
$this->assertFalse( ImageStudio\has_ai_features() );
}

// -------------------------------------------------------------------------
// is_image_studio_enabled() tests
// -------------------------------------------------------------------------

/**
* Test is_image_studio_enabled returns true when jetpack_image_studio_enabled is true.
* Enabled when jetpack_image_studio_enabled filter is true and AI features exist.
*/
public function test_is_enabled_via_jetpack_filter() {
$this->enable_image_studio();
$this->assertTrue( ImageStudio\is_image_studio_enabled() );
}

/**
* Test is_image_studio_enabled returns true when unified experience is true.
* Enabled when unified experience is true and AI features exist.
*/
public function test_is_enabled_via_unified_experience() {
$this->enable_unified_experience();
$this->assertTrue( ImageStudio\is_image_studio_enabled() );
}

/**
* Test is_image_studio_enabled returns false when both filters are false.
* Not enabled when neither filter is set.
*/
public function test_is_not_enabled_when_both_filters_false() {
$this->assertFalse( ImageStudio\is_image_studio_enabled() );
}

/**
* Test is_image_studio_enabled returns true when both filters are true.
* Enabled when both filters are true.
*/
public function test_is_enabled_when_both_filters_true() {
$this->enable_image_studio();
$this->enable_unified_experience();
$this->assertTrue( ImageStudio\is_image_studio_enabled() );
}

/**
* AI features alone aren't enough; a filter must also be set.
*/
public function test_is_not_enabled_with_ai_features_but_no_filter() {
$this->assertFalse( ImageStudio\is_image_studio_enabled() );
}

/**
* Enabled via filter with AI features available.
*/
public function test_is_enabled_via_filter_with_ai_features() {
add_filter( 'jetpack_image_studio_enabled', '__return_true' );
$this->assertTrue( ImageStudio\is_image_studio_enabled() );
}

/**
* Unified experience alone isn't enough; AI features must also exist.
*/
public function test_is_not_enabled_via_unified_experience_without_ai_features() {
$this->enable_unified_experience();
$this->disable_ai_features();
$this->assertFalse( ImageStudio\is_image_studio_enabled() );
}

/**
* Filter alone isn't enough; AI features must also exist.
*/
public function test_is_not_enabled_via_filter_without_ai_features() {
add_filter( 'jetpack_image_studio_enabled', '__return_true' );
$this->disable_ai_features();
$this->assertFalse( ImageStudio\is_image_studio_enabled() );
}

// -------------------------------------------------------------------------
// is_block_editor() tests
// -------------------------------------------------------------------------
Expand Down Expand Up @@ -1460,4 +1536,28 @@ public function test_js_url_has_min_css_urls_do_not() {
public function test_asset_transient_constant() {
$this->assertEquals( 'jetpack_image_studio_asset', ImageStudio\ASSET_TRANSIENT );
}

// -------------------------------------------------------------------------
// Hook priority tests
// -------------------------------------------------------------------------

/**
* Disable_jetpack_ai_image_extensions must run after AI extensions register.
*/
public function test_disable_ai_extensions_priority_after_ai_assistant() {
$hook = 'jetpack_register_gutenberg_extensions';

$jp_ai_priority = has_action(
$hook,
'Automattic\Jetpack\Extensions\AiAssistantPlugin\register_plugin'
);
$disable_priority = has_action(
$hook,
'Automattic\Jetpack\Extensions\ImageStudio\disable_jetpack_ai_image_extensions'
);

$this->assertNotFalse( $jp_ai_priority, 'AI Assistant register_plugin should be hooked.' );
$this->assertNotFalse( $disable_priority, 'disable_jetpack_ai_image_extensions should be hooked.' );
$this->assertGreaterThan( $jp_ai_priority, $disable_priority );
}
}
Loading