Make WordPress Core

Opened 4 months ago

Closed 3 months ago

#65020 closed defect (bug) (fixed)

Connectors: Support custom plugin is_active callback in connector registry and plugin status output

Reported by: iamadisingh Owned by: jorgefilipecosta
Priority: normal Milestone: 7.0
Component: AI Version: 7.0
Severity: normal Keywords: connectors has-patch has-unit-tests fixed-major dev-reviewed
Cc: Focuses:

Description

This changeset backports connector improvements from Gutenberg to Core:

  • Extend connector plugin metadata to support optional plugin.is_active callback.
  • Validate plugin.is_active as callable during WP_Connector_Registry::register().
  • Use plugin.is_active callback when building connector script-module data, with fallback to file_exists + is_plugin_active.
  • Update default Akismet connector to use a robust activity check: defined( AKISMET_VERSION ) && class_exists( Akismet, false ).

Some plugins (especially MU-loaded or non-standard load paths) cannot be reliably detected via is_plugin_active(file) alone. Allowing an explicit activity callback provides accurate activation state in connectors UI.

Change History (32)

#1 @gaisma22
4 months ago

  • Keywords dev-feedback added; needs-testing has-patch removed

No patch file or PR is attached to this ticket. The description contains code snippets but nothing that can be applied or tested. Removing has-patch and needs-testing. Adding dev-feedback as the changes need review from a developer with commit access first.

This ticket was mentioned in Slack in #core-test by gaisma22. View the logs.


4 months ago

#3 @JeffPaul
4 months ago

  • Keywords connectors added

This ticket was mentioned in Slack in #core-ai by jorgefilipecosta. View the logs.


4 months ago

This ticket was mentioned in PR #11565 on WordPress/wordpress-develop by @iamadisingh.


4 months ago
#5

  • Keywords has-patch added

Backport of wordpress/gutenberg#76994. Adds an optional is_active callable to the plugin definition when
registering a connector via WP_Connector_Registry::register().

The Connectors screen previously resolved a connector's active/installed status by checking is_plugin_active() and file_exists() against WP_PLUGIN_DIR only. Plugins installed as must-use plugins — or loaded from non-standard paths could not be detected this way, causing theirconnectors to disappear from the screen even though the plugin was in use.

Trac ticket: https://core.trac.wordpress.org/ticket/65020

@iamadisingh commented on PR #11565:


4 months ago
#6

This PR has been updated to also address https://core.trac.wordpress.org/ticket/65099.

#7 @JeffPaul
4 months ago

@jorgefilipecosta @gziolo this looks ready for your review

@iamadisingh commented on PR #11565:


4 months ago
#8

This PR has been updated to also address https://core.trac.wordpress.org/ticket/65099.

@gziolo commented on PR #11565:


4 months ago
#10

Some additional feedback to evaluate. The rest looks good to me. I would appreciate confirmation from @jorgefilipecosta, too.

@jorgefilipecosta commented on PR #11565:


4 months ago
#11

Hi @gziolo I pushed a commit addressing your feedback and passing an is_active callback for the ai providers.

#12 @gziolo
4 months ago

  • Keywords commit added; dev-feedback removed

All good on my end. I verified the changes. You can proceed further.

#13 @jorgefilipecosta
4 months ago

  • Owner set to jorgefilipecosta
  • Resolutionfixed
  • Status newclosed

In 62288:

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.

#14 @wildworks
3 months ago

Is [62288] intended to be backported to 7.0? If so, let's reopen this ticket.

By the way, I discovered an issue on the Gutenberg plugin side where all default connectors are unintentionally considered "active" because the default connector does not have an is_active callback added. This should be fixed in https://github.com/WordPress/gutenberg/pull/77897.

This ticket was mentioned in PR #11701 on WordPress/wordpress-develop by @wildworks.


3 months ago
#15

  • Keywords has-unit-tests added

This PR backports the changes from Gutenberg to the core: https://github.com/WordPress/gutenberg/pull/77897

Trac ticket: https://core.trac.wordpress.org/ticket/65020

