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

Add back-compat to old WP versions for new v2.2 features #6773

Merged
merged 37 commits into from
Dec 14, 2021
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
2a69d65
Check dependency_support in is_needed for AmpPlugins, AmpThemes, and …
westonruter Dec 8, 2021
949eeb3
Add status=active parameter to /wp/v2/themes REST API call for WP<5.7…
westonruter Dec 8, 2021
7fa097e
Do not search for blocks when on WordPress 4.9 and older
delawski Dec 8, 2021
f57f25c
Fail silently if plugins/themes endpoints are not available
delawski Dec 8, 2021
3f3cb57
Ensure Onboarding Wizard works on WordPress 4.9
delawski Dec 8, 2021
148d397
Fetch used plugin and theme fields only
delawski Dec 8, 2021
6b553c4
Update message copy
delawski Dec 8, 2021
c8a2d41
Add minimum WordPress version check for Support page
dhaval-parekh Dec 8, 2021
da361ae
Update unit test cases
dhaval-parekh Dec 8, 2021
bec8cbe
Fix phpcs issues
dhaval-parekh Dec 8, 2021
15a2a0f
Improve theme/plugin unavailability messaging
westonruter Dec 8, 2021
cff0d8f
Ensure ID attribute is added to scripts in WP<5.5
westonruter Dec 8, 2021
7345070
Harden injection of ID attribute into script loader tag
westonruter Dec 8, 2021
9360c3b
Fix regex pattern inversion
westonruter Dec 8, 2021
b58284d
Prevent access to validation UI when dependency_support is absent
westonruter Dec 8, 2021
2913e59
Fix URLValidationRESTControllerTest after new DependencySupport depen…
westonruter Dec 9, 2021
d830cb6
Remove obsolete SavePostValidationEvent
westonruter Dec 7, 2021
75d902c
Block access to AMP Customizer if site lacks dependency_support
westonruter Dec 9, 2021
ae04461
Fix typo
delawski Dec 9, 2021
c5ef2ec
Fix tests for restricting DevTools to whether DependencySupport present
westonruter Dec 9, 2021
0f2430b
Further fix PHPUnit tests after c5ef2ec0f
westonruter Dec 9, 2021
cc835a3
Merge branch 'develop' of github.com:ampproject/amp-wp into add/wp-ba…
westonruter Dec 10, 2021
c1e18f8
Temporarily register dependency_support as first service
westonruter Dec 10, 2021
721916a
Revert "Ensure Onboarding Wizard works on WordPress 4.9"
westonruter Dec 10, 2021
30b78fc
Add dependency_support as a requirement for AmpPlugins & AmpThemes
schlessera Dec 12, 2021
3214f92
Add missing HasRequirements interface to PluginActivationSiteScan
westonruter Dec 13, 2021
942f91e
Add codeCoverageIgnore comments
westonruter Dec 13, 2021
00ec54f
Further harden regex in amp_ensure_id_attribute_on_script_loader_tag()
westonruter Dec 13, 2021
24943e9
Restore wp_version in test tearDown method
westonruter Dec 13, 2021
e5c562b
Run amp_ensure_id_attribute_on_script_loader_tag at earliest priority
westonruter Dec 13, 2021
0dcdc77
Fix tests in WP 4.9..5.1
westonruter Dec 13, 2021
6d26e84
Fix test_prepare_response_standard in WP<5.5
westonruter Dec 13, 2021
f1c6208
Add tests for AMP_Customizer_Design_Settings
westonruter Dec 13, 2021
ccb9090
Add tests for amp_bootstrap_plugin()
westonruter Dec 13, 2021
6dbd043
Fix test_init_customizer to account for Gutenberg being active
westonruter Dec 13, 2021
779104f
Use remove_all_filters instead of remove_all_actions for purity sake
westonruter Dec 13, 2021
ff7e7b7
Hide DevTools toggles when dependency_support is absent
westonruter Dec 13, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .phpstorm.meta.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
'rest.scannable_urls_controller' => \AmpProject\AmpWP\Validation\ScannableURLsRestController::class,
'rest.validation_counts_controller' => \AmpProject\AmpWP\Validation\ValidationCountsRestController::class,
'sandboxing' => \AmpProject\AmpWP\Sandboxing::class,
'save_post_validation_event' => \AmpProject\AmpWP\Validation\SavePostValidationEvent::class,
'server_timing' => \AmpProject\AmpWP\Instrumentation\ServerTiming::class,
'site_health_integration' => \AmpProject\AmpWP\Admin\SiteHealth::class,
'support' => \AmpProject\AmpWP\Support\SupportCliCommand::class,
Expand Down
2 changes: 1 addition & 1 deletion assets/src/admin/site-scan-notice/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ function Providers( { children } ) {
optionsRestPath={ OPTIONS_REST_PATH }
populateDefaultValues={ false }
>
<PluginsContextProvider hasErrorBoundary={ true }>
<PluginsContextProvider>
<SiteScanContextProvider
scannableUrlsRestPath={ SCANNABLE_URLS_REST_PATH }
validateNonce={ VALIDATE_NONCE }
Expand Down
42 changes: 10 additions & 32 deletions assets/src/components/plugins-context-provider/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,22 @@ import PropTypes from 'prop-types';
/**
* WordPress dependencies
*/
import {
createContext,
useContext,
useEffect,
useRef,
useState,
} from '@wordpress/element';
import { createContext, useEffect, useRef, useState } from '@wordpress/element';
import apiFetch from '@wordpress/api-fetch';

/**
* Internal dependencies
*/
import { ErrorContext } from '../error-context-provider';
import { useAsyncError } from '../../utils/use-async-error';
import { addQueryArgs } from '@wordpress/url';

export const Plugins = createContext();

/**
* Plugins context provider.
*
* @param {Object} props Component props.
* @param {any} props.children Component children.
* @param {boolean} props.hasErrorBoundary Whether the component is wrapped in an error boundary.
* @param {Object} props Component props.
* @param {any} props.children Component children.
*/
export function PluginsContextProvider( {
children,
hasErrorBoundary = false,
} ) {
export function PluginsContextProvider( { children } ) {
const [ plugins, setPlugins ] = useState( [] );
const [ fetchingPlugins, setFetchingPlugins ] = useState( null );

const { error, setError } = useContext( ErrorContext );
const { setAsyncError } = useAsyncError();
const [ error, setError ] = useState();

/**
* This component sets state inside async functions.
Expand All @@ -62,7 +45,9 @@ export function PluginsContextProvider( {

try {
const fetchedPlugins = await apiFetch( {
path: '/wp/v2/plugins',
path: addQueryArgs( '/wp/v2/plugins', {
_fields: [ 'author', 'name', 'plugin', 'status', 'version' ],
} ),
} );

if ( hasUnmounted.current === true ) {
Expand All @@ -76,17 +61,11 @@ export function PluginsContextProvider( {
}

setError( e );

if ( hasErrorBoundary ) {
setAsyncError( e );
}

return;
}

setFetchingPlugins( false );
} )();
}, [ error, fetchingPlugins, hasErrorBoundary, plugins, setAsyncError, setError ] );
}, [ error, fetchingPlugins, plugins ] );

return (
<Plugins.Provider
Expand All @@ -101,5 +80,4 @@ export function PluginsContextProvider( {
}
PluginsContextProvider.propTypes = {
children: PropTypes.any,
hasErrorBoundary: PropTypes.bool,
};
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export function PluginsWithAmpIncompatibility( {
<SiteScanSourcesList
sources={ sources }
inactiveSourceNotice={ __( 'This plugin has been deactivated since last site scan.' ) }
uninstalledSourceNotice={ __( 'This plugin has been uninstalled since last site scan.' ) }
uninstalledSourceNotice={ __( 'This plugin has been uninstalled or its metadata is unavailable.' ) }
/>
</SiteScanResults>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export function ThemesWithAmpIncompatibility( {
<SiteScanSourcesList
sources={ sources }
inactiveSourceNotice={ __( 'This theme has been deactivated since last site scan.' ) }
uninstalledSourceNotice={ __( 'This theme has been uninstalled since last site scan.' ) }
uninstalledSourceNotice={ __( 'This theme has been uninstalled or its metadata is unavailable.' ) }
/>
</SiteScanResults>
);
Expand Down
42 changes: 10 additions & 32 deletions assets/src/components/themes-context-provider/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,39 +6,22 @@ import PropTypes from 'prop-types';
/**
* WordPress dependencies
*/
import {
createContext,
useContext,
useEffect,
useRef,
useState,
} from '@wordpress/element';
import { createContext, useEffect, useRef, useState } from '@wordpress/element';
import apiFetch from '@wordpress/api-fetch';

/**
* Internal dependencies
*/
import { ErrorContext } from '../error-context-provider';
import { useAsyncError } from '../../utils/use-async-error';
import { addQueryArgs } from '@wordpress/url';

export const Themes = createContext();

/**
* Themes context provider.
*
* @param {Object} props Component props.
* @param {any} props.children Component children.
* @param {boolean} props.hasErrorBoundary Whether the component is wrapped in an error boundary.
* @param {Object} props Component props.
* @param {any} props.children Component children.
*/
export function ThemesContextProvider( {
children,
hasErrorBoundary = false,
} ) {
export function ThemesContextProvider( { children } ) {
const [ themes, setThemes ] = useState( [] );
const [ fetchingThemes, setFetchingThemes ] = useState( null );

const { error, setError } = useContext( ErrorContext );
const { setAsyncError } = useAsyncError();
const [ error, setError ] = useState();

/**
* This component sets state inside async functions.
Expand All @@ -62,7 +45,9 @@ export function ThemesContextProvider( {

try {
const fetchedThemes = await apiFetch( {
path: '/wp/v2/themes',
path: addQueryArgs( '/wp/v2/themes', {
_fields: [ 'author', 'name', 'status', 'stylesheet', 'version' ],
} ),
} );

if ( hasUnmounted.current === true ) {
Expand All @@ -76,17 +61,11 @@ export function ThemesContextProvider( {
}

setError( e );

if ( hasErrorBoundary ) {
setAsyncError( e );
}

return;
}

setFetchingThemes( false );
} )();
}, [ error, fetchingThemes, hasErrorBoundary, themes, setAsyncError, setError ] );
}, [ error, fetchingThemes, themes ] );

return (
<Themes.Provider
Expand All @@ -101,5 +80,4 @@ export function ThemesContextProvider( {
}
ThemesContextProvider.propTypes = {
children: PropTypes.any,
hasErrorBoundary: PropTypes.bool,
};
4 changes: 2 additions & 2 deletions assets/src/onboarding-wizard/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,8 @@ export function Providers( { children } ) {
userOptionDeveloperTools={ USER_FIELD_DEVELOPER_TOOLS_ENABLED }
usersResourceRestPath={ USERS_RESOURCE_REST_PATH }
>
<PluginsContextProvider hasErrorBoundary={ true }>
<ThemesContextProvider hasErrorBoundary={ true }>
<PluginsContextProvider>
<ThemesContextProvider>
<SiteScanContextProvider
fetchCachedValidationErrors={ false }
resetOnOptionsChange={ false }
Expand Down
4 changes: 2 additions & 2 deletions assets/src/settings-page/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ function Providers( { children } ) {
updatesNonce={ UPDATES_NONCE }
wpAjaxUrl={ wpAjaxUrl }
>
<PluginsContextProvider hasErrorBoundary={ true }>
<ThemesContextProvider hasErrorBoundary={ true }>
<PluginsContextProvider>
<ThemesContextProvider>
<SiteScanContextProvider
fetchCachedValidationErrors={ true }
resetOnOptionsChange={ true }
Expand Down
35 changes: 35 additions & 0 deletions includes/admin/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
* @package AMP
*/

use AmpProject\AmpWP\DependencySupport;
use AmpProject\AmpWP\Option;
use AmpProject\AmpWP\QueryVar;
use AmpProject\AmpWP\Services;

/**
* Sets up the AMP template editor for the Customizer.
Expand All @@ -15,6 +17,39 @@
*/
function amp_init_customizer() {

if ( ! Services::get( 'dependency_support' )->has_support() ) {
// @codeCoverageIgnoreStart
add_action(
'customize_controls_init',
static function () {
global $wp_customize;
if (
Services::get( 'reader_theme_loader' )->is_theme_overridden()
||
array_intersect( $wp_customize->get_autofocus(), [ 'panel' => AMP_Template_Customizer::PANEL_ID ] )
||
isset( $_GET[ QueryVar::AMP_PREVIEW ] ) // phpcs:ignore WordPress.Security.NonceVerification.Recommended
) {
wp_die(
esc_html(
sprintf(
/* translators: %s is minimum WordPress version */
__( 'Customizer for AMP is unavailable due to WordPress being out of date. Please upgrade to WordPress %s or greater.', 'amp' ),
DependencySupport::WP_MIN_VERSION
)
),
esc_html__( 'AMP Customizer Unavailable', 'amp' ),
[
'response' => 503,
'back_link' => true,
]
);
}
}
);
// @codeCoverageIgnoreEnd
}

// Fire up the AMP Customizer.
add_action( 'customize_register', [ AMP_Template_Customizer::class, 'init' ], 500 );

Expand Down
34 changes: 34 additions & 0 deletions includes/amp-helper-functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ function amp_bootstrap_plugin() {
// Ensure async and custom-element/custom-template attributes are present on script tags.
add_filter( 'script_loader_tag', 'amp_filter_script_loader_tag', PHP_INT_MAX, 2 );

// Ensure ID attribute is present in WP<5.5.
if ( version_compare( get_bloginfo( 'version' ), '5.5', '<' ) ) {
add_filter( 'script_loader_tag', 'amp_ensure_id_attribute_on_script_loader_tag', ~PHP_INT_MAX, 2 );
}

// Ensure crossorigin=anonymous is added to font links.
add_filter( 'style_loader_tag', 'amp_filter_font_style_loader_tag_with_crossorigin_anonymous', 10, 4 );

Expand Down Expand Up @@ -1157,6 +1162,35 @@ function amp_filter_script_loader_tag( $tag, $handle ) {
return $tag;
}

/**
* Ensure ID attribute is added to printed scripts.
*
* Core started adding the ID attribute in WP 5.5. This attribute is used both by validation logic for sourcing
* attribution as well as in the script and comments sanitizers.
*
* @link https://core.trac.wordpress.org/changeset/48295
* @since 2.2
* @internal
*
* @param string $tag The script tag for the enqueued script.
* @param string $handle The script's registered handle.
* @return string Filtered script.
*/
function amp_ensure_id_attribute_on_script_loader_tag( $tag, $handle ) {
$tag = preg_replace_callback(
'/(<script[^>]*?\ssrc=(["\']).*?\2)([^>]*?>)/',
static function ( $matches ) use ( $handle ) {
if ( false === strpos( $matches[0], 'id=' ) ) {
return $matches[1] . sprintf( ' id="%s"', esc_attr( "$handle-js" ) ) . $matches[3];
}
return $matches[0];
},
$tag,
1
);
return $tag;
}

/**
* Explicitly opt-in to CORS mode by adding the crossorigin attribute to font stylesheet links.
*
Expand Down
4 changes: 4 additions & 0 deletions includes/settings/class-amp-customizer-design-settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
*/

use AmpProject\AmpWP\Option;
use AmpProject\AmpWP\Services;

/**
* Class AMP_Customizer_Design_Settings
Expand Down Expand Up @@ -72,6 +73,9 @@ public static function init() {
* Init customizer.
*/
public static function init_customizer() {
if ( ! Services::get( 'dependency_support' )->has_support() ) {
return;
}
add_action( 'amp_customizer_register_settings', [ __CLASS__, 'register_customizer_settings' ] );
add_action( 'amp_customizer_register_ui', [ __CLASS__, 'register_customizer_ui' ] );
add_action( 'amp_customizer_enqueue_preview_scripts', [ __CLASS__, 'enqueue_customizer_preview_scripts' ] );
Expand Down
28 changes: 24 additions & 4 deletions includes/validation/class-amp-validation-manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -666,7 +666,20 @@ public static function add_validation_error_sourcing() {

add_filter( 'do_shortcode_tag', [ __CLASS__, 'decorate_shortcode_source' ], PHP_INT_MAX, 2 );
add_filter( 'embed_oembed_html', [ __CLASS__, 'decorate_embed_source' ], PHP_INT_MAX, 3 );
add_filter( 'the_content', [ __CLASS__, 'add_block_source_comments' ], 8 ); // The do_blocks() function runs at priority 9.

// The `WP_Block_Type_Registry` class was added in WordPress 5.0.0. Because of that it sometimes caused issues
// on the AMP Validated URL screen when on WordPress 4.9.
if ( class_exists( 'WP_Block_Type_Registry' ) ) {
westonruter marked this conversation as resolved.
Show resolved Hide resolved
add_filter(
'the_content',
[
__CLASS__,
'add_block_source_comments',
],
8
); // The do_blocks() function runs at priority 9.
}

add_filter( 'the_editor', [ __CLASS__, 'filter_the_editor_to_detect_sources' ] );
}

Expand Down Expand Up @@ -938,9 +951,16 @@ protected static function has_dependency( WP_Dependencies $dependencies, $curren
* @return bool
*/
protected static function is_matching_script( DOMElement $element, $script_handle ) {

// Use the ID attribute which was added to printed scripts after WP ?.?.
if ( $element->getAttribute( Attribute::ID ) === "{$script_handle}-js" ) {
return true;
}

if ( ! isset( wp_scripts()->registered[ $script_handle ] ) ) {
return false;
}

$script_dependency = wp_scripts()->registered[ $script_handle ];
if ( empty( $script_dependency->src ) ) {
return false;
Expand Down Expand Up @@ -989,7 +1009,7 @@ public static function locate_sources( DOMNode $node ) {
&&
'link' === $node->nodeName
&&
preg_match( '/(?P<handle>.+)-css$/', (string) $node->getAttribute( 'id' ), $matches )
preg_match( '/(?P<handle>.+)-css$/', (string) $node->getAttribute( Attribute::ID ), $matches )
&&
wp_styles()->query( $matches['handle'] )
);
Expand Down Expand Up @@ -1034,9 +1054,9 @@ static function ( $enqueued_style_source ) use ( $style_handle ) {
&&
$node->firstChild instanceof DOMText
&&
$node->hasAttribute( 'id' )
$node->hasAttribute( Attribute::ID )
&&
preg_match( '/^(?P<handle>.+)-inline-css$/', $node->getAttribute( 'id' ), $matches )
preg_match( '/^(?P<handle>.+)-inline-css$/', $node->getAttribute( Attribute::ID ), $matches )
&&
wp_styles()->query( $matches['handle'] )
&&
Expand Down
Loading