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 button into Site Health to reenable CSS transient caching #4522

Merged
merged 30 commits into from
Apr 10, 2020
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
13359f8
Add button into Site Health to reenable CSS transient caching
schlessera Apr 3, 2020
c19c1ac
Use wp_jsonencode() instead of addslashes()
schlessera Apr 4, 2020
7b56dd1
Remove unneeded PHPCS exception
schlessera Apr 4, 2020
d1e2aa2
Use wp.ajax and heredoc for JS script
schlessera Apr 4, 2020
cc2bd07
Update styling
schlessera Apr 4, 2020
e820e65
Add capability check
schlessera Apr 4, 2020
8869d99
Use current_user_can()
schlessera Apr 4, 2020
24fa804
Add CSS transient caching option to options manager validation
schlessera Apr 4, 2020
ce1682f
Fix code style issues
schlessera Apr 4, 2020
a258998
Only read Option::DISABLE_CSS_TRANSIENT_CACHING if exists
schlessera Apr 6, 2020
3ae8fed
Remove <script> tags from JS code passed to wp_add_inline_script()
schlessera Apr 7, 2020
41bf7a9
Remove pesky 2nd blank line
schlessera Apr 9, 2020
61f7d8b
Rename AjaxAction to ReenableCssTransientCachingAjaxAction
schlessera Apr 9, 2020
25ca0c8
Remove $access and default to authenticated users only
schlessera Apr 9, 2020
caea4dd
Remove $scope and default to admin backend only
schlessera Apr 9, 2020
fcaeffa
Remove $action and hardcode as const
schlessera Apr 9, 2020
d60da1e
Remove $callback and move method into AjaxAction
schlessera Apr 9, 2020
50e1ca1
Remove $selector and hardcode as const
schlessera Apr 9, 2020
f0e1db0
Only register AJAX action on site-health.php screen
schlessera Apr 9, 2020
9c41211
Use tabs instead of spaces to indent CSS
schlessera Apr 9, 2020
66a7b73
Escape button label translations
schlessera Apr 9, 2020
de1038c
Add nonce verification
schlessera Apr 9, 2020
f94dbf3
Disable button after click
schlessera Apr 9, 2020
5cbe86b
Use DOMContentLoaded instead of a timeout
schlessera Apr 9, 2020
712c1f2
Indent JS code with tabs instead of spaces
schlessera Apr 9, 2020
a52b391
Document $hook_suffix argument
schlessera Apr 9, 2020
daa92ca
Merge branch 'develop' of github.com:ampproject/amp-wp into add-css-c…
westonruter Apr 10, 2020
b9a1eb1
Flesh out guidance for CSS transient caching
westonruter Apr 10, 2020
ff9a37e
Avoid string interpolation for JS injection to better ensure late-esc…
westonruter Apr 10, 2020
a26112b
Use nowdoc instead of heredoc
westonruter Apr 10, 2020
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
8 changes: 8 additions & 0 deletions includes/options/class-amp-options-manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
* @package AMP
*/

use AmpProject\AmpWP\Option;

/**
* Class AMP_Options_Manager
*/
Expand Down Expand Up @@ -262,6 +264,12 @@ public static function validate_options( $new_options ) {
}
}

if ( array_key_exists( Option::DISABLE_CSS_TRANSIENT_CACHING, $new_options ) && true === $new_options[ Option::DISABLE_CSS_TRANSIENT_CACHING ] ) {
$options[ Option::DISABLE_CSS_TRANSIENT_CACHING ] = true;
} else {
unset( $options[ Option::DISABLE_CSS_TRANSIENT_CACHING ] );
}

// Store the current version with the options so we know the format.
$options['version'] = AMP__VERSION;

Expand Down
126 changes: 126 additions & 0 deletions src/Admin/ReenableCssTransientCachingAjaxAction.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<?php
/**
* Class ReenableCssTransientCachingAjaxAction.
*
* @package AmpProject\AmpWP
*/

namespace AmpProject\AmpWP\Admin;

use AMP_Options_Manager;
use AmpProject\AmpWP\Option;

