-
Notifications
You must be signed in to change notification settings - Fork 466
feat: Experiments API #3098
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Experiments API #3098
Conversation
|
@justlevine I like where this is going. Will try and look at it more detailed shortly, but very nice idea |
|
@jasonbahl this is very early work, I'll ping you when it's worth your time to look over for real |
9245c75 to
fec4324
Compare
269ff74 to
c5ec8ed
Compare
|
@jasonbahl this is ready for initial review.
|
| /** | ||
| * Prepares the configuration. | ||
| * | ||
| * @return array{title:string,description:string} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we using phpstan now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We've been using it for a while. I'll probably unseal the type before final merge, but for now it makes sure nothing unnecessary is leaking in to the PR
| */ | ||
| protected function is_enabled(): bool { | ||
| if ( ! isset( $this->is_enabled ) ) { | ||
| $this->is_enabled = defined( 'GRAPHQL_EXPERIMENTAL_FEATURES' ) ? (bool) GRAPHQL_EXPERIMENTAL_FEATURES : true; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have any custom tab in the Site Health screen/page? Might help with debugging.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not yet, but it was mentioned in the last Office Hours 🤞
|
|
||
| return []; | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if multiple experiments are registered with the same slug we should call that out.
When testing the API, I accidentally left the slug the same as the test experiement, and my new one showed up but the test one disappeared and it took me a second to realize that it was because I left the slug the same. I caught it quickly, but would have caught it quicker if something warned me about the duplicate slugs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jasonbahlon re-review, I'm not entirely sure where to implement this, if at all.
As the initial release only targets usage by the core plugin, the register_experiments() relies on a hard-coded map, so issues like this would best be caught by code review.
We could refactor so each Experiment "registers itself" instead of using a class-map, but imo that's unnecessary complexity at this stage.
Thoughts?
|
@justlevine What is the difference between an "Experiment" and a "Feature Plugin"? In both cases I have the option to activate / deactivate some functionality. But the difference is that experiments are now bundled in core WPGraphQL where feature plugins (i.e. WPGraphQL Smart Cache, etc) can be versioned, updated, rolled-back, etc separate from WPGraphQL core. I'm curious what you believe the scope of an "Experiment" should be and how it is different than another plugin that can be installed and activated? Some examples of possible experiments that come to my mind might be:
I don't actually know how to justify bundling these in core as an experiment vs. shipping them as a separate plugin that folks can "enable" via installing and activating the plugin 🤔 |
|
I think the main difference from a feature plugin is that you can activate a feature per request, per part of the site. Similar to this plugin. Instead of deactivating the whole plugin. Experiment here, to me, is similar to an A/B test feature. I need both code to be available/active but I can choose to use one at a time or at the same time per request/page/etc. |
What do you mean "per request"? I read that as per http request. Like one query might have the feature enabled and one query might not? Or something like that? Does the HTTP request have to identify that it wants to use said experiment via query parameter or something? I guess I'm not fully following |
|
@renatonascalves looking at the plugin you shared from Alley, I'm still not sure how that differs from activating/de-activating a plugin. The user experience is still:
That sounds just like the user experience of navigating to the plugins page and using a checkbox interface to activate a plugin. I think I need some more concrete examples and use cases of where this makes sense and adds value that an extension plugin doesn't make sense or doesn't add the same value? It's clear there are use cases, but I'm struggling to see them |
|
I think I'll leave for @justlevine to explain it since it is his feature. But I understood the feature as something that could be toggled on and off easily and used or not per request/page/location (but that is more about how the feature could be used rather than the intention of the feature). |
|
From @justlevine: End user statement:"WPGraphQL Experiments allow you to experience the future of WPGraphQL today". Purpose:Allow for the shipping, iterating, and gathering feedback on (potential) upcoming changes to WPGraphQL core. What makes a good experiment:
What makes a bad experiment:
Real world triage:
|
|
@justlevine how would we migrate an experiment to production or deprecate an experiment we believe was a mistake? |
|
To tl;dr my above notes:
With the above context some replies:
With the above clarification between feature plugin and extension, the justification is reversed and usually clearer.
Similar but not exactly. I think I addressed most of this already so tl;dr for now, but happy to expand if needed:
Moving on from use case to implementation:
I havn't implemented this into the code yet, but per my mental model:
|
|
@justlevine how do consumers of the API know that they are consuming field(s) / Type(s) that are experimental? For orgs / teams where there are different people/teams consuming the API and another person/team maintaining the WordPress install, it would be nice for a consumer of the API to know whether they are interacting with something experimental and/or explicitly ask to interact with an experimental version of the API or a stable version. Hypothetical Scenario:WP team enables an experimental feature xx. Client team starts consuming xx. Experiment is deprecated. An admin notice was displayed for the WordPress team, but the client team didn't know about the impending deprecation. Client app is now breaking. Should we consider outputting something in the Extensions output of GraphQL queries to indicate active experiments? And/or allow the client to pass something in the request like: graphql( [
'query' => $query,
'variables' => $variables,
'extensions' => [
'experimentsEnabled' => true/false // or something along those lines?
]
] );And/or the payload of a response could include something like: {
"data": {
"someExperimentalField": "some data",
},
"extensions": {
"enabledExperiments": [
"experimentOne": {
"description": "Description of the experiment and impact on the Schema / Resolution",
"link": "https://github.com/wp-graphql/path/to/docs/about/the/experiment.md",
"notes": "Maybe some notes such as impending deprecation date or impending core merge date or other?"
}
]
}
}This would allow clients to have some insight into things that may/may not be around in the future, etc 🤔 |
|
@jasonbahl I think a simple
(More so, I think a Anything beyond that though feels like scope creep:
|
|
Code Climate has analyzed commit adb5756 and detected 1 issue on this pull request. Here's the issue category breakdown:
View more on Code Climate. |
Added deprecation handling in adb5756 |
|
Some thoughts about the Experiments API after playing with implementing the WPGraphQL IDE as an experiment: Admin NotificationIt would be nice to have an admin notification informing users that new Experiment(s) are available to be activated. If a new experiment is available (we'd likely need to store a list of experiments in the DB and diff against it in admin_init or something to that tune) then an admin notice (using register_graphql_admin_notice) could be displayed informing the user about the new experiment(s). We should probably do the same when an experiment is removed, informing the users about the removal (de-activation / deprecation). Experiment Activation / Deactivation HookSimilar to when a plugin is activated / de-activated, experiments should be able to "do something" in response to being activated or de-activated. For example, if I as an admin user activate the new WPGraphQL IDE Experiment, I would like to know what to do next. If the experiment was able to do something like redirect to the IDE settings tab, or redirect to a custom IDE landing page or something, then users would know "what to do next" Another (much simpler) option would be to just clarify the messaging in the Experiment description stating something to the tune of: "After activating this experiment, do x,y and z" and "After de-activating this experiment to x,y and z" ^ That might mean we at least have some contextual messaging we should display on the experiments page. i.e. display x message if the experiment is active and y message if it's not active. |
Implements the core Experiments API to enable rapid iteration on new features before they're declared production-ready. This allows the community to test and provide feedback on upcoming WPGraphQL features. ## Key Changes ### Core API Implementation - Add `AbstractExperiment` base class for all experiments - Add `ExperimentRegistry` to manage experiment registration and lifecycle - Add `Experimental` class to initialize experimental functionality - Add `Admin` class to integrate experiments into WPGraphQL Settings page - Add `TestExperiment` as an example implementation ### Initialization & Timing - Initialize experiments on `after_setup_theme` hook to prevent early translation loading - Make `WPGraphQL::setup_experiments()` public for hook compatibility ### Experiment Activation Controls - Support `GRAPHQL_EXPERIMENTAL_FEATURES` constant for programmatic control - `false` disables all experiments - Array format enables specific experiments: `['slug' => true]` - Constant overrides database settings - Add `graphql_dangerously_override_experiments` filter to override constant behavior - Named to clearly indicate dangerous nature of bypassing hard-coded controls - Useful for testing and specific deployment scenarios ### Testing Infrastructure - Add `ExperimentRegistryTest` with 2 tests covering registration and activation - Add `AbstractExperimentTest` with 6 tests covering: - Config validation (title, description) - Slug retrieval - Deprecation methods - GRAPHQL_EXPERIMENTAL_FEATURES constant behavior (false & array) - Filter override functionality - Add `clear_active_cache()` method to AbstractExperiment for testability - Add `reload_experiments()` method to ExperimentRegistry for test isolation ### Code Quality - Fix PHPStan error in `AppContext::get_loader()` return type - Fix PHPStan error in `ExperimentRegistry` hook parameter type - Update all `@since @todo` annotations to `@since next-version` - Clean implementation without ReflectionClass usage in production code ## Related - PR wp-graphql#3098 - Part of Phase 1.1 (Testing) from experiments-roadmap.md ## Testing All 8 tests passing: - 2 tests in ExperimentRegistryTest - 6 tests in AbstractExperimentTest - PHPStan analysis passes (1 pre-existing error in AppContext fixed)
Add complete documentation suite for the WPGraphQL Experiments API, including four focused guides covering all user types and a Vision section in README.md clarifying what belongs in core. ## Documentation Added - docs/experiments.md (~166 lines) - What are experiments and why they exist - Experiments vs Extensions vs Feature Flags comparison - Experiment lifecycle with clear phases - Core principles and comprehensive FAQ - docs/experiments-using.md (~393 lines) - End-user guide for enabling experiments - Multiple activation methods (Admin UI, wp-config, filters) - Environment-specific strategies (dev/staging/production) - Troubleshooting common issues and feedback guidelines - docs/experiments-creating.md (~608 lines) - Step-by-step developer tutorial with fully-commented examples - Complete EmailAddress scalar implementation walkthrough - Testing patterns and best practices - Advanced patterns (dependencies, deprecation, graduation) - Common mistakes and debugging tips - docs/experiments-contributing.md (~547 lines) - Contribution process from proposal to merge - Proposal template with detailed examples - Code review and iteration guidance - Graduation and deprecation processes - Tips for successful contributions ## Navigation & Structure - Updated docs/docs_nav.json - Added dedicated "Experiments" section - Positioned between "Dig Deeper" and "Community" - All four docs linked and accessible ## README Updates - Added Vision section (#vision anchor) - Clarifies WPGraphQL's role as canonical GraphQL API for WordPress - Defines what belongs in core vs extensions - NEW: Distinguishes experiments as "candidates for core" being validated - Explains experiments may graduate to core or be removed - Helps contributors understand appropriate scope for experiments ## Roadmap Updates - Updated experiments-roadmap.md - Marked Phase 1.4 (Documentation) as complete - Listed all completed documentation files - Updated metrics and next steps ## Key Improvements 1. **Clarifies Experiments vs Extensions**: README Vision section now explicitly distinguishes experiments (potential core features being validated) from extensions (intentionally separate plugins) 2. **Complete Coverage**: Docs address three distinct audiences: - End users: How to enable and use experiments - Developers: How to create experiments - Contributors: How to propose experiments to core 3. **Practical Examples**: Every concept includes working code examples that can be copied and used immediately 4. **Cross-Referenced**: All docs link to related content, creating a cohesive documentation experience ## Acceptance Criteria Met ✅ Users can understand and enable experiments without asking questions ✅ Developers can build experiments following clear patterns ✅ Contributors understand the proposal-to-graduation process ✅ Vision section provides scope guidance for experiment proposals ✅ Documentation integrated into website navigation Total: ~1,700 lines of new documentation Related: wp-graphql#3098
Complete Phase 1.2 (Code Cleanup) by enhancing documentation and ensuring code quality standards are met. ## Changes ### TestExperiment Documentation Updated src/Experimental/Experiment/TestExperiment.php: - Added comprehensive class-level documentation explaining purpose - Clearly states it's a demonstration experiment for learning - Documents what it does: adds a `testExperiment` field to RootQuery - Includes example GraphQL query in docblock - References documentation for real-world examples - Serves triple purpose: * Working example for developers learning to create experiments * Test fixture for validating Experiments API * Harmless way for users to try enabling/disabling experiments ### ExperimentRegistry Documentation Updated src/Experimental/ExperimentRegistry.php: - Improved register_experiments() method documentation - Added inline comment explaining TestExperiment's purpose - Included code example showing how to register custom experiments - Enhanced PHPDoc blocks for better developer experience ### Roadmap Updates Updated experiments-roadmap.md: - Marked Phase 1.2 (Code Cleanup) as complete ✅ - Documented all changes with date stamp - Updated "Next Steps" section to reflect progress ## Testing ✅ All 861 tests passing ✅ PHPStan analysis: 0 errors ✅ No functionality changes, only documentation improvements ## Phase 1 Progress - ✅ Phase 1.1 (Testing): Complete - ✅ Phase 1.2 (Code Cleanup): Complete - ⏸️ Phase 1.3 (Dependencies): Next - ✅ Phase 1.4 (Documentation): Complete ## Next Steps 1. Verify CI/CD passes 2. Implement Experiment Dependencies (Phase 1.3) Related: wp-graphql#3098
|
@justlevine closing in favor of: #3428 |
What does this implement/fix? Explain your changes.
This PR introduces the new Experiments API, allowing us to begin working/iterating on on experimental features within WPGraphQL core without worrying about future compatibility.
How it Works.
WPGraphQL\Experimental\Experiment\AbstractExperimentclass.WPGraphQL\Experimental\ExperimentRegistry, and their functionality loaded (by callingAbstractExperiment::init()) only if the experiment is active.WPGraphQL Settings > Experimentstab, or programmatically with theGRAPHQL_EXPERIMENTAL_FEATURESconstant.More details in
src/Experimental/README.mdTasks
Does this close any currently open issues?
Part of #3081
Any relevant logs, error output, GraphiQL screenshots, etc?
Note
This screen recycles existing
Settings API field types.To improve the UX we may want to introduce a new field type callback.
Any other comments?
src/Experimental/Experiment/TestExperiment. This should be removed before the PR is merged.Where has this been tested?
Operating System: Ubuntu 20.04 (wsl2+ devilbox + php 8.1.15)
WordPress Version: 6.5.2