Feat/add role user access controls - #749
Conversation
…trolSettings to enable explicit saving
… update dependencies
…ion in AccessControlSettings
…ction tracking in AccessControlSettings
… and refresh lockfile
…pdate clear hook type definition
|
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. |
…ication logic in helper function
…ic to reset access control settings upon toggle
…rom suggestions in AccessControlSettings
…me variables for consistent styling
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## develop #749 +/- ##
=============================================
+ Coverage 78.40% 78.53% +0.13%
- Complexity 2454 2470 +16
=============================================
Files 104 105 +1
Lines 9918 10027 +109
=============================================
+ Hits 7776 7875 +99
- Misses 2142 2152 +10
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
@Infinite-Null FYI some merge conflicts to resolve to keep this moving along |
Added - New "Advanced settings" option in Developer Tools to show/hide additional configuration options for features and experiments. Changed - Move all existing configuration options into a new "Advanced settings" section which is hidden by default. Co-authored-by: Infinite-Null <ankitkumarshah@git.wordpress.org> Co-authored-by: jeffpaul <jeffpaul@git.wordpress.org> Co-authored-by: dkotter <dkotter@git.wordpress.org>
|
Thanks for the heads up, @jeffpaul! I've resolved the merge conflicts now. Whenever you have a chance, could you please take another look? Thanks! |
…oduce helper functions for managing access settings.
…arization settings
|
Thanks for working on this. I maintain Flavor Agent, a third-party The current implementation appears to enforce access by calling In Flavor Agent, for example, Would it make sense to:
I can contribute the failing third-party integration test and the centralized enforcement change. The important acceptance criterion for me is that an unauthorized user receives neither the first-party feature surface nor an executable programmatic path, while existing WordPress capability checks remain in force. |
| * {@inheritDoc} | ||
| */ | ||
| public function register(): void { | ||
| if ( ! \WordPress\AI\ai_current_user_can_access_feature( $this->get_id() ) ) { |
There was a problem hiding this comment.
I don't love forcing each experiment to run this same code. Since all experiments extend Abstract_Feature, could a check like this live there so any experiment that extends that class automatically gets this behavior? Or maybe even better in our Loader class?
There was a problem hiding this comment.
For example, this PR doesn't apply this to Image Generation or Type Ahead
There was a problem hiding this comment.
The other issue to consider is that some features do other things in this register method beyond just loading the UI and the Ability. For instance, custom post meta is registered or caches are cleared. Those things will no longer run for certain users, if restriction is turned on, leading to weird edge cases that will be hard to debug. Ideally we figure out a way to prevent the actual experiment from running but still allow other pieces to function properly
| /** | ||
| * Roles_Users_Controller test case. | ||
| * | ||
| * @since 0.9.0 |
There was a problem hiding this comment.
All @since statements in this PR need to be set to x.x.x
|
|
||
| private const MAX_USERS = 10; | ||
|
|
||
| public function init(): void { |
There was a problem hiding this comment.
Any reason to not have docblocks on all methods and constants in this class?
| ); | ||
|
|
||
| if ( '' !== $search ) { | ||
| $get_users_args['search'] = '*' . $search . '*'; |
There was a problem hiding this comment.
Any escaping we should be applying here?
| * If no roles or users are explicitly configured for the feature, it allows access by default. | ||
| * If there are configured roles/users, the current user must match at least one role or be explicitly listed. | ||
| * | ||
| * @since 0.1.0 |
There was a problem hiding this comment.
| * @since 0.1.0 | |
| * @since x.x.x |
|
|
||
| $current_user = wp_get_current_user(); | ||
|
|
||
| if ( in_array( $current_user->ID, $users, true ) ) { |
There was a problem hiding this comment.
| if ( in_array( $current_user->ID, $users, true ) ) { | |
| if ( in_array( $current_user->ID, array_map( 'intval', (array) $users ), true ) ) { |
| $roles = get_option( "wpai_feature_{$feature_id}_roles", array() ); | ||
| $users = get_option( "wpai_feature_{$feature_id}_users", array() ); | ||
|
|
||
| if ( empty( $roles ) && empty( $users ) ) { |
There was a problem hiding this comment.
Do we also need an is_array check here on these?
| ) | ||
| ); | ||
|
|
||
| register_setting( |
There was a problem hiding this comment.
Might want to add a sanitize_callback to both of these to ensure we only save real user roles and real user IDs
| </p> | ||
| ) } | ||
| { ! isLoading && ! fetchError && ( | ||
| <> |
There was a problem hiding this comment.
Is this fragment necessary?
| accessibleWhenDisabled | ||
| > | ||
| { isSaving ? ( | ||
| <Spinner /> |
There was a problem hiding this comment.
No need to display a spinner here, we can rely on isBusy
…mplementation across experimental modules.
|
@Infinite-Null please let us know when you're updated from comments/code review feedback for us to test this out again, thanks! |
Hey @jeffpaul, I am out till 16th August due to personal commitments. I will update the comments/code review after then. Thank you for understanding. |
Closes: #736
Description
This PR introduces Feature-Level Access Controls exclusively for Editor Experiments, allowing site administrators to restrict access to individual AI-powered editor features based on specific WordPress roles or individual users.
Testing Instructions
Screencast
User: Ankit Shah | Role: Editor
Screen.Recording.2026-06-22.at.1.35.17.PM-compressed.mp4
Use of AI Tools
AI assistance: Yes
Tool(s): Claude Code
Model(s): Sonnet 4.6
Used for: Validating bug, suggesting a fix.
Changelog Entry