## Use of AI Tools

None

#16 @JeffPaul
3 months ago

  • Keywords dev-feedback fixed-major added
  • Resolution fixed
  • Status closedreopened

Reopening for merge to the 7.0 branch pending committer sign off.

@westonruter commented on PR #11701:


3 months ago
#17

See feedback from @jorgefilipecosta at https://github.com/WordPress/gutenberg/pull/77897/changes#r3183140237 and https://github.com/WordPress/gutenberg/pull/77897/changes#r3189900673

If is_active is always then set among the \WP_Connector_Registry::$registered_connectors, then the Connector type modified in https://github.com/WordPress/wordpress-develop/commit/b3b40be9c3fda7d731c4275c25a22722196f0804 should be updated as follows:

  • src/wp-includes/class-wp-connector-registry.php

    diff --git a/src/wp-includes/class-wp-connector-registry.php b/src/wp-includes/class-wp-connector-registry.php
    index fbf35ad73e..4fd451b2b0 100644
    a b  
    4141 *     },
    4242 *     plugin?: array{
    4343 *         file: non-empty-string,
    44  *         is_active?: callable(): bool
     44 *         is_active: callable(): bool
    4545 *     }
    4646 * }
    4747 */

@wildworks commented on PR #11701:


3 months ago
#18

Based on the feedback in Gutenberg, I have updated this PR. Ultimately, this PR only leaves minor code quality improvements 😄

#19 @desrosj
3 months ago

  • Keywords dev-reviewed added; dev-feedback removed

[62288] looks good for backporting.

#20 @desrosj
3 months ago

  • Resolutionfixed
  • Status reopenedclosed

In 62309:

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

Reviewed by desrosj.
Merges [62288] to the 7.0 branch.

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

#21 @desrosj
3 months ago

  • Keywords commit fixed-major dev-reviewed removed
  • Milestone Awaiting Review7.0
  • Resolution fixed
  • Status closedreopened

Reopening to consider the remaining feedback.

@westonruter commented on PR #11701:


3 months ago
#22

This was not committed yet.

@westonruter commented on PR #11701:


3 months ago
#23