/**
* Base class to define a new AJAX action.
*
* @package AmpProject\AmpWP
*/
final class ReenableCssTransientCachingAjaxAction {

/**
* Action to use for enqueueing the JS logic at the backend.
*
* @var string
*/
const BACKEND_ENQUEUE_ACTION = 'admin_enqueue_scripts';

/**
* AJAX action name to use.
*
* @var string
*/
const AJAX_ACTION = 'amp_reenable_css_transient_caching';

/**
* Selector to attach the click handler to.
*
* @var string
*/
const SELECTOR = 'a.reenable-css-transient-caching';

/**
* Register the AJAX action with the WordPress system.
*/
public function register() {
add_action( static::BACKEND_ENQUEUE_ACTION, [ $this, 'register_ajax_script' ] );
add_action( 'wp_ajax_' . self::AJAX_ACTION, [ $this, 'reenable_css_transient_caching' ] );
}

/**
* Register the AJAX logic.
*
* @param string $hook_suffix Hook suffix to identify from what admin page the call is coming from.
*/
public function register_ajax_script( $hook_suffix ) {
if ( 'site-health.php' !== $hook_suffix ) {
return;
}

$script = <<< JS_SCRIPT
westonruter marked this conversation as resolved.
Show resolved Hide resolved
;( function () {
window.addEventListener( 'DOMContentLoaded', ( event ) => {
var selector = SELECTOR;
( document.querySelectorAll( selector ) || [] )
.forEach( ( element ) => {
element.addEventListener( 'click', function ( event ) {
event.preventDefault();
if ( element.classList.contains( 'disabled' ) ) {
return;
}
wp.ajax.post( ACTION, ARGUMENTS )
.done( function () {
element.classList.remove( 'ajax-failure' );
element.classList.add( 'ajax-success' )
element.classList.add( 'disabled' )
} )
.fail( function () {
element.classList.remove( 'ajax-success' );
element.classList.add( 'ajax-failure' )
element.classList.add( 'disabled' )
} );
} );
} );
} );
} )();
JS_SCRIPT;

$replacements = array_map(
'wp_json_encode',
[
'SELECTOR' => self::SELECTOR,
'ACTION' => self::AJAX_ACTION,
'ARGUMENTS' => [ 'nonce' => wp_create_nonce( self::AJAX_ACTION ) ],
]
);

$script = str_replace(
array_keys( $replacements ),
array_values( $replacements ),
$script
);

wp_enqueue_script( 'wp-util' );
wp_add_inline_script( 'wp-util', $script );
}

/**
* Re-enable the CSS Transient caching.
*
* This is triggered via an AJAX call from the Site Health panel.
*/
public function reenable_css_transient_caching() {
check_ajax_referer( self::AJAX_ACTION, 'nonce' );

if ( ! current_user_can( 'manage_options' ) ) {
wp_send_json_error( 'Unauthorized.', 401 );
}

$result = AMP_Options_Manager::update_option( Option::DISABLE_CSS_TRANSIENT_CACHING, false );

if ( false === $result ) {
wp_send_json_error( 'CSS transient caching could not be re-enabled.', 500 );
}

wp_send_json_success( 'CSS transient caching was re-enabled.', 200 );
}
}
95 changes: 85 additions & 10 deletions src/Admin/SiteHealth.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ public function init() {
add_filter( 'site_status_tests', [ $this, 'add_tests' ] );
add_filter( 'debug_information', [ $this, 'add_debug_information' ] );
add_filter( 'site_status_test_php_modules', [ $this, 'add_extensions' ] );
add_action( 'admin_print_styles', [ $this, 'add_styles' ] );

( new ReenableCssTransientCachingAjaxAction() )->register();
}

/**
Expand Down Expand Up @@ -62,6 +65,21 @@ public function add_tests( $tests ) {
return $tests;
}

/**
* Get action HTML for the link to learn more about persistent object caching.
*
* @return string HTML.
*/
private function get_persistent_object_cache_learn_more_action() {
return sprintf(
'<p><a href="%1$s" target="_blank" rel="noopener noreferrer">%2$s <span class="screen-reader-text">%3$s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a></p>',
esc_url( 'https://make.wordpress.org/hosting/handbook/handbook/performance/#object-cache' ),
esc_html__( 'Learn more about persistent object caching', 'amp' ),
/* translators: The accessibility text. */
esc_html__( '(opens in a new tab)', 'amp' )
);
}

/**
* Gets the test result data for whether there is a persistent object cache.
*
Expand All @@ -75,13 +93,7 @@ public function persistent_object_cache() {
'color' => $is_using_object_cache ? 'green' : 'orange',
],
'description' => esc_html__( 'The AMP plugin performs at its best when persistent object cache is enabled. Object caching is used to more effectively store image dimensions and parsed CSS.', 'amp' ),
'actions' => sprintf(
'<p><a href="%1$s" target="_blank" rel="noopener noreferrer">%2$s <span class="screen-reader-text">%3$s</span><span aria-hidden="true" class="dashicons dashicons-external"></span></a></p>',
'https://codex.wordpress.org/Class_Reference/WP_Object_Cache#Persistent_Caching',
esc_html__( 'Learn more about persistent object caching', 'amp' ),
/* translators: The accessibility text. */
esc_html__( '(opens in a new tab)', 'amp' )
),
'actions' => $this->get_persistent_object_cache_learn_more_action(),
'test' => 'amp_persistent_object_cache',
];

