feat!: Refactor Experiments to be a type of Feature#316
Conversation
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
There was a problem hiding this comment.
Pull request overview
Refactors the plugin’s “Experiments” system into a broader “Features” system by introducing a Features namespace (contract, registry, loader, categories) and registering existing experiments as feature implementations, with backward-compat hooks intended to remain deprecated until v1.0.
Changes:
- Introduces
WordPress\AI\Contracts\Feature+Abstract_Feature, plusFeatures\RegistryandFeatures\Loaderto replace the prior experiment registry/loader. - Adds
Experiments\Experimentsto register experiment classes via the newwpai_default_feature_classesfilter, and movesExperiment_Categoryinto theExperimentsnamespace (built onFeatures\Feature_Category). - Updates settings wiring and test suite/e2e helpers to use new option keys and registration/initialization entrypoints.
Reviewed changes
Copilot reviewed 53 out of 53 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/e2e/utils/helpers.ts | Updates E2E selectors to new wpai_feature_{id}_enabled option IDs. |
| tests/Integration/Includes/HelpersTest.php | Adjusts test closures (static) and filter behavior for updated helpers. |
| tests/Integration/Includes/Features/Feature_CategoryTest.php | Adds integration test for Feature_Category::OTHER. |
| tests/Integration/Includes/Experiments/Title_Generation/Title_GenerationTest.php | Migrates experiment tests to Features\Loader/Registry and new option keys. |
| tests/Integration/Includes/Experiments/Summarization/SummarizationTest.php | Migrates experiment tests to Features\Loader/Registry and new option keys. |
| tests/Integration/Includes/Experiments/Review_Notes/Review_NotesTest.php | Migrates experiment tests to Features\Loader/Registry and new option keys. |
| tests/Integration/Includes/Experiments/Image_Generation/Image_GenerationTest.php | Migrates experiment tests to Features\Loader/Registry and new option keys. |
| tests/Integration/Includes/Experiments/ExperimentsTest.php | Adds test asserting experiments register via wpai_default_feature_classes. |
| tests/Integration/Includes/Experiments/Excerpt_Generation/Excerpt_GenerationTest.php | Migrates experiment tests and updates enable/disable filter hook. |
| tests/Integration/Includes/Experiments/Example_Experiment/Example_ExperimentTest.php | Migrates example experiment test to feature registry/loader APIs. |
| tests/Integration/Includes/Experiments/Alt_Text_Generation/Alt_Text_GenerationTest.php | Migrates experiment tests and updates enable/disable filter hook. |
| tests/Integration/Includes/Experiments/Abilities_Explorer/Admin_PageTest.php | Updates phpdoc types for renamed namespaces/classes. |
| tests/Integration/Includes/Experiments/Abilities_Explorer/Abilities_ExplorerTest.php | Migrates Abilities Explorer tests to feature registry/loader APIs. |
| tests/Integration/Includes/Experiment_RegistryTest.php | Refactors registry tests to new Features\Registry and Abstract_Feature. |
| tests/Integration/Includes/Experiment_LoaderTest.php | Refactors loader tests to new Features\Loader and new hooks. |
| tests/Integration/Includes/Abstracts/Abstract_ExperimentTest.php | Refactors abstract base tests to Abstract_Feature and adds stability tests. |
| tests/Integration/Includes/Abstracts/Abstract_AbilityTest.php | Updates ability test experiment implementation to Abstract_Feature. |
| tests/Integration/Includes/Abilities/Title_GenerationTest.php | Updates ability tests’ feature wrapper from Abstract_Experiment to Abstract_Feature. |
| tests/Integration/Includes/Abilities/SummarizationTest.php | Updates ability tests’ feature wrapper and phpdoc types. |
| tests/Integration/Includes/Abilities/Review_NotesTest.php | Updates ability tests’ feature wrapper and metadata loading method name. |
| tests/Integration/Includes/Abilities/Image_Prompt_GenerationTest.php | Updates ability tests’ feature wrapper and metadata loading method name. |
| tests/Integration/Includes/Abilities/Image_ImportTest.php | Updates ability tests’ feature wrapper and minor formatting tweaks. |
| tests/Integration/Includes/Abilities/Image_GenerationTest.php | Updates ability tests’ feature wrapper and minor formatting tweaks. |
| tests/Integration/Includes/Abilities/Excerpt_GenerationTest.php | Updates ability tests’ feature wrapper and metadata loading method name. |
| tests/Integration/Includes/Abilities/Alt_Text_GenerationTest.php | Updates ability tests’ feature wrapper and replaces __FILE__ with __DIR__. |
| phpcs.xml.dist | Updates global prefix rules for constants, namespace, and wpai_ prefix. |
| includes/bootstrap.php | Switches initialization to initialize_features() and wires Features\Loader/Registry plus experiments registration. |
| includes/Settings/Settings_Registration.php | Migrates settings registration to Features\Registry and new option keys. |
| includes/Settings/Settings_Page.php | Renders per-feature toggles using new option keys and feature registry. |
| includes/Features/Registry.php | Adds new feature registry (replaces old experiment registry). |
| includes/Features/Loader.php | Adds new loader for registering/initializing features and new hooks. |
| includes/Features/Feature_Category.php | Adds feature category constants (currently OTHER). |
| includes/Experiments/Title_Generation/Title_Generation.php | Converts experiment class to extend Abstract_Feature with static get_id(). |
| includes/Experiments/Summarization/Summarization.php | Converts experiment class to extend Abstract_Feature with static get_id(). |
| includes/Experiments/Review_Notes/Review_Notes.php | Converts experiment class to extend Abstract_Feature with static get_id(). |
| includes/Experiments/Image_Generation/Image_Generation.php | Converts experiment class to extend Abstract_Feature with static get_id(). |
| includes/Experiments/Experiments.php | New registration class that injects experiment classes into default feature classes. |
| includes/Experiments/Experiment_Category.php | Moves experiment categories under Experiments and inherits Feature_Category. |
| includes/Experiments/Excerpt_Generation/Excerpt_Generation.php | Converts experiment class to extend Abstract_Feature with static get_id(). |
| includes/Experiments/Example_Experiment/README.md | Updates docs to reference Abstract_Feature and new enable/disable hooks. |
| includes/Experiments/Example_Experiment/Example_Experiment.php | Converts example experiment to extend Abstract_Feature with static get_id(). |
| includes/Experiments/Alt_Text_Generation/Alt_Text_Generation.php | Converts experiment class to extend Abstract_Feature with static get_id() and updates ability registration path. |
| includes/Experiments/Abilities_Explorer/Abilities_Explorer.php | Converts experiment class to extend Abstract_Feature with static get_id(). |
| includes/Experiment_Registry.php | Removes old experiment registry implementation. |
| includes/Experiment_Loader.php | Removes old experiment loader implementation. |
| includes/Exception/Invalid_Experiment_Metadata_Exception.php | Removes old metadata exception class. |
| includes/Deprecated.php | Adds deprecated bridges for renamed feature/experiment hooks and filters. |
| includes/Contracts/Feature.php | Introduces the new Feature contract. |
| includes/Contracts/Experiment.php | Removes the old Experiment contract. |
| includes/Abstracts/Abstract_Feature.php | Introduces shared feature base class including enablement + stability. |
| includes/Abstracts/Abstract_Experiment.php | Removes the old experiment base class. |
| includes/Abstracts/Abstract_Ability.php | Renames experiment_id param to feature_id for ability paths. |
| docs/DEVELOPER_GUIDE.md | Updates developer docs for new registration hook and exception guidance. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## develop #316 +/- ##
==========================================
Coverage ? 57.15%
Complexity ? 589
==========================================
Files ? 41
Lines ? 3076
Branches ? 0
==========================================
Hits ? 1758
Misses ? 1318
Partials ? 0
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
This PR refactors the plugin’s “Experiments” system into a unified “Features” system by introducing a WordPress\AI\Features namespace and treating experiments as a type of feature, while updating hooks/options and adding deprecation bridges.
Changes:
- Introduces
Features\Registry,Features\Loader,Contracts\Feature, andAbstract_Featureand migrates experiments to extendAbstract_Feature. - Updates settings/options, hooks, and tests (E2E + integration) to use the new feature-based APIs.
- Adds deprecation shims for legacy experiment hooks/actions until v1.0.
Reviewed changes
Copilot reviewed 60 out of 60 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/e2e/utils/helpers.ts | Updates E2E selectors to feature-based option IDs. |
| tests/Integration/Includes/HelpersTest.php | Makes filter callbacks static and reformats for consistency. |
| tests/Integration/Includes/Features/Feature_CategoryTest.php | Adds coverage for Feature_Category::OTHER. |
| tests/Integration/Includes/Experiments/Title_Generation/Title_GenerationTest.php | Migrates experiment tests to feature loader/registry + new option keys. |
| tests/Integration/Includes/Experiments/Summarization/SummarizationTest.php | Migrates summarization experiment tests to features system. |
| tests/Integration/Includes/Experiments/Review_Notes/Review_NotesTest.php | Migrates review notes experiment tests to features system. |
| tests/Integration/Includes/Experiments/Image_Generation/Image_GenerationTest.php | Migrates image generation experiment tests to features system. |
| tests/Integration/Includes/Experiments/ExperimentsTest.php | Adds test ensuring Experiments registers default feature classes. |
| tests/Integration/Includes/Experiments/Excerpt_Generation/Excerpt_GenerationTest.php | Migrates excerpt generation tests + updated enable/disable filter. |
| tests/Integration/Includes/Experiments/Example_Experiment/Example_ExperimentTest.php | Migrates example experiment test to register/init via features API. |
| tests/Integration/Includes/Experiments/Alt_Text_Generation/Alt_Text_GenerationTest.php | Migrates alt text generation tests + updated enable/disable filter. |
| tests/Integration/Includes/Experiments/Abilities_Explorer/Admin_PageTest.php | Updates phpdoc types to new namespaces. |
| tests/Integration/Includes/Experiments/Abilities_Explorer/Abilities_ExplorerTest.php | Migrates abilities explorer tests to features loader/registry. |
| tests/Integration/Includes/Experiment_RegistryTest.php | Converts registry tests from experiments to features registry. |
| tests/Integration/Includes/Experiment_LoaderTest.php | Converts loader tests from Experiment_Loader to Features\Loader. |
| tests/Integration/Includes/Abstracts/Abstract_ExperimentTest.php | Converts abstract experiment tests to Abstract_Feature + adds stability tests. |
| tests/Integration/Includes/Abstracts/Abstract_AbilityTest.php | Updates ability tests to use Abstract_Feature and refactors minor formatting. |
| tests/Integration/Includes/Abilities/Title_GenerationTest.php | Updates ability test experiment to Abstract_Feature + static get_id(). |
| tests/Integration/Includes/Abilities/SummarizationTest.php | Updates ability test experiment to Abstract_Feature + static get_id(). |
| tests/Integration/Includes/Abilities/Review_NotesTest.php | Updates ability test experiment to Abstract_Feature + static get_id(). |
| tests/Integration/Includes/Abilities/Image_Prompt_GenerationTest.php | Updates ability test experiment to Abstract_Feature + static get_id(). |
| tests/Integration/Includes/Abilities/Image_ImportTest.php | Updates ability test experiment to Abstract_Feature + static get_id() and minor alignment. |
| tests/Integration/Includes/Abilities/Image_GenerationTest.php | Updates ability test experiment to Abstract_Feature + static get_id() and minor alignment. |
| tests/Integration/Includes/Abilities/Excerpt_GenerationTest.php | Updates ability test experiment to Abstract_Feature + static get_id(). |
| tests/Integration/Includes/Abilities/Alt_Text_GenerationTest.php | Updates ability test experiment to Abstract_Feature + __DIR__ usage. |
| phpcs.xml.dist | Updates global prefix rules to match new naming/prefixes. |
| includes/bootstrap.php | Switches initialization to initialize_features() and wires in feature loader/registry. |
| includes/Settings/Settings_Registration.php | Migrates settings registration to iterate features and new option keys. |
| includes/Settings/Settings_Page.php | Migrates settings UI to read features and new option keys/IDs. |
| includes/Features/Registry.php | Adds new feature registry responsible for storing feature instances. |
| includes/Features/Loader.php | Adds new loader to register/initialize features from filtered class lists. |
| includes/Features/Feature_Category.php | Adds feature-level category constants (currently OTHER). |
| includes/Experiments/Title_Generation/Title_Generation.php | Migrates experiment implementation to Abstract_Feature + static get_id(). |
| includes/Experiments/Summarization/Summarization.php | Migrates experiment implementation to Abstract_Feature + static get_id(). |
| includes/Experiments/Review_Notes/Review_Notes.php | Migrates experiment implementation to Abstract_Feature + static get_id(). |
| includes/Experiments/Image_Generation/Image_Generation.php | Migrates experiment implementation to Abstract_Feature + static get_id(). |
| includes/Experiments/Experiments.php | Adds class that registers experiment classes as default features via filter. |
| includes/Experiments/Excerpt_Generation/Excerpt_Generation.php | Migrates experiment implementation to Abstract_Feature + static get_id(). |
| includes/Experiments/Example_Experiment/README.md | Updates docs to Abstract_Feature + new hooks/filters. |
| includes/Experiments/Example_Experiment/Example_Experiment.php | Migrates example experiment to Abstract_Feature + static get_id(). |
| includes/Experiments/Alt_Text_Generation/Alt_Text_Generation.php | Migrates experiment to Abstract_Feature + updates ability registration path building. |
| includes/Experiments/Abilities_Explorer/Abilities_Explorer.php | Migrates experiment implementation to Abstract_Feature + static get_id(). |
| includes/Experiment_Category.php | Moves experiment category to Experiments namespace and inherits feature category. |
| includes/Deprecated.php | Adds deprecation bridges from legacy experiment hooks/actions to new feature equivalents. |
| includes/Contracts/Feature.php | Adds new Feature interface (static id + stability). |
| includes/Abstracts/Abstract_Feature.php | Adds new base class implementing shared feature behavior + enablement logic. |
| includes/Abstracts/Abstract_Ability.php | Renames param in path() from experiment to feature for clarity. |
| docs/DEVELOPER_GUIDE.md | Updates developer docs for new custom feature registration hooks and exceptions. |
| includes/Experiment_Registry.php | Removes legacy experiment registry class (replaced by Features\Registry). |
| includes/Experiment_Loader.php | Removes legacy experiment loader class (replaced by Features\Loader). |
| includes/Abstracts/Abstract_Experiment.php | Removes legacy abstract experiment base class (replaced by Abstract_Feature). |
| includes/Contracts/Experiment.php | Removes legacy experiment contract (replaced by Contracts\Feature). |
| includes/Exception/Invalid_Experiment_Metadata_Exception.php | Removes legacy exception (docs now suggest standard exceptions). |
Comments suppressed due to low confidence (8)
tests/Integration/Includes/Experiment_LoaderTest.php:1
- These assertions still call an instance method
get_id(), but the newContracts\\FeatureAPI exposesget_id()as a static method. Update these calls to use$abilities_explorer_experiment::get_id()(and similarly for the others), or add a non-staticget_id()instance accessor inAbstract_Featureif you intend to keep the old call style.
tests/Integration/Includes/Experiment_LoaderTest.php:1 - These assertions still call an instance method
get_id(), but the newContracts\\FeatureAPI exposesget_id()as a static method. Update these calls to use$abilities_explorer_experiment::get_id()(and similarly for the others), or add a non-staticget_id()instance accessor inAbstract_Featureif you intend to keep the old call style.
tests/Integration/Includes/Experiment_LoaderTest.php:1 - These assertions still call an instance method
get_id(), but the newContracts\\FeatureAPI exposesget_id()as a static method. Update these calls to use$abilities_explorer_experiment::get_id()(and similarly for the others), or add a non-staticget_id()instance accessor inAbstract_Featureif you intend to keep the old call style.
tests/Integration/Includes/Experiment_LoaderTest.php:1 - These assertions still call an instance method
get_id(), but the newContracts\\FeatureAPI exposesget_id()as a static method. Update these calls to use$abilities_explorer_experiment::get_id()(and similarly for the others), or add a non-staticget_id()instance accessor inAbstract_Featureif you intend to keep the old call style.
tests/Integration/Includes/Experiment_LoaderTest.php:1 - These assertions still call an instance method
get_id(), but the newContracts\\FeatureAPI exposesget_id()as a static method. Update these calls to use$abilities_explorer_experiment::get_id()(and similarly for the others), or add a non-staticget_id()instance accessor inAbstract_Featureif you intend to keep the old call style.
tests/Integration/Includes/Experiment_LoaderTest.php:1 - These assertions still call an instance method
get_id(), but the newContracts\\FeatureAPI exposesget_id()as a static method. Update these calls to use$abilities_explorer_experiment::get_id()(and similarly for the others), or add a non-staticget_id()instance accessor inAbstract_Featureif you intend to keep the old call style.
tests/Integration/Includes/Experiment_LoaderTest.php:1 - These assertions still call an instance method
get_id(), but the newContracts\\FeatureAPI exposesget_id()as a static method. Update these calls to use$abilities_explorer_experiment::get_id()(and similarly for the others), or add a non-staticget_id()instance accessor inAbstract_Featureif you intend to keep the old call style.
tests/Integration/Includes/Abilities/Title_GenerationTest.php:1 - The docblock indentation here is inconsistent (extra indentation before
*) and is likely to trip WordPressCS/phpcs formatting rules. Align the docblock to the project’s standard indentation (one tab inside the class body) to keep linting consistent.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
dkotter
left a comment
There was a problem hiding this comment.
Overall this looks and tests well to me, left a few minor comments.
This is mentioned in the PR description but worth highlighting again that this introduces breaking changes. For instance, anyone that built custom experiments on top of our Abstract_Experiment class (which now no longer exists) will run into fatal errors. Or anyone accessing the Experiment_Registry directly (among other areas that have been removed). I think that's fine but needs to be called out in our changelog.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Darin Kotter <darin.kotter@gmail.com>
Co-authored-by: Darin Kotter <darin.kotter@gmail.com>
Co-authored-by: Darin Kotter <darin.kotter@gmail.com>
0eaba59 to
b361d2d
Compare
What?
This PR creates the new
Featuresnamespace, and makesExperimentsa type ofFeature.Class and methods contain breaking changes, hooks are
Deprecateduntil v1.0Important
This PR is based on #315 which should be merged first.
Why?
How?
Hooks
ai_experiments_register_experimentswpai_register_featuresai_experiments_default_experiment_classeswpai_default_feature_classesai_experiments_enabledwpai_features_enabledai_experiments_initializedwpai_features_initializedai_experiments_experiment_{id}_enabledwpai_feature_{id}_enabledOptions
ai_experiments_enabledwpai_features_enabledai_experiment_{id}_enabledwpai_feature_{id}_enabledai_experiment_{id}_field_{option_name}wpai_feature_{id}_field_{option_name}Important
There is no migrator class in this PR.
Class/Methods
WordPress\AI\Abstracts\Abstract_ExperimentWordPress\AI\Abstracts\Abstract_FeatureWordPress\AI\Contracts\ExperimentWordPress\AI\Contracts\FeatureWordPress\AI\Experiment_LoaderWordPress\AI\Features\LoaderWordPress\AI\Experiment_RegistryWordPress\AI\Features\RegistryWordPress\AI\Experiment_CategoryWordPress\AI\Features\Feature_CategoryWordPress\AI\Exception\Invalid_Experiment_Metadata_Exception\InvalidArgumentExceptionAbstract_Experiment::load_experiment_metadata()Abstract_Feature::load_metadata()id; ID is now staticExperiment::get_id()Feature::get_id()staticExperiment_Loader::register_default_experiments()Loader::register_features()Experiment_Loader::get_default_experiments()Loader::get_default_features()Experiment_Loader::initialize_experiments()Loader::initialize_features()Experiment_Registry::register_experiment()Registry::register_feature()Experiment_Registry::get_experiment()Registry::get_feature()Experiment_Registry::get_all_experiments()Registry::get_all_features()Experiment_Registry::has_experiment()Registry::has_feature()WordPress\AI\initialize_experiments()WordPress\AI\initialize_features()Use of AI Tools
Testing Instructions
Testing Instructions for Keyboard
Screenshots or screencast