WordPress.org

Make WordPress Core

Changeset 40101


Ignore:
Timestamp:
02/21/17 18:17:32 (4 months ago)
Author:
jnylen0
Message:

REST API: Fix multiple issues with setting dates of posts and comments.

This commit modifies the rest_get_date_with_gmt function to correctly parse local and UTC timestamps with or without timezone information.

It also ensures that the REST API can edit the dates of draft posts by setting the edit_date flag to wp_update_post.

Overall this commit ensures that post and comment dates can be set and updated as expected.

Fixes #39256.

Location:
trunk
Files:
5 edited

Legend:

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

    r40047 r40101  
    781781 
    782782/** 
    783  * Retrieves a local date with its GMT equivalent, in MySQL datetime format. 
     783 * Parses a date into both its local and UTC equivalent, in MySQL datetime format. 
    784784 * 
    785785 * @since 4.4.0 
     
    787787 * @see rest_parse_date() 
    788788 * 
    789  * @param string $date      RFC3339 timestamp. 
    790  * @param bool   $force_utc Whether a UTC timestamp should be forced. Default false. 
     789 * @param string $date   RFC3339 timestamp. 
     790 * @param bool   $is_utc Whether the provided date should be interpreted as UTC. Default false. 
    791791 * @return array|null Local and UTC datetime strings, in MySQL datetime format (Y-m-d H:i:s), 
    792792 *                    null on failure. 
    793793 */ 
    794 function rest_get_date_with_gmt( $date, $force_utc = false ) { 
    795     $date = rest_parse_date( $date, $force_utc ); 
     794function rest_get_date_with_gmt( $date, $is_utc = false ) { 
     795    // Whether or not the original date actually has a timezone string 
     796    // changes the way we need to do timezone conversion.  Store this info 
     797    // before parsing the date, and use it later. 
     798    $has_timezone = preg_match( '#(Z|[+-]\d{2}(:\d{2})?)$#', $date ); 
     799 
     800    $date = rest_parse_date( $date ); 
    796801 
    797802    if ( empty( $date ) ) { 
     
    799804    } 
    800805 
    801     $utc = date( 'Y-m-d H:i:s', $date ); 
    802     $local = get_date_from_gmt( $utc ); 
     806    // At this point $date could either be a local date (if we were passed a 
     807    // *local* date without a timezone offset) or a UTC date (otherwise). 
     808    // Timezone conversion needs to be handled differently between these two 
     809    // cases. 
     810    if ( ! $is_utc && ! $has_timezone ) { 
     811        $local = date( 'Y-m-d H:i:s', $date ); 
     812        $utc = get_gmt_from_date( $local ); 
     813    } else { 
     814        $utc = date( 'Y-m-d H:i:s', $date ); 
     815        $local = get_date_from_gmt( $utc ); 
     816    } 
    803817 
    804818    return array( $local, $utc ); 
  • trunk/src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php

    r40080 r40101  
    10051005            if ( ! empty( $date_data ) ) { 
    10061006                list( $prepared_post->post_date, $prepared_post->post_date_gmt ) = $date_data; 
     1007                $prepared_post->edit_date = true; 
    10071008            } 
    10081009        } elseif ( ! empty( $schema['properties']['date_gmt'] ) && ! empty( $request['date_gmt'] ) ) { 
     
    10111012            if ( ! empty( $date_data ) ) { 
    10121013                list( $prepared_post->post_date, $prepared_post->post_date_gmt ) = $date_data; 
     1014                $prepared_post->edit_date = true; 
    10131015            } 
    10141016        } 
  • trunk/tests/phpunit/tests/rest-api.php

    r38832 r40101  
    384384    } 
    385385 
     386    public function rest_date_provider() { 
     387        return array( 
     388            // Valid dates with timezones 
     389            array( '2017-01-16T11:30:00-05:00', gmmktime( 11, 30,  0,  1, 16, 2017 ) + 5 * HOUR_IN_SECONDS ), 
     390            array( '2017-01-16T11:30:00-05:30', gmmktime( 11, 30,  0,  1, 16, 2017 ) + 5.5 * HOUR_IN_SECONDS ), 
     391            array( '2017-01-16T11:30:00-05'   , gmmktime( 11, 30,  0,  1, 16, 2017 ) + 5 * HOUR_IN_SECONDS ), 
     392            array( '2017-01-16T11:30:00+05'   , gmmktime( 11, 30,  0,  1, 16, 2017 ) - 5 * HOUR_IN_SECONDS ), 
     393            array( '2017-01-16T11:30:00-00'   , gmmktime( 11, 30,  0,  1, 16, 2017 ) ), 
     394            array( '2017-01-16T11:30:00+00'   , gmmktime( 11, 30,  0,  1, 16, 2017 ) ), 
     395            array( '2017-01-16T11:30:00Z'     , gmmktime( 11, 30,  0,  1, 16, 2017 ) ), 
     396 
     397            // Valid dates without timezones 
     398            array( '2017-01-16T11:30:00'      , gmmktime( 11, 30,  0,  1, 16, 2017 ) ), 
     399 
     400            // Invalid dates (TODO: support parsing partial dates as ranges, see #38641) 
     401            array( '2017-01-16T11:30:00-5', false ), 
     402            array( '2017-01-16T11:30', false ), 
     403            array( '2017-01-16T11', false ), 
     404            array( '2017-01-16T', false ), 
     405            array( '2017-01-16', false ), 
     406            array( '2017-01', false ), 
     407            array( '2017', false ), 
     408        ); 
     409    } 
     410 
     411    /** 
     412     * @dataProvider rest_date_provider 
     413     */ 
     414    public function test_rest_parse_date( $string, $value ) { 
     415        $this->assertEquals( $value, rest_parse_date( $string ) ); 
     416    } 
     417 
     418    public function rest_date_force_utc_provider() { 
     419        return array( 
     420            // Valid dates with timezones 
     421            array( '2017-01-16T11:30:00-05:00', gmmktime( 11, 30,  0,  1, 16, 2017 ) ), 
     422            array( '2017-01-16T11:30:00-05:30', gmmktime( 11, 30,  0,  1, 16, 2017 ) ), 
     423            array( '2017-01-16T11:30:00-05'   , gmmktime( 11, 30,  0,  1, 16, 2017 ) ), 
     424            array( '2017-01-16T11:30:00+05'   , gmmktime( 11, 30,  0,  1, 16, 2017 ) ), 
     425            array( '2017-01-16T11:30:00-00'   , gmmktime( 11, 30,  0,  1, 16, 2017 ) ), 
     426            array( '2017-01-16T11:30:00+00'   , gmmktime( 11, 30,  0,  1, 16, 2017 ) ), 
     427            array( '2017-01-16T11:30:00Z'     , gmmktime( 11, 30,  0,  1, 16, 2017 ) ), 
     428 
     429            // Valid dates without timezones 
     430            array( '2017-01-16T11:30:00'      , gmmktime( 11, 30,  0,  1, 16, 2017 ) ), 
     431 
     432            // Invalid dates (TODO: support parsing partial dates as ranges, see #38641) 
     433            array( '2017-01-16T11:30:00-5', false ), 
     434            array( '2017-01-16T11:30', false ), 
     435            array( '2017-01-16T11', false ), 
     436            array( '2017-01-16T', false ), 
     437            array( '2017-01-16', false ), 
     438            array( '2017-01', false ), 
     439            array( '2017', false ), 
     440        ); 
     441    } 
     442 
     443    /** 
     444     * @dataProvider rest_date_force_utc_provider 
     445     */ 
     446    public function test_rest_parse_date_force_utc( $string, $value ) { 
     447        $this->assertEquals( $value, rest_parse_date( $string, true ) ); 
     448    } 
    386449} 
  • trunk/tests/phpunit/tests/rest-api/rest-comments-controller.php

    r39954 r40101  
    961961    } 
    962962 
     963    public function comment_dates_provider() { 
     964        return array( 
     965            'set date without timezone' => array( 
     966                'params'   => array( 
     967                    'timezone_string' => 'America/New_York', 
     968                    'date'            => '2016-12-12T14:00:00', 
     969                ), 
     970                'results' => array( 
     971                    'date'            => '2016-12-12T14:00:00', 
     972                    'date_gmt'        => '2016-12-12T19:00:00', 
     973                ), 
     974            ), 
     975            'set date_gmt without timezone' => array( 
     976                'params'   => array( 
     977                    'timezone_string' => 'America/New_York', 
     978                    'date_gmt'        => '2016-12-12T19:00:00', 
     979                ), 
     980                'results' => array( 
     981                    'date'            => '2016-12-12T14:00:00', 
     982                    'date_gmt'        => '2016-12-12T19:00:00', 
     983                ), 
     984            ), 
     985            'set date with timezone' => array( 
     986                'params'   => array( 
     987                    'timezone_string' => 'America/New_York', 
     988                    'date'            => '2016-12-12T18:00:00-01:00', 
     989                ), 
     990                'results' => array( 
     991                    'date'            => '2016-12-12T14:00:00', 
     992                    'date_gmt'        => '2016-12-12T19:00:00', 
     993                ), 
     994            ), 
     995            'set date_gmt with timezone' => array( 
     996                'params'   => array( 
     997                    'timezone_string' => 'America/New_York', 
     998                    'date_gmt'        => '2016-12-12T18:00:00-01:00', 
     999                ), 
     1000                'results' => array( 
     1001                    'date'            => '2016-12-12T14:00:00', 
     1002                    'date_gmt'        => '2016-12-12T19:00:00', 
     1003                ), 
     1004            ), 
     1005        ); 
     1006    } 
     1007 
     1008    /** 
     1009     * @dataProvider comment_dates_provider 
     1010     */ 
     1011    public function test_create_comment_date( $params, $results ) { 
     1012        wp_set_current_user( self::$admin_id ); 
     1013        update_option( 'timezone_string', $params['timezone_string'] ); 
     1014 
     1015        $request = new WP_REST_Request( 'POST', '/wp/v2/comments' ); 
     1016        $request->set_param( 'content', 'not empty' ); 
     1017        $request->set_param( 'post', self::$post_id ); 
     1018        if ( isset( $params['date'] ) ) { 
     1019            $request->set_param( 'date', $params['date'] ); 
     1020        } 
     1021        if ( isset( $params['date_gmt'] ) ) { 
     1022            $request->set_param( 'date_gmt', $params['date_gmt'] ); 
     1023        } 
     1024        $response = $this->server->dispatch( $request ); 
     1025 
     1026        update_option( 'timezone_string', '' ); 
     1027 
     1028        $this->assertEquals( 201, $response->get_status() ); 
     1029        $data = $response->get_data(); 
     1030        $comment = get_comment( $data['id'] ); 
     1031 
     1032        $this->assertEquals( $results['date'], $data['date'] ); 
     1033        $comment_date = str_replace( 'T', ' ', $results['date'] ); 
     1034        $this->assertEquals( $comment_date, $comment->comment_date ); 
     1035 
     1036        $this->assertEquals( $results['date_gmt'], $data['date_gmt'] ); 
     1037        $comment_date_gmt = str_replace( 'T', ' ', $results['date_gmt'] ); 
     1038        $this->assertEquals( $comment_date_gmt, $comment->comment_date_gmt ); 
     1039    } 
     1040 
    9631041    public function test_create_item_using_accepted_content_raw_value() { 
    9641042        wp_set_current_user( self::$admin_id ); 
     
    19692047        $this->assertEquals( mysql_to_rfc3339( $updated->comment_date ), $comment['date'] ); 
    19702048        $this->assertEquals( '2014-11-07T10:14:25', $comment['date'] ); 
     2049    } 
     2050 
     2051    /** 
     2052     * @dataProvider comment_dates_provider 
     2053     */ 
     2054    public function test_update_comment_date( $params, $results ) { 
     2055        wp_set_current_user( self::$editor_id ); 
     2056        update_option( 'timezone_string', $params['timezone_string'] ); 
     2057 
     2058        $comment_id = $this->factory->comment->create(); 
     2059 
     2060        $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/comments/%d', $comment_id ) ); 
     2061        if ( isset( $params['date'] ) ) { 
     2062            $request->set_param( 'date', $params['date'] ); 
     2063        } 
     2064        if ( isset( $params['date_gmt'] ) ) { 
     2065            $request->set_param( 'date_gmt', $params['date_gmt'] ); 
     2066        } 
     2067        $response = $this->server->dispatch( $request ); 
     2068 
     2069        update_option( 'timezone_string', '' ); 
     2070 
     2071        $this->assertEquals( 200, $response->get_status() ); 
     2072        $data = $response->get_data(); 
     2073        $comment = get_comment( $data['id'] ); 
     2074 
     2075        $this->assertEquals( $results['date'], $data['date'] ); 
     2076        $comment_date = str_replace( 'T', ' ', $results['date'] ); 
     2077        $this->assertEquals( $comment_date, $comment->comment_date ); 
     2078 
     2079        $this->assertEquals( $results['date_gmt'], $data['date_gmt'] ); 
     2080        $comment_date_gmt = str_replace( 'T', ' ', $results['date_gmt'] ); 
     2081        $this->assertEquals( $comment_date_gmt, $comment->comment_date_gmt ); 
    19712082    } 
    19722083 
  • trunk/tests/phpunit/tests/rest-api/rest-posts-controller.php

    r40037 r40101  
    11531153    } 
    11541154 
     1155    public function post_dates_provider() { 
     1156        $all_statuses = array( 
     1157            'draft', 
     1158            'publish', 
     1159            'future', 
     1160            'pending', 
     1161            'private', 
     1162        ); 
     1163 
     1164        $cases_short = array( 
     1165            'set date without timezone' => array( 
     1166                'statuses' => $all_statuses, 
     1167                'params'   => array( 
     1168                    'timezone_string' => 'America/New_York', 
     1169                    'date'            => '2016-12-12T14:00:00', 
     1170                ), 
     1171                'results' => array( 
     1172                    'date'            => '2016-12-12T14:00:00', 
     1173                    'date_gmt'        => '2016-12-12T19:00:00', 
     1174                ), 
     1175            ), 
     1176            'set date_gmt without timezone' => array( 
     1177                'statuses' => $all_statuses, 
     1178                'params'   => array( 
     1179                    'timezone_string' => 'America/New_York', 
     1180                    'date_gmt'        => '2016-12-12T19:00:00', 
     1181                ), 
     1182                'results' => array( 
     1183                    'date'            => '2016-12-12T14:00:00', 
     1184                    'date_gmt'        => '2016-12-12T19:00:00', 
     1185                ), 
     1186            ), 
     1187            'set date with timezone' => array( 
     1188                'statuses' => array( 'draft', 'publish' ), 
     1189                'params'   => array( 
     1190                    'timezone_string' => 'America/New_York', 
     1191                    'date'            => '2016-12-12T18:00:00-01:00', 
     1192                ), 
     1193                'results' => array( 
     1194                    'date'            => '2016-12-12T14:00:00', 
     1195                    'date_gmt'        => '2016-12-12T19:00:00', 
     1196                ), 
     1197            ), 
     1198            'set date_gmt with timezone' => array( 
     1199                'statuses' => array( 'draft', 'publish' ), 
     1200                'params'   => array( 
     1201                    'timezone_string' => 'America/New_York', 
     1202                    'date_gmt'        => '2016-12-12T18:00:00-01:00', 
     1203                ), 
     1204                'results' => array( 
     1205                    'date'            => '2016-12-12T14:00:00', 
     1206                    'date_gmt'        => '2016-12-12T19:00:00', 
     1207                ), 
     1208            ), 
     1209        ); 
     1210 
     1211        $cases = array(); 
     1212        foreach ( $cases_short as $description => $case ) { 
     1213            foreach ( $case['statuses'] as $status ) { 
     1214                $cases[ $description . ', status=' . $status ] = array( 
     1215                    $status, 
     1216                    $case['params'], 
     1217                    $case['results'], 
     1218                ); 
     1219            } 
     1220        } 
     1221 
     1222        return $cases; 
     1223    } 
     1224 
     1225    /** 
     1226     * @dataProvider post_dates_provider 
     1227     */ 
     1228    public function test_create_post_date( $status, $params, $results ) { 
     1229        wp_set_current_user( self::$editor_id ); 
     1230        update_option( 'timezone_string', $params['timezone_string'] ); 
     1231 
     1232        $request = new WP_REST_Request( 'POST', '/wp/v2/posts' ); 
     1233        $request->set_param( 'status', $status ); 
     1234        $request->set_param( 'title', 'not empty' ); 
     1235        if ( isset( $params['date'] ) ) { 
     1236            $request->set_param( 'date', $params['date'] ); 
     1237        } 
     1238        if ( isset( $params['date_gmt'] ) ) { 
     1239            $request->set_param( 'date_gmt', $params['date_gmt'] ); 
     1240        } 
     1241        $response = $this->server->dispatch( $request ); 
     1242 
     1243        update_option( 'timezone_string', '' ); 
     1244 
     1245        $this->assertEquals( 201, $response->get_status() ); 
     1246        $data = $response->get_data(); 
     1247        $post = get_post( $data['id'] ); 
     1248 
     1249        $this->assertEquals( $results['date'], $data['date'] ); 
     1250        $post_date = str_replace( 'T', ' ', $results['date'] ); 
     1251        $this->assertEquals( $post_date, $post->post_date ); 
     1252 
     1253        $this->assertEquals( $results['date_gmt'], $data['date_gmt'] ); 
     1254        // TODO expect null here for drafts (see https://core.trac.wordpress.org/ticket/5698#comment:14) 
     1255        $post_date_gmt = str_replace( 'T', ' ', $results['date_gmt'] ); 
     1256        $this->assertEquals( $post_date_gmt, $post->post_date_gmt ); 
     1257    } 
     1258 
    11551259    /** 
    11561260     * @ticket 38698 
     
    19842088        $this->assertEquals( date( 'Y-m-d', strtotime( mysql_to_rfc3339( $expected_modified ) ) ), date( 'Y-m-d', strtotime( $data['modified'] ) ) ); 
    19852089        $this->assertEquals( date( 'Y-m-d', strtotime( $expected_modified ) ), date( 'Y-m-d', strtotime( $new_post->post_modified ) ) ); 
     2090    } 
     2091 
     2092    /** 
     2093     * @dataProvider post_dates_provider 
     2094     */ 
     2095    public function test_update_post_date( $status, $params, $results ) { 
     2096        wp_set_current_user( self::$editor_id ); 
     2097        update_option( 'timezone_string', $params['timezone_string'] ); 
     2098 
     2099        $post_id = $this->factory->post->create( array( 'post_status' => $status ) ); 
     2100 
     2101        $request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', $post_id ) ); 
     2102        if ( isset( $params['date'] ) ) { 
     2103            $request->set_param( 'date', $params['date'] ); 
     2104        } 
     2105        if ( isset( $params['date_gmt'] ) ) { 
     2106            $request->set_param( 'date_gmt', $params['date_gmt'] ); 
     2107        } 
     2108        $response = $this->server->dispatch( $request ); 
     2109 
     2110        update_option( 'timezone_string', '' ); 
     2111 
     2112        $this->assertEquals( 200, $response->get_status() ); 
     2113        $data = $response->get_data(); 
     2114        $post = get_post( $data['id'] ); 
     2115 
     2116        $this->assertEquals( $results['date'], $data['date'] ); 
     2117        $post_date = str_replace( 'T', ' ', $results['date'] ); 
     2118        $this->assertEquals( $post_date, $post->post_date ); 
     2119 
     2120        $this->assertEquals( $results['date_gmt'], $data['date_gmt'] ); 
     2121        // TODO expect null here for drafts (see https://core.trac.wordpress.org/ticket/5698#comment:14) 
     2122        $post_date_gmt = str_replace( 'T', ' ', $results['date_gmt'] ); 
     2123        $this->assertEquals( $post_date_gmt, $post->post_date_gmt ); 
    19862124    } 
    19872125 
Note: See TracChangeset for help on using the changeset viewer.