Skip to content

Commit 27a2104

Browse files
authored
Merge pull request #6773 from ampproject/add/wp-back-compat
Add back-compat to old WP versions for new v2.2 features
2 parents 3003385 + ff7e7b7 commit 27a2104

40 files changed

+686
-515
lines changed

.phpstorm.meta.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@
5454
'rest.scannable_urls_controller' => \AmpProject\AmpWP\Validation\ScannableURLsRestController::class,
5555
'rest.validation_counts_controller' => \AmpProject\AmpWP\Validation\ValidationCountsRestController::class,
5656
'sandboxing' => \AmpProject\AmpWP\Sandboxing::class,
57-
'save_post_validation_event' => \AmpProject\AmpWP\Validation\SavePostValidationEvent::class,
5857
'server_timing' => \AmpProject\AmpWP\Instrumentation\ServerTiming::class,
5958
'site_health_integration' => \AmpProject\AmpWP\Admin\SiteHealth::class,
6059
'support' => \AmpProject\AmpWP\Support\SupportCliCommand::class,

assets/src/admin/site-scan-notice/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ function Providers( { children } ) {
4949
optionsRestPath={ OPTIONS_REST_PATH }
5050
populateDefaultValues={ false }
5151
>
52-
<PluginsContextProvider hasErrorBoundary={ true }>
52+
<PluginsContextProvider>
5353
<SiteScanContextProvider
5454
scannableUrlsRestPath={ SCANNABLE_URLS_REST_PATH }
5555
validateNonce={ VALIDATE_NONCE }

assets/src/components/plugins-context-provider/index.js

Lines changed: 10 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,39 +6,22 @@ import PropTypes from 'prop-types';
66
/**
77
* WordPress dependencies
88
*/
9-
import {
10-
createContext,
11-
useContext,
12-
useEffect,
13-
useRef,
14-
useState,
15-
} from '@wordpress/element';
9+
import { createContext, useEffect, useRef, useState } from '@wordpress/element';
1610
import apiFetch from '@wordpress/api-fetch';
17-
18-
/**
19-
* Internal dependencies
20-
*/
21-
import { ErrorContext } from '../error-context-provider';
22-
import { useAsyncError } from '../../utils/use-async-error';
11+
import { addQueryArgs } from '@wordpress/url';
2312

2413
export const Plugins = createContext();
2514

2615
/**
2716
* Plugins context provider.
2817
*
29-
* @param {Object} props Component props.
30-
* @param {any} props.children Component children.
31-
* @param {boolean} props.hasErrorBoundary Whether the component is wrapped in an error boundary.
18+
* @param {Object} props Component props.
19+
* @param {any} props.children Component children.
3220
*/
33-
export function PluginsContextProvider( {
34-
children,
35-
hasErrorBoundary = false,
36-
} ) {
21+
export function PluginsContextProvider( { children } ) {
3722
const [ plugins, setPlugins ] = useState( [] );
3823
const [ fetchingPlugins, setFetchingPlugins ] = useState( null );
39-
40-
const { error, setError } = useContext( ErrorContext );
41-
const { setAsyncError } = useAsyncError();
24+
const [ error, setError ] = useState();
4225

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

6346
try {
6447
const fetchedPlugins = await apiFetch( {
65-
path: '/wp/v2/plugins',
48+
path: addQueryArgs( '/wp/v2/plugins', {
49+
_fields: [ 'author', 'name', 'plugin', 'status', 'version' ],
50+
} ),
6651
} );
6752

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

7863
setError( e );
79-
80-
if ( hasErrorBoundary ) {
81-
setAsyncError( e );
82-
}
83-
84-
return;
8564
}
8665

8766
setFetchingPlugins( false );
8867
} )();
89-
}, [ error, fetchingPlugins, hasErrorBoundary, plugins, setAsyncError, setError ] );
68+
}, [ error, fetchingPlugins, plugins ] );
9069

