Make WordPress Core

Changeset 62288 for trunk


Ignore:
Timestamp:
04/30/2026 12:16:22 PM (8 weeks ago)
Author:
jorgefilipecosta
Message:

Connectors: Add is_active callback support to plugin registration.

Adds an optional is_active callable to the plugin definition accepted by
WP_Connector_Registry::register(). The callback receives no arguments, must
return a boolean, and is used by the Connectors screen to decide whether a
connector's backing plugin is currently active. When omitted, it defaults to
__return_true; when provided but not callable, registration fails with a
_doing_it_wrong() notice.

Developed in: https://github.com/WordPress/wordpress-develop/pull/11565

Props iamadisingh, jorgefilipecosta, mukesh27, gziolo.
Fixes #65020.

Location:
trunk
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp-connector-registry.php

    r62210 r62288  
    4141 *     },
    4242 *     plugin?: array{
    43  *         file: non-empty-string
     43 *         file: non-empty-string,
     44 *         is_active?: callable(): bool
    4445 *     }
    4546 * }
     
    110111     *         Optional. Plugin data for install/activate UI.
    111112     *
    112      *         @type string $file The plugin's main file path relative to the plugins
    113      *                            directory (e.g. 'my-plugin/my-plugin.php' or 'hello.php').
     113     *         @type string   $file      Optional. The plugin's main file path relative to the
     114     *                                   plugins directory (e.g. 'my-plugin/my-plugin.php' or
     115     *                                   'hello.php').
     116     *         @type callable $is_active Optional callback to determine whether the plugin
     117     *                                   is active. Receives no arguments and must return bool.
     118     *                                   Defaults to `__return_true`.
    114119     *     }
    115120     * }
     
    244249        }
    245250
    246         if ( ! empty( $args['plugin'] ) && is_array( $args['plugin'] ) && ! empty( $args['plugin']['file'] ) ) {
    247             $connector['plugin'] = array( 'file' => $args['plugin']['file'] );
     251        $connector['plugin'] = array();
     252
     253        if ( ! empty( $args['plugin'] ) && is_array( $args['plugin'] ) ) {
     254            if ( ! empty( $args['plugin']['file'] ) ) {
     255                $connector['plugin']['file'] = $args['plugin']['file'];
     256            }
     257
     258            if ( isset( $args['plugin']['is_active'] ) ) {
     259                if ( ! is_callable( $args['plugin']['is_active'] ) ) {
     260                    _doing_it_wrong(
     261                        __METHOD__,
     262                        /* translators: %s: Connector ID. */
     263                        sprintf( __( 'Connector "%s" plugin is_active must be callable.' ), esc_html( $id ) ),
     264                        '7.0.0'
     265                    );
     266                    return null;
     267                }
     268
     269                $connector['plugin']['is_active'] = $args['plugin']['is_active'];
     270            }
     271        }
     272
     273        if ( ! isset( $connector['plugin']['is_active'] ) ) {
     274            $connector['plugin']['is_active'] = '__return_true';
    248275        }
    249276
  • trunk/src/wp-includes/connectors.php

    r62210 r62288  
    368368            }
    369369        }
     370
     371        if ( ! isset( $args['plugin']['is_active'] ) ) {
     372            $args['plugin']['is_active'] = static function () use ( $ai_registry, $id ): bool {
     373                try {
     374                    return $ai_registry->hasProvider( $id );
     375                } catch ( Exception $e ) {
     376                    return false;
     377                }
     378            };
     379        }
     380
    370381        $registry->register( $id, $args );
    371382    }
     
    639650    $registry = AiClient::defaultRegistry();
    640651
    641     if ( ! function_exists( 'is_plugin_active' ) ) {
    642         require_once ABSPATH . 'wp-admin/includes/plugin.php';
    643     }
    644 
    645652    $connectors = array();
    646653    foreach ( wp_get_connectors() as $connector_id => $connector_data ) {
     
    675682        if ( ! empty( $connector_data['plugin']['file'] ) ) {
    676683            $file         = $connector_data['plugin']['file'];
    677             $is_installed = file_exists( wp_normalize_path( WP_PLUGIN_DIR . '/' . $file ) );
    678             $is_activated = $is_installed && is_plugin_active( $file );
     684            $is_activated = (bool) call_user_func( $connector_data['plugin']['is_active'] );
     685            $is_installed = $is_activated || file_exists( wp_normalize_path( WP_PLUGIN_DIR . '/' . $file ) );
    679686
    680687            $connector_out['plugin'] = array(
  • trunk/tests/phpunit/tests/connectors/wpConnectorRegistry.php

    r62192 r62288  
    300300
    301301        $this->assertArrayHasKey( 'plugin', $result );
    302         $this->assertSame( array( 'file' => 'my-plugin/my-plugin.php' ), $result['plugin'] );
    303     }
    304 
    305     /**
    306      * @ticket 64791
    307      */
    308     public function test_register_omits_plugin_when_not_provided() {
     302        $this->assertSame( 'my-plugin/my-plugin.php', $result['plugin']['file'] );
     303    }
     304
     305    /**
     306     * @ticket 65020
     307     */
     308    public function test_register_stores_plugin_is_active_callback() {
     309        $args           = self::$default_args;
     310        $args['plugin'] = array(
     311            'file'      => 'my-plugin/my-plugin.php',
     312            'is_active' => '__return_true',
     313        );
     314
     315        $result = $this->registry->register( 'with-callback', $args );
     316
     317        $this->assertIsArray( $result );
     318        $this->assertArrayHasKey( 'is_active', $result['plugin'] );
     319        $this->assertIsCallable( $result['plugin']['is_active'] );
     320    }
     321
     322    /**
     323     * @ticket 65020
     324     */
     325    public function test_register_rejects_non_callable_plugin_is_active() {
     326        $this->setExpectedIncorrectUsage( 'WP_Connector_Registry::register' );
     327
     328        $args           = self::$default_args;
     329        $args['plugin'] = array(
     330            'file'      => 'my-plugin/my-plugin.php',
     331            'is_active' => 'not_a_real_function_name',
     332        );
     333
     334        $result = $this->registry->register( 'bad-callback', $args );
     335
     336        $this->assertNull( $result );
     337    }
     338
     339    /**
     340     * @ticket 65020
     341     */
     342    public function test_register_defaults_plugin_is_active_to_return_true() {
     343        $args           = self::$default_args;
     344        $args['plugin'] = array( 'file' => 'my-plugin/my-plugin.php' );
     345
     346        $result = $this->registry->register( 'default-callback', $args );
     347
     348        $this->assertIsArray( $result );
     349        $this->assertArrayHasKey( 'is_active', $result['plugin'] );
     350        $this->assertSame( '__return_true', $result['plugin']['is_active'] );
     351    }
     352
     353    /**
     354     * @ticket 64791
     355     */
     356    public function test_register_defaults_plugin_when_not_provided() {
    309357        $result = $this->registry->register( 'no-plugin', self::$default_args );
    310358
    311         $this->assertArrayNotHasKey( 'plugin', $result );
     359        $this->assertArrayHasKey( 'plugin', $result );
     360        $this->assertArrayNotHasKey( 'file', $result['plugin'] );
     361        $this->assertSame( '__return_true', $result['plugin']['is_active'] );
    312362    }
    313363
Note: See TracChangeset for help on using the changeset viewer.