I found several PHPStan issues at rule level 10 when looking at src/wp-includes/class-wp-connector-registry.php and src/wp-includes/connectors.php:

 ------ ----------------------------------------------------------------------- 
  Line   connectors.php                                                         
 ------ ----------------------------------------------------------------------- 
  88     Function wp_get_connector() should return array{name:                  
         non-empty-string, description: non-empty-string, logo_url?:            
         non-empty-string, type: non-empty-string, authentication:              
         array{method: 'api_key'|'none', credentials_url?: non-empty-string,    
         setting_name?: non-empty-string, constant_name?: non-empty-string,     
         env_var_name?: non-empty-string}, plugin?: array{file:                 
         non-empty-string}}|null but returns array{name: non-empty-string,      
         description: non-empty-string, logo_url?: non-empty-string, type:      
         non-empty-string, authentication: array{method: 'api_key'|'none',      
         credentials_url?: non-empty-string, setting_name?: non-empty-string,   
         constant_name?: non-empty-string, env_var_name?: non-empty-string},    
         plugin: array{file?: non-empty-string, is_active: callable():          
         bool}}|null.                                                           
         🪪  return.type                                                        
         💡  Type #1 from the union: Offset 'plugin' (array{file:               
         non-empty-string}) does not accept type array{file?:                   
         non-empty-string, is_active: callable(): bool}: Array might not have   
         offset 'file'.                                                         
         at src/wp-includes/connectors.php:88                                   
  150    Function wp_get_connectors() should return array<string, array{name:   
         non-empty-string, description: non-empty-string, logo_url?:            
         non-empty-string, type: non-empty-string, authentication:              
         array{method: 'api_key'|'none', credentials_url?: non-empty-string,    
         setting_name?: non-empty-string, constant_name?: non-empty-string,     
         env_var_name?: non-empty-string}, plugin?: array{file:                 
         non-empty-string}}> but returns array<string, array{name: non-empty-s  
         tring, description: non-empty-string, logo_url?: non-empty-string,     
         type: non-empty-string, authentication: array{method:                  
         'api_key'|'none', credentials_url?: non-empty-string, setting_name?:   
         non-empty-string, constant_name?: non-empty-string, env_var_name?:     
         non-empty-string}, plugin: array{file?: non-empty-string, is_active:   
         callable(): bool}}>.                                                   
         🪪  return.type                                                        
         💡  Offset 'plugin' (array{file: non-empty-string}) does not accept    
         type array{file?: non-empty-string, is_active: callable(): bool}:      
         Array might not have offset 'file'.                                    
         at src/wp-includes/connectors.php:150                                  
  353    Offset 'setting_name' on array{method: 'api_key'|'none',               
         credentials_url?: mixed} in isset() does not exist.                    
         🪪  isset.offset                                                       
         at src/wp-includes/connectors.php:353                                  
  358    Offset 'constant_name' on array{method: 'api_key'|'none',              
         credentials_url?: mixed, setting_name: non-falsy-string} in isset()    
         does not exist.                                                        
         🪪  isset.offset                                                       
         at src/wp-includes/connectors.php:358                                  
  358    Offset 'env_var_name' on *NEVER* in isset() always exists and is not   
         nullable.                                                              
         🪪  isset.offset                                                       
         at src/wp-includes/connectors.php:358                                  
  358    Result of || is always true.                                           
         🪪  booleanOr.alwaysTrue                                               
         at src/wp-includes/connectors.php:358                                  
  359    Parameter #1 $str of function strtoupper expects string, string|null   
         given.                                                                 
         🪪  argument.type                                                      
         at src/wp-includes/connectors.php:359                                  
  361    Offset 'constant_name' on array{method: 'api_key'|'none',              
         credentials_url?: mixed, setting_name: non-falsy-string} in isset()    
         does not exist.                                                        
         🪪  isset.offset                                                       
         at src/wp-includes/connectors.php:361                                  
  365    Offset 'env_var_name' on array{method: 'api_key'|'none',               
         credentials_url?: mixed, setting_name: non-falsy-string,               
         constant_name: non-falsy-string} in isset() does not exist.            
         🪪  isset.offset                                                       
         at src/wp-includes/connectors.php:365                                  
  371    Offset 'is_active' on array{file: 'ai-provider-for…'} in isset() does  
         not exist.                                                             
         🪪  isset.offset                                                       
         at src/wp-includes/connectors.php:371                                  
  381    Parameter #2 $args of method WP_Connector_Registry::register()         
         expects array{name: non-empty-string, description: non-empty-string,   
         logo_url?: non-empty-string, type: non-empty-string, authentication:   
         array{method: 'api_key'|'none', credentials_url?: non-empty-string,    
         setting_name?: non-empty-string, constant_name?: non-empty-string,     
         env_var_name?: non-empty-string}, plugin: array{file?:                 
         non-empty-string, is_active: callable(): bool}}, array{name: string,   
         description: string, type: 'ai_provider', plugin: array{file?:         
         'ai-provider-for…', is_active: Closure(): bool}, authentication:       
         array{method: 'api_key', credentials_url?: non-falsy-string|null,      
         setting_name: non-falsy-string, constant_name: non-falsy-string,       
         env_var_name: non-falsy-string}|array{method: 'none',                  
         credentials_url?: non-falsy-string|null}, logo_url?: string|null}      
         given.                                                                 
         🪪  argument.type                                                      
         💡  Offset 'name' (non-empty-string) does not accept type string.      
         💡  Offset 'description' (non-empty-string) does not accept type       
         string.                                                                
         💡  Offset 'logo_url' (non-empty-string) does not accept type          
         string|null.                                                           
         💡  Offset 'authentication' (array{method: 'api_key'|'none',           
         credentials_url?: non-empty-string, setting_name?: non-empty-string,   
         constant_name?: non-empty-string, env_var_name?: non-empty-string})    
         does not accept type array{method: 'api_key', credentials_url?:        
         non-falsy-string|null, setting_name: non-falsy-string, constant_name:  
         non-falsy-string, env_var_name: non-falsy-string}|array{method:        
         'none', credentials_url?: non-falsy-string|null}: Offset               
         'credentials_url' (non-empty-string) does not accept type              
         non-falsy-string|null.                                                 
         at src/wp-includes/connectors.php:381                                  
  581    Parameter #2 ...$values of function sprintf expects                    
         bool|float|int|string|null, mixed given.                               
         🪪  argument.type                                                      
         at src/wp-includes/connectors.php:581                                  
  586    Parameter #2 ...$values of function sprintf expects                    
         bool|float|int|string|null, mixed given.                               
         🪪  argument.type                                                      
         at src/wp-includes/connectors.php:586                                  
  633    Parameter #1 $apiKey of class                                          
         WordPress\AiClient\Providers\Http\DTO\ApiKeyRequestAuthentication      
         constructor expects string, mixed given.                               
         🪪  argument.type                                                      
         at src/wp-includes/connectors.php:633                                  
  690    Offset 'is_active' does not exist on array{file: non-falsy-string}.    
         🪪  offsetAccess.notFound                                              
         at src/wp-includes/connectors.php:690                                  
  690    Parameter #1 $function of function call_user_func expects callable():  
         mixed, mixed given.                                                    
         🪪  argument.type                                                      
         at src/wp-includes/connectors.php:690                                  
 ------ ----------------------------------------------------------------------- 


 [ERROR] Found 16 errors                                                        

