diff --git a/src/wp-includes/default-filters.php b/src/wp-includes/default-filters.php index 4b6d9de25fa11..b6482ab148a75 100644 --- a/src/wp-includes/default-filters.php +++ b/src/wp-includes/default-filters.php @@ -565,8 +565,7 @@ add_action( 'init', 'wp_initialize_site_preview_hooks', 1 ); // Calendar widget cache. -add_action( 'save_post', 'delete_get_calendar_cache' ); -add_action( 'delete_post', 'delete_get_calendar_cache' ); +add_action( 'clean_post_cache', 'delete_get_calendar_cache' ); add_action( 'update_option_start_of_week', 'delete_get_calendar_cache' ); add_action( 'update_option_gmt_offset', 'delete_get_calendar_cache' ); diff --git a/src/wp-includes/general-template.php b/src/wp-includes/general-template.php index 47e2aeb2ebb05..736a59204297c 100644 --- a/src/wp-includes/general-template.php +++ b/src/wp-includes/general-template.php @@ -2341,12 +2341,18 @@ function get_calendar( $args = array() ) { ); wp_recursive_ksort( $cache_args ); - $key = md5( serialize( $cache_args ) ); - $cache = wp_cache_get( 'get_calendar', 'calendar' ); - if ( $cache && is_array( $cache ) && isset( $cache[ $key ] ) ) { + if ( ! wp_cache_supports( 'flush_group' ) ) { + $generation = wp_cache_get( 'get_calendar_generation', 'calendar' ); + $cache_args['_generation_'] = $generation ? (int) $generation : 0; + } + + $key = 'get_calendar_' . md5( serialize( $cache_args ) ); + $cache = wp_cache_get( $key, 'calendar' ); + + if ( false !== $cache ) { /** This filter is documented in wp-includes/general-template.php */ - $output = apply_filters( 'get_calendar', $cache[ $key ], $args ); + $output = apply_filters( 'get_calendar', $cache, $args ); if ( $args['display'] ) { echo $output; @@ -2356,10 +2362,6 @@ function get_calendar( $args = array() ) { return $output; } - if ( ! is_array( $cache ) ) { - $cache = array(); - } - $post_type = $args['post_type']; // Quick check. If we have no posts at all, abort! @@ -2376,8 +2378,7 @@ function get_calendar( $args = array() ) { ); if ( ! $gotsome ) { - $cache[ $key ] = ''; - wp_cache_set( 'get_calendar', $cache, 'calendar' ); + wp_cache_set( $key, '', 'calendar' ); return; } } @@ -2390,17 +2391,10 @@ function get_calendar( $args = array() ) { $thismonth = (int) $monthnum; $thisyear = (int) $year; } elseif ( ! empty( $w ) ) { - // We need to get the month from MySQL. $thisyear = (int) substr( $m, 0, 4 ); // It seems MySQL's weeks disagree with PHP's. $d = ( ( $w - 1 ) * 7 ) + 6; - $thismonth = (int) $wpdb->get_var( - $wpdb->prepare( - "SELECT DATE_FORMAT((DATE_ADD('%d0101', INTERVAL %d DAY) ), '%%m')", - $thisyear, - $d - ) - ); + $thismonth = (int) gmdate( 'm', strtotime( "{$thisyear}-01-01 + {$d} days" ) ); } elseif ( ! empty( $m ) ) { $thisyear = (int) substr( $m, 0, 4 ); if ( strlen( $m ) < 6 ) { @@ -2583,8 +2577,7 @@ function get_calendar( $args = array() ) { $calendar_output .= ' '; - $cache[ $key ] = $calendar_output; - wp_cache_set( 'get_calendar', $cache, 'calendar' ); + wp_cache_set( $key, $calendar_output, 'calendar' ); /** * Filters the HTML calendar output. @@ -2618,7 +2611,17 @@ function get_calendar( $args = array() ) { * @since 2.1.0 */ function delete_get_calendar_cache() { - wp_cache_delete( 'get_calendar', 'calendar' ); + if ( wp_cache_supports( 'flush_group' ) ) { + wp_cache_flush_group( 'calendar' ); + return; + } + + // Fallback for object cache implementations that do not support flushing groups. + // wp_cache_incr() returns false when the key does not exist in some backends + // (e.g. Memcached), so initialize the counter on the first invalidation. + if ( false === wp_cache_incr( 'get_calendar_generation', 1, 'calendar' ) ) { + wp_cache_add( 'get_calendar_generation', 1, 'calendar' ); + } } /** diff --git a/tests/phpunit/tests/general/getCalendar.php b/tests/phpunit/tests/general/getCalendar.php index a8a3d1361f494..f9b149233ce6f 100644 --- a/tests/phpunit/tests/general/getCalendar.php +++ b/tests/phpunit/tests/general/getCalendar.php @@ -183,7 +183,7 @@ public function test_get_calendar_caching_accounts_for_equivalent_args() { public function test_get_calendar_backwards_compatibility() { $first_calendar_html = get_echo( 'get_calendar', array( false ) ); - wp_cache_delete( 'get_calendar', 'calendar' ); + delete_get_calendar_cache(); $second_calendar_html = get_calendar( false, false ); @@ -192,4 +192,75 @@ public function test_get_calendar_backwards_compatibility() { $this->assertStringContainsString( '