From 8ef69e105ba611f83c4f9e0365b0c4ff2e25ce6b Mon Sep 17 00:00:00 2001 From: Chris Reynolds Date: Tue, 6 Aug 2024 10:57:59 -0600 Subject: [PATCH] [BUGS-8452] add callback info to filtered message (#292) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add a new function that will get the filter callback name this way it's easier to debug because we can show people where they've added the filter * alter the filtered message with the filter callback name(s) if it's in an anonymous function, we note that. * handle the anonymous function string early so we don't need to reset it to the string we want to output later * if one callaback, wrap in code tags or just output as plaintext (if anonymous) * drop handling the 'an anonymous function' transform * add test filter callbacks * add tests * adjust linting * remove $priority not used * bump tested-up-to * apparently this is a gutenberg thing * WP 6.7 changes the output of human_time_diff * strip out alpha, beta, rc, etc tags from version these aren't valid versions, so version_compare freaks out and (incorrectly) flags 6.7-alpha-whatever as less than 6.7 🤦‍♂️ --- README.md | 2 +- inc/admin-interface.php | 71 ++++++++++++++++++++++++-- readme.txt | 2 +- tests/phpunit/test-admin-interface.php | 50 ++++++++++++++++-- 4 files changed, 114 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 391f62f..aa2ad88 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ **Contributors:** [getpantheon](https://profiles.wordpress.org/getpantheon), [danielbachhuber](https://profiles.wordpress.org/danielbachhuber), [kporras07](https://profiles.wordpress.org/kporras07), [jspellman](https://profiles.wordpress.org/jspellman/), [jazzs3quence](https://profiles.wordpress.org/jazzs3quence/), [ryanshoover](https://profiles.wordpress.org/ryanshoover/), [rwagner00](https://profiles.wordpress.org/rwagner00/), [pwtyler](https://profiles.wordpress.org/pwtyler) **Tags:** pantheon, cdn, cache **Requires at least:** 6.4 -**Tested up to:** 6.5.3 +**Tested up to:** 6.6.1 **Stable tag:** 2.0.1-dev **License:** GPLv2 or later **License URI:** http://www.gnu.org/licenses/gpl-2.0.html diff --git a/inc/admin-interface.php b/inc/admin-interface.php index 8cd0b24..1943146 100644 --- a/inc/admin-interface.php +++ b/inc/admin-interface.php @@ -86,6 +86,55 @@ function add_max_age_setting_header() { return ob_get_clean(); } +/** + * Get the callback(s) hooked to pantheon_cache_default_max_age, if one exists. + * + * @since 2.1.0 + * @return string + */ +function get_pantheon_cache_filter_callback() { + global $wp_filter; + $hook = 'pantheon_cache_default_max_age'; + $output = ''; + + if ( ! has_filter( $hook ) ) { + return $output; + } + + $callback_functions = []; + if ( isset( $wp_filter[ $hook ] ) ) { + foreach ( $wp_filter[ $hook ]->callbacks as $callbacks ) { + foreach ( $callbacks as $callback ) { + if ( is_string( $callback['function'] ) ) { + // Function name. + $callback_functions[] = $callback['function']; + } elseif ( is_array( $callback['function'] ) ) { + // Method call. + $class = is_object( $callback['function'][0] ) ? get_class( $callback['function'][0] ) : $callback['function'][0]; + $method = $callback['function'][1]; + $callback_functions[] = "$class::$method"; + } else { + $callback_functions[] = __( 'an anonymous function', 'pantheon-advanced-page-cache' ); + } + } + } + } + + // Count the callbacks and if there's only one, return the name (if able). + $callbacks_count = count( $callback_functions ); + if ( $callbacks_count === 1 ) { + return stripos( $callback_functions[0], 'an anonymous function' ) === false ? "{$callback_functions[0]}" : $callback_functions[0]; + } + + // If there are multiple callbacks, format the output. + foreach ( $callback_functions as $index => $callback ) { + $callback = stripos( $callback, 'anonymous' ) !== false ? $callback : "$callback"; + $output .= $index === $callbacks_count - 1 ? __( 'and', 'pantheon-advanced-page-cache' ) . ' ' . $callback : $callback . ', '; + } + + return $output; +} + /** * Add a description to the max-age setting field. * @@ -94,15 +143,27 @@ function add_max_age_setting_header() { */ function add_max_age_setting_description() { $is_filtered = has_filter( 'pantheon_cache_default_max_age' ); + $filter_callback = get_pantheon_cache_filter_callback(); + $filtered_message = ''; $above_recommended_message = __( 'Your cache maximum age is currently above the recommended value.', 'pantheon-advanced-page-cache' ); $below_recommended_message = __( 'Your cache maximum age is currently below the recommended value.', 'pantheon-advanced-page-cache' ); $recommended_message = __( 'Your cache maximum age is currently set to the recommended value.', 'pantheon-advanced-page-cache' ); $recommendation_message = get_current_max_age() > WEEK_IN_SECONDS ? $above_recommended_message : ( get_current_max_age() < WEEK_IN_SECONDS ? $below_recommended_message : $recommended_message ); - $filtered_message = $is_filtered ? sprintf( - // translators: %s is the humanized max-age. - __( 'This value has been hardcoded to %s via a filter.', 'pantheon-advanced-page-cache' ), - '' . humanized_max_age() . '' - ) : ''; + + if ( $is_filtered ) { + // Set the message to name the callback(s). + $filtered_message = ! empty( $filter_callback ) ? sprintf( + // translators: %1$s is the humanized max-age, %2$s is the callback function(s). + __( 'This value has been hardcoded to %1$s via a filter hooked to %2$s in your code.', 'pantheon-advanced-page-cache' ), + '' . humanized_max_age() . '', + $filter_callback + ) : sprintf( + // translators: %s is the humanized max-age. + __( 'This value has been hardcoded to %s via a filter.', 'pantheon-advanced-page-cache' ), + '' . humanized_max_age() . '' + ); // If there's no callback, we'll just note that it's been hardcoded. This shouldn't ever happen. + } + $pantheon_cache = get_option( 'pantheon-cache', [] ); $has_custom_ttl = isset( $pantheon_cache['default_ttl'] ) && ! array_key_exists( $pantheon_cache['default_ttl'], max_age_options() ); $filtered_message .= $has_custom_ttl && ! $is_filtered ? '
' . __( 'Warning:The cache max age is not one of the recommended values. If this is not intentional, you should remove this custom value and save the settings, then select one of the options from the dropdown.', 'pantheon-advanced-page-cache' ) : ''; diff --git a/readme.txt b/readme.txt index a5066d5..44c193b 100644 --- a/readme.txt +++ b/readme.txt @@ -2,7 +2,7 @@ Contributors: getpantheon, danielbachhuber, kporras07, jspellman, jazzs3quence, ryanshoover, rwagner00, pwtyler Tags: pantheon, cdn, cache Requires at least: 6.4 -Tested up to: 6.5.3 +Tested up to: 6.6.1 Stable tag: 2.0.1-dev License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html diff --git a/tests/phpunit/test-admin-interface.php b/tests/phpunit/test-admin-interface.php index 29c51a7..5f5ba55 100644 --- a/tests/phpunit/test-admin-interface.php +++ b/tests/phpunit/test-admin-interface.php @@ -11,6 +11,20 @@ * Tests for the admin interface namespace.. */ class Admin_Interface_Functions extends \Pantheon_Advanced_Page_Cache_Testcase { + /** + * Get the WordPress version-compatible string for "5 minutes". + */ + private function get_five_minutes() { + $wp_version = get_bloginfo( 'version' ); + + // If the version contains a string like -alpha, -beta, etc., strip it. + $wp_version = preg_replace( '/-.*/', '', $wp_version ); + + // WordPress 6.7 changed the string for "5 mins" to "5 minutes". + $five_mins = version_compare( $wp_version, '6.7', '<' ) ? '5 mins' : '5 minutes'; + return $five_mins; + } + /** * Set up tests. */ @@ -46,6 +60,7 @@ public function test_get_max_age() { */ public function test_site_health_tests_300_seconds() { $tests = apply_filters( 'site_status_tests', [] ); + $five_mins = $this->get_five_minutes(); $this->assertContains( 'pantheon_edge_cache', array_keys( $tests['direct'] ) ); @@ -53,7 +68,8 @@ public function test_site_health_tests_300_seconds() { $test_results = test_cache_max_age(); $this->assertEquals( 'recommended', $test_results['status'] ); $this->assertEquals( 'red',$test_results['badge']['color'] ); - $this->assertStringContainsString( '5 mins', $test_results['description'] ); + + $this->assertStringContainsString( $five_mins, $test_results['description'] ); $this->assertStringContainsString( 'We recommend increasing to 1 week', $test_results['description'] ); } @@ -99,8 +115,10 @@ public function test_humanized_max_age( $max_age, $expected ) { * @return array */ public function humanized_max_age_provider() { + $five_mins = $this->get_five_minutes(); + var_dump( $five_mins ); return [ - [ 300, '5 mins' ], // 300 seconds is humanized to 5 mins. + [ 300, $five_mins ], // 300 seconds is humanized to 5 mins. [ 5 * DAY_IN_SECONDS, '5 days' ], [ WEEK_IN_SECONDS, '1 week' ], ]; @@ -328,6 +346,14 @@ public function test_add_max_age_setting_description( $max_age, $expected ) { add_filter( 'pantheon_cache_default_max_age', function() { return 10 * DAY_IN_SECONDS; } ); + } elseif ( $max_age === 'multiple-filters-below' ) { + add_filter( 'pantheon_cache_default_max_age', [ $this, 'reset_cache_max_age' ] ); + add_filter( 'pantheon_cache_default_max_age', [ $this, 'another_function' ] ); + add_filter( 'pantheon_cache_default_max_age', function() { + return 3 * DAY_IN_SECONDS; + } ); + } elseif ( $max_age === 'just-named-filters' ) { + add_filter( 'pantheon_cache_default_max_age', [ $this, 'reset_cache_max_age' ] ); } else { update_option( 'pantheon-cache', [ 'default_ttl' => $max_age ] ); } @@ -343,8 +369,10 @@ public function test_add_max_age_setting_description( $max_age, $expected ) { */ public function add_max_age_setting_description_provider() { return [ - [ 'filter-below', 'Your cache maximum age is currently below the recommended value. This value has been hardcoded to 3 days via a filter.' ], - [ 'filter-above', 'Your cache maximum age is currently above the recommended value. This value has been hardcoded to 1 week via a filter.' ], + [ 'filter-below', 'Your cache maximum age is currently below the recommended value. This value has been hardcoded to 3 days via a filter hooked to an anonymous function in your code.' ], + [ 'filter-above', 'Your cache maximum age is currently above the recommended value. This value has been hardcoded to 1 week via a filter hooked to an anonymous function in your code.' ], + [ 'multiple-filters-below', 'Your cache maximum age is currently below the recommended value. This value has been hardcoded to 3 days via a filter hooked to Pantheon_Advanced_Page_Cache\Admin_Interface\Admin_Interface_Functions::reset_cache_max_age, Pantheon_Advanced_Page_Cache\Admin_Interface\Admin_Interface_Functions::another_function, and an anonymous function in your code.' ], + [ 'just-named-filters', 'Your cache maximum age is currently below the recommended value. This value has been hardcoded to 1 second via a filter hooked to Pantheon_Advanced_Page_Cache\Admin_Interface\Admin_Interface_Functions::reset_cache_max_age in your code.' ], [ 600, 'Your cache maximum age is currently below the recommended value.
Warning:The cache max age is not one of the recommended values.' ], [ WEEK_IN_SECONDS, 'Your cache maximum age is currently set to the recommended value.' ], [ MONTH_IN_SECONDS, 'Your cache maximum age is currently above the recommended value.' ], @@ -352,6 +380,20 @@ public function add_max_age_setting_description_provider() { ]; } + /** + * Filter callback for testing pantheon_cache_default_max_age. + */ + public function reset_cache_max_age() { + return 0; + } + + /** + * Filter callback for testing pantheon_cache_default_max_age. + */ + public function another_function() { + return 42; + } + /** * Test the update_default_ttl_input function. Check the input type if the max age has been filtered. *