WordPress.org

Make WordPress Core

Changeset 38925


Ignore:
Timestamp:
10/25/2016 08:47:06 PM (20 months ago)
Author:
rachelbaker
Message:

Feeds: Always return a valid timestamp for the Last-Modified header of comment or post feeds.

Fixes bug where an invalid Last-Modified value would be returned in feed requests for sites that had 0 items to return. Comment or post feeds will now return the current timestamp as the Last-Modified header value. Example: a request for the comments feed for a site without any comments.

Replaced use of the local static variable $cache_lastcommentmodified to store the modified date in get_lastcommentmodified() with the Object Cache API. The get_lastcommentmodified() function returns early if there is a cached value and returns false if there where no comments found. Introduced _clear_modified_cache_on_transition_comment_status() to flush the lastcommentmodified cache key when a comment enters or leaves approval status. In get_lastpostmodified() return early if there is a cached value and return false if there are no posts found.

Props swissspidy, rachelbaker, dllh, leobaiano.
Fixes #38027.

Location:
trunk
Files:
1 added
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-includes/class-wp.php

    r38671 r38925  
    423423            $headers['Content-Type'] = feed_content_type( $type ) . '; charset=' . get_option( 'blog_charset' );
    424424
    425             // We're showing a feed, so WP is indeed the only thing that last changed
    426             if ( !empty($this->query_vars['withcomments'])
    427                 || false !== strpos( $this->query_vars['feed'], 'comments-' )
    428                 || ( empty($this->query_vars['withoutcomments'])
    429                     && ( !empty($this->query_vars['p'])
    430                         || !empty($this->query_vars['name'])
    431                         || !empty($this->query_vars['page_id'])
    432                         || !empty($this->query_vars['pagename'])
    433                         || !empty($this->query_vars['attachment'])
    434                         || !empty($this->query_vars['attachment_id'])
    435                     )
    436                 )
    437             )
    438                 $wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastcommentmodified('GMT'), 0).' GMT';
    439             else
    440                 $wp_last_modified = mysql2date('D, d M Y H:i:s', get_lastpostmodified('GMT'), 0).' GMT';
     425            // We're showing a feed, so WP is indeed the only thing that last changed.
     426            if ( ! empty( $this->query_vars['withcomments'] )
     427                 || false !== strpos( $this->query_vars['feed'], 'comments-' )
     428                 || ( empty( $this->query_vars['withoutcomments'] )
     429                      && ( ! empty( $this->query_vars['p'] )
     430                           || ! empty( $this->query_vars['name'] )
     431                           || ! empty( $this->query_vars['page_id'] )
     432                           || ! empty( $this->query_vars['pagename'] )
     433                           || ! empty( $this->query_vars['attachment'] )
     434                           || ! empty( $this->query_vars['attachment_id'] )
     435                      )
     436                 )
     437            ) {
     438                $wp_last_modified = mysql2date( 'D, d M Y H:i:s', get_lastcommentmodified( 'GMT' ), false );
     439            } else {
     440                $wp_last_modified = mysql2date( 'D, d M Y H:i:s', get_lastpostmodified( 'GMT' ), false );
     441            }
     442
     443            if ( ! $wp_last_modified ) {
     444                $wp_last_modified = date( 'D, d M Y H:i:s' );
     445            }
     446
     447            $wp_last_modified .= ' GMT';
     448
    441449            $wp_etag = '"' . md5($wp_last_modified) . '"';
    442450            $headers['Last-Modified'] = $wp_last_modified;
  • trunk/src/wp-includes/comment.php

    r38852 r38925  
    294294 *
    295295 * @since 1.5.0
     296 * @since 4.7.0 Replaced caching the modified date in a local static variable
     297 *              with the Object Cache API.
    296298 *
    297299 * @global wpdb $wpdb WordPress database abstraction object.
    298  * @staticvar array $cache_lastcommentmodified
    299  *
    300  * @param string $timezone Which timezone to use in reference to 'gmt', 'blog',
    301  *      or 'server' locations.
    302  * @return string Last comment modified date.
    303  */
    304 function get_lastcommentmodified($timezone = 'server') {
     300 *
     301 * @param string $timezone Which timezone to use in reference to 'gmt', 'blog', or 'server' locations.
     302 * @return string|false Last comment modified date on success, false on failure.
     303 */
     304function get_lastcommentmodified( $timezone = 'server' ) {
    305305    global $wpdb;
    306     static $cache_lastcommentmodified = array();
    307 
    308     if ( isset($cache_lastcommentmodified[$timezone]) )
    309         return $cache_lastcommentmodified[$timezone];
    310 
    311     $add_seconds_server = date('Z');
    312 
    313     switch ( strtolower($timezone)) {
     306
     307    $timezone = strtolower( $timezone );
     308    $key = "lastcommentmodified:$timezone";
     309
     310    $comment_modified_date = wp_cache_get( $key, 'timeinfo' );
     311    if ( false !== $comment_modified_date ) {
     312        return $comment_modified_date;
     313    }
     314
     315    switch ( $timezone ) {
    314316        case 'gmt':
    315             $lastcommentmodified = $wpdb->get_var("SELECT comment_date_gmt FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1");
     317            $comment_modified_date = $wpdb->get_var( "SELECT comment_date_gmt FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1" );
    316318            break;
    317319        case 'blog':
    318             $lastcommentmodified = $wpdb->get_var("SELECT comment_date FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1");
     320            $comment_modified_date = $wpdb->get_var( "SELECT comment_date FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1" );
    319321            break;
    320322        case 'server':
    321             $lastcommentmodified = $wpdb->get_var($wpdb->prepare("SELECT DATE_ADD(comment_date_gmt, INTERVAL %s SECOND) FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1", $add_seconds_server));
     323            $add_seconds_server = date( 'Z' );
     324
     325            $comment_modified_date = $wpdb->get_var( $wpdb->prepare( "SELECT DATE_ADD(comment_date_gmt, INTERVAL %s SECOND) FROM $wpdb->comments WHERE comment_approved = '1' ORDER BY comment_date_gmt DESC LIMIT 1", $add_seconds_server ) );
    322326            break;
    323327    }
    324328
    325     $cache_lastcommentmodified[$timezone] = $lastcommentmodified;
    326 
    327     return $lastcommentmodified;
     329    if ( $comment_modified_date ) {
     330        wp_cache_set( $key, $comment_modified_date, 'timeinfo' );
     331
     332        return $comment_modified_date;
     333    }
     334
     335    return false;
    328336}
    329337
     
    15741582
    15751583/**
     1584 * Clear the lastcommentmodified cached value when a comment status is changed.
     1585 *
     1586 * Deletes the lastcommentmodified cache key when a comment enters or leaves
     1587 * 'approved' status.
     1588 *
     1589 * @since 4.7.0
     1590 * @access private
     1591 *
     1592 * @param string $new_status The new comment status.
     1593 * @param string $old_status The old comment status.
     1594 */
     1595function _clear_modified_cache_on_transition_comment_status( $new_status, $old_status ) {
     1596    if ( 'approved' === $new_status || 'approved' === $old_status ) {
     1597        foreach ( array( 'server', 'gmt', 'blog' ) as $timezone ) {
     1598            wp_cache_delete( "lastcommentmodified:$timezone", 'timeinfo' );
     1599        }
     1600    }
     1601}
     1602
     1603/**
    15761604 * Get current commenter's name, email, and URL.
    15771605 *
     
    16821710    if ( $comment_approved == 1 ) {
    16831711        wp_update_comment_count( $comment_post_ID );
     1712
     1713        foreach ( array( 'server', 'gmt', 'blog' ) as $timezone ) {
     1714            wp_cache_delete( "lastcommentmodified:$timezone", 'timeinfo' );
     1715        }
    16841716    }
    16851717
  • trunk/src/wp-includes/default-filters.php

    r38832 r38925  
    214214add_filter( 'xmlrpc_pingback_error',    'xmlrpc_pingback_error'               );
    215215add_filter( 'title_save_pre',           'trim'                                );
     216
     217add_action( 'transition_comment_status', '_clear_modified_cache_on_transition_comment_status', 10, 2 );
    216218
    217219add_filter( 'http_request_host_is_external',    'allowed_http_request_hosts', 10, 2 );
  • trunk/src/wp-includes/feed-atom-comments.php

    r37674 r38925  
    3838    <subtitle type="text"><?php bloginfo_rss('description'); ?></subtitle>
    3939
    40     <updated><?php echo mysql2date('Y-m-d\TH:i:s\Z', get_lastcommentmodified('GMT'), false); ?></updated>
     40    <updated><?php
     41        $date = get_lastcommentmodified( 'GMT' );
     42        echo $date ? mysql2date( 'Y-m-d\TH:i:s\Z', $date ) : date( 'Y-m-d\TH:i:s\Z' );
     43    ?></updated>
    4144
    4245<?php if ( is_singular() ) { ?>
  • trunk/src/wp-includes/feed-atom.php

    r35506 r38925  
    3131    <subtitle type="text"><?php bloginfo_rss("description") ?></subtitle>
    3232
    33     <updated><?php echo mysql2date('Y-m-d\TH:i:s\Z', get_lastpostmodified('GMT'), false); ?></updated>
     33    <updated><?php
     34        $date = get_lastpostmodified( 'GMT' );
     35        echo $date ? mysql2date( 'Y-m-d\TH:i:s\Z', $date ) : date( 'Y-m-d\TH:i:s\Z' );
     36    ?></updated>
    3437
    3538    <link rel="alternate" type="<?php bloginfo_rss('html_type'); ?>" href="<?php bloginfo_rss('url') ?>" />
  • trunk/src/wp-includes/feed-rdf.php

    r35294 r38925  
    3434    <link><?php bloginfo_rss('url') ?></link>
    3535    <description><?php bloginfo_rss('description') ?></description>
    36     <dc:date><?php echo mysql2date('Y-m-d\TH:i:s\Z', get_lastpostmodified('GMT'), false); ?></dc:date>
     36    <dc:date><?php
     37        $date = get_lastpostmodified( 'GMT' );
     38        echo $date ? mysql2date( 'Y-m-d\TH:i:s\Z', $date ) : date( 'Y-m-d\TH:i:s\Z' );
     39    ?></dc:date>
    3740    <sy:updatePeriod><?php
    3841        /** This filter is documented in wp-includes/feed-rss2.php */
  • trunk/src/wp-includes/feed-rss.php

    r35294 r38925  
    1515    <link><?php bloginfo_rss('url') ?></link>
    1616    <description><?php bloginfo_rss('description') ?></description>
    17     <lastBuildDate><?php echo mysql2date('D, d M Y H:i:s +0000', get_lastpostmodified('GMT'), false); ?></lastBuildDate>
     17    <lastBuildDate><?php
     18        $date = get_lastpostmodified( 'GMT' );
     19        echo $date ? mysql2date( 'D, d M Y H:i:s +0000', $date ) : date( 'D, d M Y H:i:s +0000' );
     20    ?></lastBuildDate>
    1821    <docs>http://backend.userland.com/rss092</docs>
    1922    <language><?php bloginfo_rss( 'language' ); ?></language>
  • trunk/src/wp-includes/feed-rss2-comments.php

    r35294 r38925  
    4444    <link><?php (is_single()) ? the_permalink_rss() : bloginfo_rss("url") ?></link>
    4545    <description><?php bloginfo_rss("description") ?></description>
    46     <lastBuildDate><?php echo mysql2date('r', get_lastcommentmodified('GMT')); ?></lastBuildDate>
     46    <lastBuildDate><?php
     47        $date = get_lastcommentmodified( 'GMT' );
     48        echo $date ? mysql2date( 'r', $date ) : date( 'r' );
     49    ?></lastBuildDate>
    4750    <sy:updatePeriod><?php
    4851        /** This filter is documented in wp-includes/feed-rss2.php */
  • trunk/src/wp-includes/feed-rss2.php

    r37518 r38925  
    4343    <link><?php bloginfo_rss('url') ?></link>
    4444    <description><?php bloginfo_rss("description") ?></description>
    45     <lastBuildDate><?php echo mysql2date('D, d M Y H:i:s +0000', get_lastpostmodified('GMT'), false); ?></lastBuildDate>
     45    <lastBuildDate><?php
     46        $date = get_lastpostmodified( 'GMT' );
     47        echo $date ? mysql2date( 'D, d M Y H:i:s +0000', $date ) : date( 'D, d M Y H:i:s +0000' );
     48    ?></lastBuildDate>
    4649    <language><?php bloginfo_rss( 'language' ); ?></language>
    4750    <sy:updatePeriod><?php
  • trunk/src/wp-includes/post.php

    r38852 r38925  
    56135613
    56145614    $date = wp_cache_get( $key, 'timeinfo' );
    5615 
    5616     if ( ! $date ) {
    5617         if ( 'any' === $post_type ) {
    5618             $post_types = get_post_types( array( 'public' => true ) );
    5619             array_walk( $post_types, array( $wpdb, 'escape_by_ref' ) );
    5620             $post_types = "'" . implode( "', '", $post_types ) . "'";
    5621         } else {
    5622             $post_types = "'" . sanitize_key( $post_type ) . "'";
    5623         }
    5624 
    5625         switch ( $timezone ) {
    5626             case 'gmt':
    5627                 $date = $wpdb->get_var("SELECT post_{$field}_gmt FROM $wpdb->posts WHERE post_status = 'publish' AND post_type IN ({$post_types}) ORDER BY post_{$field}_gmt DESC LIMIT 1");
    5628                 break;
    5629             case 'blog':
    5630                 $date = $wpdb->get_var("SELECT post_{$field} FROM $wpdb->posts WHERE post_status = 'publish' AND post_type IN ({$post_types}) ORDER BY post_{$field}_gmt DESC LIMIT 1");
    5631                 break;
    5632             case 'server':
    5633                 $add_seconds_server = date( 'Z' );
    5634                 $date = $wpdb->get_var("SELECT DATE_ADD(post_{$field}_gmt, INTERVAL '$add_seconds_server' SECOND) FROM $wpdb->posts WHERE post_status = 'publish' AND post_type IN ({$post_types}) ORDER BY post_{$field}_gmt DESC LIMIT 1");
    5635                 break;
    5636         }
    5637 
    5638         if ( $date ) {
    5639             wp_cache_set( $key, $date, 'timeinfo' );
    5640         }
    5641     }
    5642 
    5643     return $date;
     5615    if ( false !== $date ) {
     5616        return $date;
     5617    }
     5618
     5619    if ( 'any' === $post_type ) {
     5620        $post_types = get_post_types( array( 'public' => true ) );
     5621        array_walk( $post_types, array( $wpdb, 'escape_by_ref' ) );
     5622        $post_types = "'" . implode( "', '", $post_types ) . "'";
     5623    } else {
     5624        $post_types = "'" . sanitize_key( $post_type ) . "'";
     5625    }
     5626
     5627    switch ( $timezone ) {
     5628        case 'gmt':
     5629            $date = $wpdb->get_var("SELECT post_{$field}_gmt FROM $wpdb->posts WHERE post_status = 'publish' AND post_type IN ({$post_types}) ORDER BY post_{$field}_gmt DESC LIMIT 1");
     5630            break;
     5631        case 'blog':
     5632            $date = $wpdb->get_var("SELECT post_{$field} FROM $wpdb->posts WHERE post_status = 'publish' AND post_type IN ({$post_types}) ORDER BY post_{$field}_gmt DESC LIMIT 1");
     5633            break;
     5634        case 'server':
     5635            $add_seconds_server = date( 'Z' );
     5636            $date = $wpdb->get_var("SELECT DATE_ADD(post_{$field}_gmt, INTERVAL '$add_seconds_server' SECOND) FROM $wpdb->posts WHERE post_status = 'publish' AND post_type IN ({$post_types}) ORDER BY post_{$field}_gmt DESC LIMIT 1");
     5637            break;
     5638    }
     5639
     5640    if ( $date ) {
     5641        wp_cache_set( $key, $date, 'timeinfo' );
     5642
     5643        return $date;
     5644    }
     5645
     5646    return false;
    56445647}
    56455648
Note: See TracChangeset for help on using the changeset viewer.