Skip to content
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

Do async site scan on plugin activation instead of synchronous validation #6685

Merged
merged 38 commits into from
Dec 2, 2021

Conversation

delawski
Copy link
Collaborator

@delawski delawski commented Nov 4, 2021

Summary

Fixes #5101

Screen.Recording.2021-11-23.at.09.37.04.PM.mp4

This PR renders an admin notice box whenever a plugin is activated. The admin notice starts a full Site Scan immediately and presents validation results as soon as the scan is complete:

Scan in progress after plugin activation Scan complete - no plugin issues
Screenshot 2021-11-23 at 21 09 12 Screenshot 2021-11-23 at 21 12 33
Scan complete - URLs list collapsed Scan complete - URLs list expanded
Screenshot 2021-11-23 at 21 07 37 Screenshot 2021-11-23 at 21 07 25

Note that there is a slight difference in the implementation compared to the design. After Site Scan is done, we're listing out all plugins causing AMP incompatibilities along with the URLs on which the issues were discovered. Also, a CTA to AMP compatible plugins is not hidden inside the <details> element but it's rather outside of it (since there might be multiple <details> elements in a single notice.

According to the design, we should be showing only issues related to the plugin (or multiple plugins) that has just been activated. The CTA should be collapsed by default inside the <details> element.

On one hand, the designed approach would be more complex in terms of the implementation. Since Core doesn't store a list of plugins that were last activated (or is it?), we would have to persist it on our own, probably using the Options API. On the other hand, though, from a user point of view, I believe it's better to let a user know about every plugin that causes AMP validation errors, not just the one that has been activated.

In any case, I'm happy to change the implementation so that it matches the design.

Implementation Details

  • A new JS entry point has been added to the admin group: amp-site-scan-notice.
  • Since the admin notice requires the validation issues to be grouped by a different "dimension", i.e. not by a URL but rather a plugin, the getSlugsFromValidationResults helper had to be transformed into a more robust getSourcesFromScannableUrls function. The arrays returned by getSlugsFromValidationResults contained just the plugin/theme slugs like [ 'amp', 'pwa' ]. With getSourcesFromScannableUrls, the returned arrays also contain a list of URLs where the issues were found, e.g. [ { slug: 'amp', urls: [ ... ] }, { slug: 'pwa', urls: [ ... ] } ].
  • The PHP code related to the post-plugin-activation admin notice has been refactored out of class-amp-validation-manager.php and into a new class PluginActivationSiteScan.

Checklist

  • My code is tested and passes existing tests.
  • My code follows the Engineering Guidelines (updates are often made to the guidelines, check it out periodically).

@delawski delawski force-pushed the feature/async-scan-on-plugin-activation branch from b45c4c0 to 17bedd5 Compare November 23, 2021 09:50
@delawski delawski force-pushed the feature/async-scan-on-plugin-activation branch from 8f1a04f to 3857c7a Compare November 23, 2021 12:23
@delawski delawski self-assigned this Nov 23, 2021
@delawski delawski marked this pull request as ready for review November 23, 2021 20:34
@delawski
Copy link
Collaborator Author

delawski commented Dec 1, 2021

@westonruter I've updated the post-scan notice according to your suggestions. Also, the message for non-technical users has been updated.

One plugin causing AMP incompatibilities

Technical user Non-technical user
Screenshot 2021-12-01 at 12 40 51 Screenshot 2021-12-01 at 12 48 24

Two or more plugins causing AMP incompatibilities

Technical user Non-technical user
Screenshot 2021-12-01 at 12 41 16 Screenshot 2021-12-01 at 12 48 00

@milindmore22
Copy link
Collaborator

When I tried to activate any plugin, I got the following error

{
  "message": "destroy is not a function",
  "stack": "TypeError: destroy is not a function\n    at commitHookEffectListUnmount (https://amp-local.test/wp-includes/js/dist/vendor/react-dom.js?ver=16.13.1:19845:13)\n    at commitPassiveHookEffects (https://amp-local.test/wp-includes/js/dist/vendor/react-dom.js?ver=16.13.1:19903:13)\n    at HTMLUnknownElement.callCallback (https://amp-local.test/wp-includes/js/dist/vendor/react-dom.js?ver=16.13.1:182:16)\n    at Object.invokeGuardedCallbackDev (https://amp-local.test/wp-includes/js/dist/vendor/react-dom.js?ver=16.13.1:231:18)\n    at invokeGuardedCallback (https://amp-local.test/wp-includes/js/dist/vendor/react-dom.js?ver=16.13.1:286:33)\n    at flushPassiveEffectsImpl (https://amp-local.test/wp-includes/js/dist/vendor/react-dom.js?ver=16.13.1:22988:11)\n    at unstable_runWithPriority (https://amp-local.test/wp-includes/js/dist/vendor/react.js?ver=16.13.1:2685:14)\n    at runWithPriority$1 (https://amp-local.test/wp-includes/js/dist/vendor/react-dom.js?ver=16.13.1:11174:12)\n    at flushPassiveEffects (https://amp-local.test/wp-includes/js/dist/vendor/react-dom.js?ver=16.13.1:22955:14)\n    at https://amp-local.test/wp-includes/js/dist/vendor/react-dom.js?ver=16.13.1:22834:13"
}

image

@delawski
Copy link
Collaborator Author

delawski commented Dec 2, 2021

@milindmore22 Thank you for the report. I'm not able to reproduce the error. It happens only if Gutenberg is not activated. I'm investigating it now.

@delawski
Copy link
Collaborator Author

delawski commented Dec 2, 2021

The issue described by @milindmore22 was caused by the fact that Gutenberg comes with React 17 while WordPress 5.8 is contains React 16.13. Version 17 brought some changes to how useEffect cleanup functions are handled. With 18178b1, the Site Scan feature should work well with the older version of React, too. What's more, we'll now be testing if the feature works as expected even without Gutenberg (f2a0937).

Along the way, I noticed some other issues:

  • wp-components has not been set as a dependency to the new amp-site-scan-notice stylesheet causing some minor visual issues (fixed in f6f5ff5).
  • Site scan has been needlessly triggered on a plugin network activation (fixed in b17b93a).

@delawski
Copy link
Collaborator Author

delawski commented Dec 2, 2021

While working on this issue, I noticed a potential bug with a multisite setup: #6755

Copy link
Collaborator

@milindmore22 milindmore22 left a comment

Choose a reason for hiding this comment

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

LGTM 👍🏼

…sync-scan-on-plugin-activation

* 'develop' of github.com:ampproject/amp-wp:
  Add test case for Bento lacking layout attributes; improve test coverage
  Fix phpcs alignment warning
  Cast term IDs to integers instead of using sanitize_key()
  Use strict check for in_array() and improve comment
  Derive intrinsic layout when max-width defined
  Validate supported layouts for converted Bento components; add support for fill and nodisplay
  Update AMP_Base_Sanitier::set_layout() to account for 100% width/height styles
  Harmonize Bento component name parsing
  Fix variable name
  Fix typos in comments
  Add support for converting Bento component dimensions from inline styles to AMP layout
  Further improve test converage and remove dead code
  Improve test coverage for ID attribute changes
  Improve Bento sanitizer and add tests
  Prevent bento components from being treated as light shadow DOM wrappers
  Prevent JS error on validated URL screen when no validation errors present
  Fix handling of ID attributes during sanitizer conversion
  Introduce Bento sanitizer to deal with BentoJS components
  Prevent completely tree-shaken styles from triggering excessive CSS
Comment on lines 41 to 61
if ( ! userIsTechnical ) {
return (
<p
dangerouslySetInnerHTML={ {
__html: sprintf(
/* translators: %s is a name of a plugin or a list of plugin names separated with commas. */
_n(
'AMP compatibility issues discovered with %s.',
'AMP compatibility issues discovered with the following plugins: %s.',
pluginsWithAmpIncompatibility.length,
'amp',
),
pluginsWithAmpIncompatibility
.map( ( pluginWithAmpIncompatibility ) => `<b>${ pluginNames[ pluginWithAmpIncompatibility.slug ] }</b>` )
.join( ', ' ),
),
} }
/>
);
}

Copy link
Member

Choose a reason for hiding this comment

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

I appreciate the concern for users who are not technical, but the additional information exposed below doesn't have anything technical on it. It just has the URLs on which issues were encountered. Listing out the URLs on which errors occur is helpful even for non-technical users so that they can check them out to see if anything is broken. Therefore I don't think this condition is needed.

Something I can see as being helpful in terms of making it more user-friendly is for the original <title> of the validated URL to be stored and for that to be displayed as the link text instead of URL. But we can explore that in a subsequent improvement.

Copy link
Member

@westonruter westonruter left a comment

Choose a reason for hiding this comment

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

This is so great and so much better than before. Not only does it no longer slow down the activation of a plugin, it also scans all the scannable URLs instead of just one. 💯

@westonruter westonruter merged commit 78092fe into develop Dec 2, 2021
@westonruter westonruter deleted the feature/async-scan-on-plugin-activation branch December 2, 2021 23:03
<a
href={ AMP_COMPATIBLE_PLUGINS_URL }
className="button"
{ ...isExternalUrl( AMP_COMPATIBLE_PLUGINS_URL ) ? { target: '_blank', rel: 'noopener noreferrer' } : {} }
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That being said, it seems that noopener noreferrer is a common practice, e.g. the <ExternalLink> from @wordpress/components sets both rel types (plus an external type).

If that's the case, let's keep both noopener and noreferrer.

Comment on lines +72 to +74
<a href={ url } target="_blank" rel="noopener noreferrer">
{ url }
</a>
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I guess it'd be best to use ExternalLink from @wordpress/components instead of a plain <a> tag.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Scratch that. ExternalLink adds an icon next to a link and there seem to be no way to remove the icon at the JS-level (other than hiding it with CSS):

Screenshot 2021-12-03 at 11 50 51

await page.waitForSelector( `tr[data-slug="${ slug }"] .deactivate a` );
}

describe( 'for a user', () => {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We can now safely remove this nested describe since we're not testing different user types anymore.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This has been addressed in a followup PR: #6758.

@westonruter westonruter added the Changelogged Whether the issue/PR has been added to release notes. label Dec 14, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Changelogged Whether the issue/PR has been added to release notes. Developer Tools Site Scanning Validation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Discontinue doing synchronous validation requests upon activating plugins
4 participants