9170
return (
9271
<Plugins.Provider
@@ -101,5 +80,4 @@ export function PluginsContextProvider( {
10180
}
10281
PluginsContextProvider.propTypes = {
10382
children: PropTypes.any,
104-
hasErrorBoundary: PropTypes.bool,
10583
};

assets/src/components/site-scan-results/plugins-with-amp-incompatibility.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export function PluginsWithAmpIncompatibility( {
7272
<SiteScanSourcesList
7373
sources={ sources }
7474
inactiveSourceNotice={ __( 'This plugin has been deactivated since last site scan.' ) }
75-
uninstalledSourceNotice={ __( 'This plugin has been uninstalled since last site scan.' ) }
75+
uninstalledSourceNotice={ __( 'This plugin has been uninstalled or its metadata is unavailable.' ) }
7676
/>
7777
</SiteScanResults>
7878
);

assets/src/components/site-scan-results/themes-with-amp-incompatibility.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ export function ThemesWithAmpIncompatibility( {
7272
<SiteScanSourcesList
7373
sources={ sources }
7474
inactiveSourceNotice={ __( 'This theme has been deactivated since last site scan.' ) }
75-
uninstalledSourceNotice={ __( 'This theme has been uninstalled since last site scan.' ) }
75+
uninstalledSourceNotice={ __( 'This theme has been uninstalled or its metadata is unavailable.' ) }
7676
/>
7777
</SiteScanResults>
7878
);

assets/src/components/themes-context-provider/index.js

Lines changed: 10 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,39 +6,22 @@ import PropTypes from 'prop-types';
66
/**
77
* WordPress dependencies
88
*/
9-
import {
10-
createContext,
11-
useContext,
12-
useEffect,
13-
useRef,
14-
useState,
15-
} from '@wordpress/element';
9+
import { createContext, useEffect, useRef, useState } from '@wordpress/element';
1610
import apiFetch from '@wordpress/api-fetch';
17-
18-
/**
19-
* Internal dependencies
20-
*/
21-
import { ErrorContext } from '../error-context-provider';
22-
import { useAsyncError } from '../../utils/use-async-error';
11+
import { addQueryArgs } from '@wordpress/url';
2312

2413
export const Themes = createContext();
2514

2615
/**
2716
* Themes context provider.
2817
*
29-
* @param {Object} props Component props.
30-
* @param {any} props.children Component children.
31-
* @param {boolean} props.hasErrorBoundary Whether the component is wrapped in an error boundary.
18+
* @param {Object} props Component props.
19+
* @param {any} props.children Component children.
3220
*/
33-
export function ThemesContextProvider( {
34-
children,
35-
hasErrorBoundary = false,
36-
} ) {
21+
export function ThemesContextProvider( { children } ) {
3722
const [ themes, setThemes ] = useState( [] );
3823
const [ fetchingThemes, setFetchingThemes ] = useState( null );
39-
40-
const { error, setError } = useContext( ErrorContext );
41-
const { setAsyncError } = useAsyncError();
24+
const [ error, setError ] = useState();
4225

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

6346
try {
6447
const fetchedThemes = await apiFetch( {
65-
path: '/wp/v2/themes',
48+
path: addQueryArgs( '/wp/v2/themes', {
49+
_fields: [ 'author', 'name', 'status', 'stylesheet', 'version' ],
50+
} ),
6651
} );
6752

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

7863
setError( e );
79-
80-
if ( hasErrorBoundary ) {
81-
setAsyncError( e );
82-
}
83-
84-
return;
8564
}
8665

8766
setFetchingThemes( false );
8867
} )();
89-
}, [ error, fetchingThemes, hasErrorBoundary, themes, setAsyncError, setError ] );
68+
}, [ error, fetchingThemes, themes ] );
9069