Expand Down Expand Up @@ -240,11 +252,13 @@ public function icu_version() {
* @return array The test data.
*/
public function css_transient_caching() {
$disabled = AMP_Options_Manager::get_option( Option::DISABLE_CSS_TRANSIENT_CACHING, false );

if ( wp_using_ext_object_cache() ) {
$status = 'good';
$color = 'blue';
$label = __( 'Transient caching of parsed stylesheets is not used due to external object cache', 'amp' );
} elseif ( AMP_Options_Manager::get_option( Option::DISABLE_CSS_TRANSIENT_CACHING, false ) ) {
} elseif ( $disabled ) {
$status = 'recommended';
$color = 'orange';
$label = __( 'Transient caching of parsed stylesheets is disabled', 'amp' );
Expand All @@ -254,16 +268,40 @@ public function css_transient_caching() {
$label = __( 'Transient caching of parsed stylesheets is enabled', 'amp' );
}

return [
$data = [
'badge' => [
'label' => esc_html__( 'AMP', 'amp' ),
'color' => $color,
],
'description' => esc_html__( 'On sites which have highly variable CSS and are not using a persistent object cache, the transient caching of parsed stylesheets may be automatically disabled in order to prevent a site from filling up its wp_options table with too many transients.', 'amp' ),
'description' => wp_kses(
sprintf(
/* translators: %1$s is wp_options table, %2$s is the amp_css_transient_monitoring_threshold filter, and %3$s is the amp_css_transient_monitoring_sampling_range filter */
__( 'On sites which have highly variable CSS and are not using a persistent object cache, the transient caching of parsed stylesheets may be automatically disabled in order to prevent a site from filling up its <code>%1$s</code> table with too many transients. Examples of highly variable CSS include dynamically-generated style rules with selectors referring to user IDs or elements being given randomized background colors. There are two filters which may be used to configure the CSS transient monitoring: <code>%2$s</code> and <code>%3$s</code>.', 'amp' ),
'wp_options',
'amp_css_transient_monitoring_threshold',
'amp_css_transient_monitoring_sampling_range'
),
[
'code' => [],
]
),
'test' => 'amp_css_transient_caching',
'status' => $status,
'label' => esc_html( $label ),
];

if ( $disabled ) {
$data['description'] .= ' ' . esc_html__( 'If you have identified and eliminated the cause of the variable CSS, please re-enable transient caching to reduce the amount of CSS processing required to generate AMP pages.', 'amp' );
$data['actions'] = sprintf(
'<p><a class="button reenable-css-transient-caching" href="#">%s</a><span class="dashicons dashicons-yes success-icon"></span><span class="dashicons dashicons-no failure-icon"></span><span class="success-text">%s</span><span class="failure-text">%s</span></p>',
esc_html__( 'Re-enable transient caching', 'amp' ),
esc_html__( 'Reload the page to refresh the diagnostic check.', 'amp' ),
esc_html__( 'The operation failed, please reload the page and try again.', 'amp' )
);
$data['actions'] .= $this->get_persistent_object_cache_learn_more_action();
}

return $data;
}

/**
Expand Down Expand Up @@ -502,4 +540,41 @@ public function add_extensions( $extensions ) {
]
);
}

/**
* Add needed styles for the Site Health integration.
*/
public function add_styles() {
echo '
<style>
.wp-core-ui .button.reenable-css-transient-caching ~ .success-icon,
.wp-core-ui .button.reenable-css-transient-caching ~ .success-text,
.wp-core-ui .button.reenable-css-transient-caching ~ .failure-icon,
.wp-core-ui .button.reenable-css-transient-caching ~ .failure-text {
display: none;
}

.wp-core-ui .button.reenable-css-transient-caching ~ .success-icon,
.wp-core-ui .button.reenable-css-transient-caching ~ .failure-icon {
font-size: xx-large;
padding-right: 1rem;
}

.wp-core-ui .button.reenable-css-transient-caching.ajax-success ~ .success-icon,
.wp-core-ui .button.reenable-css-transient-caching.ajax-success ~ .success-text,
.wp-core-ui .button.reenable-css-transient-caching.ajax-failure ~ .failure-icon,
.wp-core-ui .button.reenable-css-transient-caching.ajax-failure ~ .failure-text {
display: inline-block;
}

.wp-core-ui .button.reenable-css-transient-caching.ajax-success ~ .success-icon {
color: #46b450;
}

.wp-core-ui .button.reenable-css-transient-caching.ajax-failure ~ .failure-icon {
color: #dc3232;
}
</style>
';
}
}