Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 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: minor
Type: added

Agents Manager: Enqueue standalone agents manager app
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ class Agents_Manager {
public function __construct() {
add_action( 'rest_api_init', array( $this, 'register_rest_api' ) );
add_filter( 'calypso_preferences_update', array( $this, 'calypso_preferences_update' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'add_inline_script' ), 101 );
add_action( 'wp_enqueue_scripts', array( $this, 'add_inline_script' ), 101 );
add_action( 'next_admin_init', array( $this, 'add_inline_script' ), 1001 );
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ), 101 );
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ), 101 );
add_action( 'next_admin_init', array( $this, 'enqueue_scripts' ), 1001 );
add_filter( 'agents_manager_use_unified_experience', array( $this, 'should_use_unified_experience' ) );
}

Expand Down Expand Up @@ -142,9 +142,9 @@ public function add_menu_panel( $wp_admin_bar ) {
}

/**
* Add inline script data for the Agents Manager.
* Enqueue Agents Manager scripts and add inline script data.
*/
public function add_inline_script() {
public function enqueue_scripts() {
if ( $this->should_display_menu_panel() ) {
add_action(
'admin_bar_menu',
Expand Down Expand Up @@ -197,11 +197,25 @@ function ( $wp_admin_bar ) {
*/
$use_unified_experience = apply_filters( 'agents_manager_use_unified_experience', false );

// For now, we want this added wherever the help-center script is enqueued.
// This allows us to be quite blunt here because the logic for whether to inject this is currently
// in the help-center script.
$is_block_editor = $this->is_block_editor();

// Enqueue rules:
// - In block editor: enqueue when should_use_big_sky_ui is true (BigSky is available and 'unified-big-sky' flag is not set)
// - Outside block editor: enqueue only when unified experience is enabled.
if ( ( $is_block_editor && $this->should_use_big_sky_ui() ) || ( ! $is_block_editor && ! $use_unified_experience ) ) {
return;
}

if ( $is_block_editor ) {
$variant = 'gutenberg';
} else {
$variant = 'wp-admin';
}

$this->enqueue_script( $variant );

wp_add_inline_script(
'help-center',
'agents-manager',
'const agentsManagerData = ' . wp_json_encode(
array(
'agentProviders' => $agent_providers,
Expand All @@ -213,6 +227,92 @@ function ( $wp_admin_bar ) {
);
}

/**
* Enqueue Agents Manager script based on context.
*
* @param string $variant The variant of the asset file to get.
*/
private function enqueue_script( $variant ) {
$cache_key = 'agents-manager-asset-' . $variant . '.asset.json';
$asset_file = get_transient( $cache_key );

if ( ! $asset_file ) {
$asset_file = self::get_assets_json( 'widgets.wp.com/agents-manager/agents-manager-' . $variant . '.asset.json' );
if ( ! $asset_file ) {
return;
}
set_transient( $cache_key, $asset_file, HOUR_IN_SECONDS );
}

// When the request is proxied, use a random cache buster as the version for easier debugging.
$version = self::is_proxied() ? wp_rand() : $asset_file['version'];

$script_dependencies = $asset_file['dependencies'] ?? array();

wp_enqueue_script(
'agents-manager',
'https://widgets.wp.com/agents-manager/agents-manager-' . $variant . '.min.js',
$script_dependencies,
$version,
true
);

wp_enqueue_style(
'agents-manager-style',
'https://widgets.wp.com/agents-manager/agents-manager-' . $variant . ( is_rtl() ? '.rtl.css' : '.css' ),
array(),
$version
);
}

/**
* Get the asset via file-system on wpcom and via network on Atomic sites.
*
* @param string $filepath The URL to download the asset file from.
* @return array|null The asset file data or null on failure.
*/
private static function get_assets_json( $filepath ) {
$accessible_directly = file_exists( ABSPATH . $filepath );

if ( $accessible_directly ) {
$file_contents = file_get_contents( ABSPATH . $filepath );

if ( false === $file_contents ) {
return null;
}

return json_decode( $file_contents, true );
}

$request = wp_remote_get( 'https://' . $filepath );

if ( is_wp_error( $request ) ) {
return null;
}

$response_code = wp_remote_retrieve_response_code( $request );
if ( 200 !== $response_code ) {
return null;
}

$content_type = wp_remote_retrieve_header( $request, 'content-type' );
if ( is_string( $content_type ) && false === strpos( $content_type, 'json' ) ) {
return null;
}

$body = wp_remote_retrieve_body( $request );
if ( '' === $body ) {
return null;
}

$decoded = json_decode( $body, true );
if ( json_last_error() !== JSON_ERROR_NONE ) {
return null;
}

return $decoded;
}

/**
* Update the calypso preferences.
*
Expand Down Expand Up @@ -415,6 +515,47 @@ private function fetch_unified_experience_preference() {

return $result;
}

/**
* Returns true if the current screen is the block editor.
*
* @return bool True if the current screen is the block editor.
*/
private function is_block_editor() {
if ( ! function_exists( 'get_current_screen' ) ) {
return false;
}

$current_screen = get_current_screen();
// The widgets screen has the block editor but no Gutenberg top bar.
return $current_screen && $current_screen->is_block_editor() && $current_screen->id !== 'widgets';
}

/**
* Determine if the user should use the Big Sky UI.
*
* @return bool True if the user should use the Big Sky UI.
*/
private function should_use_big_sky_ui() {
if ( ! function_exists( 'is_plugin_active' ) ) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}

if ( ! is_plugin_active( 'big-sky-plugin/big-sky.php' ) && ! is_plugin_active( 'big-sky/big-sky.php' ) ) {
return false;
}

// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is a feature flag check, not a form submission.
if ( isset( $_GET['flags'] ) ) {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- This is a feature flag check, not a form submission.
$flags = explode( ',', sanitize_text_field( wp_unslash( $_GET['flags'] ) ) );
if ( in_array( 'unified-big-sky', $flags, true ) ) {
return false;
}
}

return true;
}
}

add_action( 'init', array( __NAMESPACE__ . '\Agents_Manager', 'init' ) );
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ public function tear_down() {
// Remove hooks added by the Agents_Manager constructor.
remove_action( 'rest_api_init', array( $this->agents_manager, 'register_rest_api' ) );
remove_filter( 'calypso_preferences_update', array( $this->agents_manager, 'calypso_preferences_update' ) );
remove_action( 'wp_enqueue_scripts', array( $this->agents_manager, 'add_inline_script' ), 101 );
remove_action( 'admin_enqueue_scripts', array( $this->agents_manager, 'add_inline_script' ), 101 );
remove_action( 'next_admin_init', array( $this->agents_manager, 'add_inline_script' ), 1001 );
remove_action( 'wp_enqueue_scripts', array( $this->agents_manager, 'enqueue_scripts' ), 101 );
remove_action( 'admin_enqueue_scripts', array( $this->agents_manager, 'enqueue_scripts' ), 101 );
remove_action( 'next_admin_init', array( $this->agents_manager, 'enqueue_scripts' ), 1001 );
remove_filter( 'agents_manager_use_unified_experience', array( $this->agents_manager, 'should_use_unified_experience' ) );

// Reset the REST server to clear any registered routes.
Expand Down Expand Up @@ -283,35 +283,44 @@ public function test_init_creates_singleton_instance() {
}

/**
* Tests that add_inline_script adds script with empty providers and useUnifiedExperience false by default.
* Tests that enqueue_scripts adds script with empty providers and useUnifiedExperience false by default.
*/
public function test_add_inline_script_with_empty_providers() {
// Register the help-center script so we can attach inline script to it.
wp_register_script( 'help-center', 'https://example.com/help-center.js', array(), '1.0', true );
public function test_enqueue_scripts_with_empty_providers() {
// Register the agents-manager script so we can attach inline script to it.
wp_register_script( 'agents-manager', 'https://example.com/agents-manager.js', array(), '1.0', true );

$this->agents_manager->add_inline_script();
// Add a filter to enable unified experience.
add_filter(
'agents_manager_use_unified_experience',
'__return_true',
// Use a higher priority to ensure it runs after the class's own filter.
20
);

$this->agents_manager->enqueue_scripts();

global $wp_scripts;
$inline_scripts = $wp_scripts->registered['help-center']->extra['before'] ?? array();
$inline_scripts = $wp_scripts->registered['agents-manager']->extra['before'] ?? array();

// Find the inline script containing agentsManagerData (wp_add_inline_script may add at different indices).
$inline_script = implode( "\n", array_filter( $inline_scripts ) );

$this->assertStringContainsString( 'const agentsManagerData =', $inline_script );
$this->assertStringContainsString( '"agentProviders":[]', $inline_script );
$this->assertStringContainsString( '"useUnifiedExperience":false', $inline_script );

remove_filter( 'agents_manager_use_unified_experience', '__return_true', 20 );
}

/**
* Tests that add_inline_script includes providers added via the filter.
* Tests that enqueue_scripts includes providers added via the filter.
*/
public function test_add_inline_script_includes_filtered_providers() {
public function test_enqueue_scripts_includes_filtered_providers() {
// Reset the script registry to ensure test isolation.
global $wp_scripts;
$wp_scripts = null;

// Register the help-center script so we can attach inline script to it.
wp_register_script( 'help-center', 'https://example.com/help-center.js', array(), '1.0', true );
// Register the agents-manager script so we can attach inline script to it.
wp_register_script( 'agents-manager', 'https://example.com/agents-manager.js', array(), '1.0', true );

// Add a filter to provide agent providers.
add_filter(
Expand All @@ -321,10 +330,18 @@ function () {
}
);

$this->agents_manager->add_inline_script();
// Add a filter to enable unified experience.
add_filter(
'agents_manager_use_unified_experience',
'__return_true',
// Use a higher priority to ensure it runs after the class's own filter.
20
);

$this->agents_manager->enqueue_scripts();

// Re-fetch global after wp_register_script initializes it.
$inline_scripts = $wp_scripts->registered['help-center']->extra['before'] ?? array(); // @phan-suppress-current-line PhanTypeExpectedObjectPropAccessButGotNull
$inline_scripts = $wp_scripts->registered['agents-manager']->extra['before'] ?? array(); // @phan-suppress-current-line PhanTypeExpectedObjectPropAccessButGotNull

// Find the inline script containing agentsManagerData (wp_add_inline_script may add at different indices).
$inline_script = implode( "\n", array_filter( $inline_scripts ) );
Expand All @@ -335,18 +352,19 @@ function () {

// Clean up the filter.
remove_all_filters( 'agents_manager_agent_providers' );
remove_filter( 'agents_manager_use_unified_experience', '__return_true', 20 );
}

/**
* Tests that add_inline_script includes useUnifiedExperience true when filter returns true.
* Tests that enqueue_scripts includes useUnifiedExperience true when filter returns true.
*/
public function test_add_inline_script_includes_use_unified_experience_when_enabled() {
public function test_enqueue_scripts_includes_use_unified_experience_when_enabled() {
// Reset the script registry to ensure test isolation.
global $wp_scripts;
$wp_scripts = null;

// Register the help-center script so we can attach inline script to it.
wp_register_script( 'help-center', 'https://example.com/help-center.js', array(), '1.0', true );
// Register the agents-manager script so we can attach inline script to it.
wp_register_script( 'agents-manager', 'https://example.com/agents-manager.js', array(), '1.0', true );

// Add a filter to enable unified experience.
add_filter(
Expand All @@ -356,10 +374,10 @@ public function test_add_inline_script_includes_use_unified_experience_when_enab
20
);

$this->agents_manager->add_inline_script();
$this->agents_manager->enqueue_scripts();

// Re-fetch global after wp_register_script initializes it.
$inline_scripts = $wp_scripts->registered['help-center']->extra['before'] ?? array(); // @phan-suppress-current-line PhanTypeExpectedObjectPropAccessButGotNull
$inline_scripts = $wp_scripts->registered['agents-manager']->extra['before'] ?? array(); // @phan-suppress-current-line PhanTypeExpectedObjectPropAccessButGotNull

// Find the inline script containing agentsManagerData.
$inline_script = implode( "\n", array_filter( $inline_scripts ) );
Expand Down