Skip to content

Conversation

edanzer
Copy link
Contributor

@edanzer edanzer commented Sep 3, 2025

Proposed changes:

Disable the plugin install or activate buttons in the form integrations dashboard and block modal when the user does not have needed permissions.

Why? We need this because in an upcoming PR, we are going to start exposing the integrations panels in the VIP environment where users do not have plugin install rights. But it will also have an impact, for example, in WordPress multisite environments where users can activate but not install plugins. In short, there are environments where users should see the integrations panel, but not be able to click buttons to install/activate plugins.

Specific changes: The PluginActionButton component now retrieves plugin install/activate permissions from the forms config endpoint, and disables buttons if appropriate.

Screenshot: User who can install but not activate plugins will see this.
jetpack-plugin-permissions

Other information:

  • Have you written new tests for your changes, if applicable?
  • Have you checked the E2E test CI results, and verified that your changes do not break them?
  • Have you tested your changes on WordPress.com, if applicable (if so, you'll see a generated comment below with a script to run)?

Jetpack product discussion

Does this pull request change what data or activity we track or use?

Testing instructions:

NOTE: Make sure that you are not separate setting the jetpack_forms_enable_integrations_tab to false, which would hide the integrations dashboard. That's set to true by default here. Note that this filter will be removed and replaced in a separate PR.

  • Prepare plugins. Deactviate and delete the creative mail plugin. Then deactivate either the Jetpack CRM or MailPoet plugins, but leave them installed. This will give you some plugins in different states to test.

  • Create new user. Add a new user to your Jetpack dev site with an editor role. By default, editors cannot install or activate plugins.

  • Confirm cannot install or activate. Login to your Jetpack dev site with that new user. Go to Dashboard > Jetpack > Forms > Integrations. Confirm plugin Install or Activate buttons are disabled and if you hover, you see the correct tooltip text telling you the issue.

  • Update user. You now need to update your new user so they can activate, but still not install plugins. You can do that by adding this to your themes functions.php file:

// Update editor to be able to activaet plugin
add_action( 'init', function () {
	$role = get_role( 'editor' );
	
	if ( $role ) {
		$role->add_cap( 'activate_plugins' );
	}
} );
  • Confirm can activate but not install.. Go to Dashboard > Jetpack > Forms > Integrations again. Confirm plugin Install button is still disabled, but Activate button is now enabled and works.

  • Confirm admins can still install/activate. Finally, confirm no regressions by logging in with your admin user and confirm that user can always install and activate plugins.

@edanzer edanzer self-assigned this Sep 3, 2025
@edanzer edanzer added [Type] Enhancement Changes to an existing feature — removing, adding, or changing parts of it [Status] Needs Review This PR is ready for review. [Pri] Normal [Block] Contact Form Form block (also see Contact Form label) [Package] Forms labels Sep 3, 2025
@github-actions github-actions bot added [Feature] Contact Form [Plugin] Jetpack Issues about the Jetpack plugin. https://wordpress.org/plugins/jetpack/ [Status] In Progress labels Sep 3, 2025
Copy link
Contributor

github-actions bot commented Sep 3, 2025

Thank you for your PR!

When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:

  • ✅ Include a description of your PR changes.
  • ✅ Add a "[Status]" label (In Progress, Needs Review, ...).
  • ✅ Add a "[Type]" label (Bug, Enhancement, Janitorial, Task).
  • ✅ Add testing instructions.
  • ✅ Specify whether this PR includes any changes to data or privacy.
  • ✅ Add changelog entries to affected projects

This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖


Follow this PR Review Process:

  1. Ensure all required checks appearing at the bottom of this PR are passing.
  2. Make sure to test your changes on all platforms that it applies to. You're responsible for the quality of the code you ship.
  3. You can use GitHub's Reviewers functionality to request a review.
  4. When it's reviewed and merged, you will be pinged in Slack to deploy the changes to WordPress.com simple once the build is done.

If you have questions about anything, reach out in #jetpack-developers for guidance!


Jetpack plugin:

The Jetpack plugin has different release cadences depending on the platform:

  • WordPress.com Simple releases happen as soon as you deploy your changes after merging this PR (PCYsg-Jjm-p2).
  • WoA releases happen weekly.
  • Releases to self-hosted sites happen monthly:
    • Scheduled release: October 7, 2025
    • Code freeze: October 6, 2025

If you have any questions about the release process, please ask in the #jetpack-releases channel on Slack.

Copy link
Contributor

github-actions bot commented Sep 3, 2025

Are you an Automattician? Please test your changes on all WordPress.com environments to help mitigate accidental explosions.

  • To test on WoA, go to the Plugins menu on a WoA dev site. Click on the "Upload" button and follow the upgrade flow to be able to upload, install, and activate the Jetpack Beta plugin. Once the plugin is active, go to Jetpack > Jetpack Beta, select your plugin (Jetpack), and enable the add/forms-plugin-permissions-check branch.
  • To test on Simple, run the following command on your sandbox:
bin/jetpack-downloader test jetpack add/forms-plugin-permissions-check

Interested in more tips and information?

  • In your local development environment, use the jetpack rsync command to sync your changes to a WoA dev blog.
  • Read more about our development workflow here: PCYsg-eg0-p2
  • Figure out when your changes will be shipped to customers here: PCYsg-eg5-p2

@@ -788,6 +788,8 @@ public static function load_editor_scripts() {
'assetsUrl' => Jetpack_Forms::assets_url(),
'preferredView' => $preferred_view,
'isMailPoetEnabled' => Jetpack_Forms::is_mailpoet_enabled(),
'canInstallPlugins' => current_user_can( 'install_plugins' ),
'canActivatePlugins' => current_user_can( 'activate_plugins' ),
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that we are adding these values here, but also in class-dashboard.php below. Right now, we have three different ways in which we pass data to the frontend - one only for the editor and two for the dashboard here and here. We should try to consolidate that to avoid duplication. I started on PR, but it's a separate undertaking that doesn't fit in this PR.

For now, because the PluginActionButton shows in both the dashboard integrations panel, and the form integrations modal, we need that component to check both methods for passing data to the frontend.

>
{ getButtonText() }
</Button>
</span>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to wrap the Button in a span here because if Tooltip directly wraps Button, and Button is disabled, the tooltip will not show. Tooltips do not show on disabled buttons.

Copy link

jp-launch-control bot commented Sep 3, 2025

Code Coverage Summary

Coverage changed in 1 file.

File Coverage Δ% Δ Uncovered
projects/packages/forms/src/blocks/contact-form/components/jetpack-integrations-modal/integration-card/plugin-action-button.tsx 0/27 (0.00%) 0.00% 15 💔

Full summary · PHP report · JS report

If appropriate, add one of these labels to override the failing coverage check: Covered by non-unit tests Use to ignore the Code coverage requirement check when E2Es or other non-unit tests cover the code Coverage tests to be added later Use to ignore the Code coverage requirement check when tests will be added in a follow-up PR I don't care about code coverage for this PR Use this label to ignore the check for insufficient code coveage.

@edanzer edanzer marked this pull request as ready for review September 3, 2025 19:58
@edanzer edanzer requested review from a team and ilonagl September 3, 2025 19:58
CGastrell
CGastrell previously approved these changes Sep 3, 2025
Copy link
Contributor

@CGastrell CGastrell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worked well with my editor user and admin showed no regressions :shipit:

enejb
enejb previously approved these changes Sep 3, 2025
Copy link
Member

@enejb enejb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR worked as expected for me in the wp-admin side of things. As an admin and as the editor.

Nice work!

@edanzer edanzer force-pushed the add/forms-plugin-permissions-check branch from 9a36795 to f049915 Compare September 3, 2025 21:40
@simison
Copy link
Member

simison commented Sep 4, 2025

Can you elaborate on choice to pass permission checks from backend with custom data, instead of using core data store and canUser( 'create', 'plugins' )? Just a question, not a blocker for merging.

Design and copy looks great!

@edanzer
Copy link
Contributor Author

edanzer commented Sep 4, 2025

Can you elaborate on choice to pass permission checks from backend with custom data, instead of using core data store and canUser( 'create', 'plugins' )? Just a question, not a blocker for merging.

Design and copy looks great!

@simison That is actually what I did for the first implementation. But I could not get the checks to work correctly. I should say that canUser( 'create', 'plugins' ) was working, which checks for the permissions to install plugins. But I could not get the canUser( 'update', 'plugins' ) check for permissions to activate plugins to work separately. If you know why that may not work I'd be open to thoughts. I spend a while troubleshooting.

There are also some benefits to checking in PHP and localizing to JS, mostly around avoiding latency and jumps/flickr in the interface as things load. And we already have established mechanisms for passing data from PHP.

Even so, I'd be happy to continue digging on using the core data store if we prefer.

@edanzer
Copy link
Contributor Author

edanzer commented Sep 4, 2025

@simison - To add more context on the point above about core-data and the canUser check. I re-set this up locally and confirmed again it's not working. Here's the explanation for Cursor:

Install uses the collection route, which allows POST on /wp/v2/plugins. So canUser('create','plugins') checks that collection and returns true when install_plugins is allowed.

Activate uses the item route, not the collection. The collection typically doesn’t allow PUT/PATCH; activation is done on /wp/v2/plugins/{plugin}. So canUser('update','plugins') against the collection returns false even for admins.

To check activation via core-data, you’d need to target an item route, e.g. canUser('update', plugins/${pluginFile}), because the permission is evaluated per plugin resource. For a generic “can this user activate plugins” check (without a specific plugin), core-data can’t answer that on the collection; use a server-side boolean (current_user_can('activate_plugins')) or pass it via your existing localization.

So it's possible but it gets a bit funky. I think we'd need to pass the pluginFile path to the component and do something like:

const canActivateTHISSPECIFICPLUGIN = wp.data.select( coreStore )
  .canUser( 'update', `plugins/${ encodeURIComponent( pluginFile ) }` );

So it's a check per-plugin, not a general permissions check. Seems like a weird architectural choice not to have a general activate_plugins check, but I think that's the situation.

@simison
Copy link
Member

simison commented Sep 4, 2025

Thanks for digging into it!

Everything in WP is headed so much headless/JS SPA way that my gut tells it's generally better if things are API driven and data is pulled by JS, hence the question. In this case effort and efficiency from making the initial loading feel smooth begs for the backend solution, so let's go with it. 👍

Thanks again!

@edanzer edanzer force-pushed the add/forms-plugin-permissions-check branch from f049915 to a5fcd2c Compare September 4, 2025 16:33
@edanzer edanzer force-pushed the add/forms-plugin-permissions-check branch from a5fcd2c to 63d2b66 Compare September 8, 2025 19:36
@edanzer edanzer force-pushed the add/forms-plugin-permissions-check branch from 63d2b66 to fe5c912 Compare September 8, 2025 19:43
@edanzer edanzer dismissed stale reviews from enejb and CGastrell via d20b12a September 8, 2025 20:02
@edanzer
Copy link
Contributor Author

edanzer commented Sep 8, 2025

I have updated the approach in this PR. We were checking for plugin install/activate permissions in PHP and passing those to JS via the 'config' object on the dashboard and the jpFormsBlocks object in the editor.

But in #45091, we added a new 'forms config' endpoint that is preloaded on both dashboard and editor, and includes the permissions checks. So the current PR has been updated to use data from that endpoint.

This also fixes the build error were getting on this PR due to JS bundle size. The old approach was effectively loading the whole dashboard dependency tree in the editor because of how the config object is setup. The new way resolves that by using a simple endpoint.

@simison - You asked above about why we retrieve permissions in PHP. Just tagging you here because that's now changed.

Copy link
Contributor

@CGastrell CGastrell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Works nicely! Thanks! :shipit:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Block] Contact Form Form block (also see Contact Form label) [Feature] Contact Form [Package] Forms [Plugin] Jetpack Issues about the Jetpack plugin. https://wordpress.org/plugins/jetpack/ [Pri] Normal [Status] In Progress [Status] Needs Review This PR is ready for review. [Type] Enhancement Changes to an existing feature — removing, adding, or changing parts of it
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants