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
21 changes: 21 additions & 0 deletions src/wp-includes/ai-client.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,27 @@

use WordPress\AiClient\AiClient;

/**
* Returns whether AI features are supported in the current environment.
*
* @since 7.0.0
*/
function wp_supports_ai(): bool {
// Constant check gives a hard short-circuit for environments that cannot be overridden with a filter, such as wp-config.php settings or hosting provider configurations.
if ( defined( 'WP_DISABLE_AI' ) && WP_DISABLE_AI ) {
return false;
}

/**
* Filters whether the current request should use AI.
*
* @since 7.0.0
*
* @param bool $is_enabled Whether the current request should use AI. Default true.
*/
return (bool) apply_filters( 'wp_supports_ai', true );
}

/**
* Creates a new AI prompt builder using the default provider registry.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,11 @@ class WP_AI_Client_Prompt_Builder {
*/
public function __construct( ProviderRegistry $registry, $prompt = null ) {
try {
if ( ! wp_supports_ai() ) {
// The catch block will convert this to a WP_Error.
throw new \RuntimeException( __( 'AI features are not supported in the current environment.' ) );
}

$this->builder = new PromptBuilder( $registry, $prompt );
} catch ( Exception $e ) {
$this->builder = new PromptBuilder( $registry );
Expand Down
6 changes: 5 additions & 1 deletion src/wp-includes/connectors.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
* @access private
*/
function _wp_connectors_add_settings_menu_item(): void {
if ( ! class_exists( '\WordPress\AiClient\AiClient' ) || ! function_exists( 'wp_connectors_wp_admin_render_page' ) ) {
if ( ! wp_supports_ai() || ! class_exists( '\WordPress\AiClient\AiClient' ) || ! function_exists( 'wp_connectors_wp_admin_render_page' ) ) {
return;
}

Expand Down Expand Up @@ -117,6 +117,10 @@ function _wp_connectors_get_real_api_key( string $option_name, callable $mask_ca
* @return array<string, array{provider: string, label: string, description: string, mask: callable, sanitize: callable}> Provider settings keyed by setting name.
*/
function _wp_connectors_get_provider_settings(): array {
if ( ! wp_supports_ai() ) {
return array();
}

$providers = array(
'google' => array(
'name' => 'Google',
Expand Down
19 changes: 19 additions & 0 deletions tests/phpunit/tests/ai-client/wpAiClientPrompt.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,23 @@ public function test_returns_independent_instances() {

$this->assertNotSame( $builder1, $builder2 );
}

/**
* Tests that returns a WP_AI_Client_Prompt_Builder instance even when AI is not supported, but that the builder contains an error.
*/
public function test_returns_error_builder_when_ai_not_supported() {
// Temporarily disable AI support for this test.
add_filter( 'wp_supports_ai', '__return_false' );
$builder = wp_ai_client_prompt();
$this->assertInstanceOf( WP_AI_Client_Prompt_Builder::class, $builder );

// Check the $error prop is a real WP_Error with the expected message.
$reflection = new ReflectionClass( $builder );
$error_prop = $reflection->getProperty( 'error' );
$error_prop->setAccessible( true );
$error = $error_prop->getValue( $builder );

$this->assertInstanceOf( WP_Error::class, $error );
$this->assertSame( 'AI features are not supported in the current environment.', $error->get_error_message() );
}
}
40 changes: 40 additions & 0 deletions tests/phpunit/tests/ai-client/wpSupportsAI.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php
/**
* Tests for wp_supports_ai().
*
* @group ai-client
* @covers ::wp_supports_ai
*/

class Tests_WP_Supports_AI extends WP_UnitTestCase {
/**
* {@inheritDoc}
*/
public function tear_down() {
// Remove the WP_DISABLE_AI constant if it was defined during tests.
remove_all_filters( 'wp_supports_ai' );

parent::tear_down();
}

/**
* Test that wp_supports_ai() defaults to true.
*
* @ticket 64591
*/
public function test_defaults_to_true() {
$this->assertTrue( wp_supports_ai() );
}

/**
* Tests that the wp_supports_ai filter can disable/enable AI features.
*/
public function test_filter_can_disable_ai_features() {
add_filter( 'wp_supports_ai', '__return_false' );
$this->assertFalse( wp_supports_ai() );

// Try a later filter to re-enable AI and confirm that it works.
add_filter( 'wp_supports_ai', '__return_true' );
$this->assertTrue( wp_supports_ai() );
}
}
12 changes: 12 additions & 0 deletions tests/phpunit/tests/connectors/wpConnectorsGetProviderSettings.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,16 @@ public function test_provider_values_match_expected() {
$this->assertSame( 'openai', $settings['connectors_ai_openai_api_key']['provider'] );
$this->assertSame( 'anthropic', $settings['connectors_ai_anthropic_api_key']['provider'] );
}

/**
* Tests providers return an empty array when AI is not supported
*/
public function test_returns_empty_array_when_ai_not_supported() {
// Temporarily disable AI support for this test.
add_filter( 'wp_supports_ai', '__return_false' );

$settings = _wp_connectors_get_provider_settings();
$this->assertIsArray( $settings );
$this->assertEmpty( $settings );
}
}
Loading