9170
return (
9271
<Themes.Provider
@@ -101,5 +80,4 @@ export function ThemesContextProvider( {
10180
}
10281
ThemesContextProvider.propTypes = {
10382
children: PropTypes.any,
104-
hasErrorBoundary: PropTypes.bool,
10583
};

assets/src/onboarding-wizard/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ export function Providers( { children } ) {
7676
userOptionDeveloperTools={ USER_FIELD_DEVELOPER_TOOLS_ENABLED }
7777
usersResourceRestPath={ USERS_RESOURCE_REST_PATH }
7878
>
79-
<PluginsContextProvider hasErrorBoundary={ true }>
80-
<ThemesContextProvider hasErrorBoundary={ true }>
79+
<PluginsContextProvider>
80+
<ThemesContextProvider>
8181
<SiteScanContextProvider
8282
fetchCachedValidationErrors={ false }
8383
resetOnOptionsChange={ false }

assets/src/settings-page/index.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,8 @@ function Providers( { children } ) {
9393
updatesNonce={ UPDATES_NONCE }
9494
wpAjaxUrl={ wpAjaxUrl }
9595
>
96-
<PluginsContextProvider hasErrorBoundary={ true }>
97-
<ThemesContextProvider hasErrorBoundary={ true }>
96+
<PluginsContextProvider>
97+
<ThemesContextProvider>
9898
<SiteScanContextProvider
9999
fetchCachedValidationErrors={ true }
100100
resetOnOptionsChange={ true }
@@ -277,7 +277,9 @@ function Root( { appRoot } ) {
277277
initialOpen={ 'other-settings' === focusedSection }
278278
>
279279
<MobileRedirection />
280-
<DeveloperTools />
280+
{ HAS_DEPENDENCY_SUPPORT && (
281+
<DeveloperTools />
282+
) }
281283
<DeleteDataAtUninstall />
282284
</AMPDrawer>
283285
<SettingsFooter />

includes/admin/functions.php

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@
55
* @package AMP
66
*/
77

8+
use AmpProject\AmpWP\DependencySupport;
89
use AmpProject\AmpWP\Option;
910
use AmpProject\AmpWP\QueryVar;
11+
use AmpProject\AmpWP\Services;
1012

1113
/**
1214
* Sets up the AMP template editor for the Customizer.
@@ -15,6 +17,39 @@
1517
*/
1618
function amp_init_customizer() {
1719

20+
if ( ! Services::get( 'dependency_support' )->has_support() ) {
21+
// @codeCoverageIgnoreStart
22+
add_action(
23+
'customize_controls_init',
24+
static function () {
25+
global $wp_customize;
26+
if (
27+
Services::get( 'reader_theme_loader' )->is_theme_overridden()
28+
||
29+
array_intersect( $wp_customize->get_autofocus(), [ 'panel' => AMP_Template_Customizer::PANEL_ID ] )
30+
||
31+
isset( $_GET[ QueryVar::AMP_PREVIEW ] ) // phpcs:ignore WordPress.Security.NonceVerification.Recommended
32+
) {
33+
wp_die(
34+
esc_html(
35+
sprintf(
36+
/* translators: %s is minimum WordPress version */
37+
__( 'Customizer for AMP is unavailable due to WordPress being out of date. Please upgrade to WordPress %s or greater.', 'amp' ),
38+
DependencySupport::WP_MIN_VERSION
39+
)
40+
),
41+
esc_html__( 'AMP Customizer Unavailable', 'amp' ),
42+
[
43+
'response' => 503,
44+
'back_link' => true,
45+
]
46+
);
47+
}
48+
}
49+
);
50+
// @codeCoverageIgnoreEnd
51+
}
52+
1853
// Fire up the AMP Customizer.
1954
add_action( 'customize_register', [ AMP_Template_Customizer::class, 'init' ], 500 );
2055

includes/amp-helper-functions.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ function amp_bootstrap_plugin() {
9292
// Ensure async and custom-element/custom-template attributes are present on script tags.
9393
add_filter( 'script_loader_tag', 'amp_filter_script_loader_tag', PHP_INT_MAX, 2 );
9494

95+
// Ensure ID attribute is present in WP<5.5.
96+
if ( version_compare( get_bloginfo( 'version' ), '5.5', '<' ) ) {
97+
add_filter( 'script_loader_tag', 'amp_ensure_id_attribute_on_script_loader_tag', ~PHP_INT_MAX, 2 );
98+
}
99+
95100
// Ensure crossorigin=anonymous is added to font links.
96101
add_filter( 'style_loader_tag', 'amp_filter_font_style_loader_tag_with_crossorigin_anonymous', 10, 4 );
97102

@@ -1157,6 +1162,35 @@ function amp_filter_script_loader_tag( $tag, $handle ) {
11571162
return $tag;
11581163
}
11591164

1165+
/**
1166+
* Ensure ID attribute is added to printed scripts.
1167+
*
1168+
* Core started adding the ID attribute in WP 5.5. This attribute is used both by validation logic for sourcing
1169+
* attribution as well as in the script and comments sanitizers.
1170+
*
1171+
* @link https://core.trac.wordpress.org/changeset/48295
1172+
* @since 2.2
1173+
* @internal
1174+
*
1175+
* @param string $tag The script tag for the enqueued script.
1176+
* @param string $handle The script's registered handle.
1177+
* @return string Filtered script.
1178+
*/
1179+
function amp_ensure_id_attribute_on_script_loader_tag( $tag, $handle ) {
1180+
$tag = preg_replace_callback(
1181+
'/(<script[^>]*?\ssrc=(["\']).*?\2)([^>]*?>)/',
1182+
static function ( $matches ) use ( $handle ) {
1183+
if ( false === strpos( $matches[0], 'id=' ) ) {
1184+
return $matches[1] . sprintf( ' id="%s"', esc_attr( "$handle-js" ) ) . $matches[3];
1185+
}
1186+
return $matches[0];
1187+
},
1188+
$tag,
1189+
1
1190+
);
1191+
return $tag;
1192+
}
1193+
11601194
/**
11611195
* Explicitly opt-in to CORS mode by adding the crossorigin attribute to font stylesheet links.
11621196
*

0 commit comments

Comments
 (0)