I've fixed these in e15d15557e by amending this PR.

@westonruter commented on PR #11701:


3 months ago
#24

For reference, the command I used to obtain the above PHPStan errors:

composer phpstan -- --configuration=phpstan.neon.dist --level=10 src/wp-includes/class-wp-connector-registry.php src/wp-includes/connectors.php

@wildworks commented on PR #11701:


3 months ago
#25

@westonruter Thank you for the additional improvements! Let's change the PR title to reflect the actual code changes. After this PR is merged, I'd like to backport the improved PHPStan issues to Gutenberg.

#26 @wildworks
3 months ago

In 62332:

Connectors: Refine plugin install check and PHPStan types.

Replace file_exists() with validate_plugin() in the connectors script module data, and refine PHPStan type definitions in the connectors code to better reflect the actual shape of registered connector data.

Follow-up to [62288].

Props jorgefilipecosta, mukesh27, peterwilsoncc, westonruter, wildworks.
See #65020.

#27 @wildworks
3 months ago

  • Keywords dev-feedback added

Requesting another committer's sign-off to backport [62332] to 7.0.

Last edited 3 months ago by wildworks (previous) (diff)

#28 @desrosj
3 months ago

  • Keywords fixed-major added

Adding fixed-major so it shows up in the correct group for reports organized by workflow (such as tickets/major/workflow.

#29 @ellatrix
3 months ago

  • Keywords dev-reviewed added; dev-feedback removed

I don't know much about the Connectors code, but this was reviewed by both @westonruter and @jorgefilipecosta, and created by Aki, who are all committers, so I'll backport this to the 7.0 branch.

@wildworks commented on PR #11701:


3 months ago
#30

This PR was committed in r62332

#31 @ellatrix
3 months ago

In 62336:

Connectors: Refine plugin install check and PHPStan types.

Replace file_exists() with validate_plugin() in the connectors script module data, and refine PHPStan type definitions in the connectors code to better reflect the actual shape of registered connector data.

Follow-up to [62288].

Reviewed by ellatrix.
Merges [62332] to the 7.0 branch.

Props jorgefilipecosta, mukesh27, peterwilsoncc, westonruter, wildworks.
See #65020.

#32 @wildworks
3 months ago

  • Resolutionfixed
  • Status reopenedclosed

Since PR 11701 was committed to both trunk and 7.0, I think this ticket can be closed again.

Note: See TracTickets for help on using tickets.