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. Props jnylen0. Merges [40101] to the 4.7 branch. Fixes #39256. git-svn-id: https://develop.svn.wordpress.org/branches/4.7@40114 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
parent
32ccf017de
commit
9c7ef6a3ad
@ -780,26 +780,40 @@ function rest_parse_date( $date, $force_utc = false ) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a local date with its GMT equivalent, in MySQL datetime format.
|
||||
* Parses a date into both its local and UTC equivalent, in MySQL datetime format.
|
||||
*
|
||||
* @since 4.4.0
|
||||
*
|
||||
* @see rest_parse_date()
|
||||
*
|
||||
* @param string $date RFC3339 timestamp.
|
||||
* @param bool $force_utc Whether a UTC timestamp should be forced. Default false.
|
||||
* @param string $date RFC3339 timestamp.
|
||||
* @param bool $is_utc Whether the provided date should be interpreted as UTC. Default false.
|
||||
* @return array|null Local and UTC datetime strings, in MySQL datetime format (Y-m-d H:i:s),
|
||||
* null on failure.
|
||||
*/
|
||||
function rest_get_date_with_gmt( $date, $force_utc = false ) {
|
||||
$date = rest_parse_date( $date, $force_utc );
|
||||
function rest_get_date_with_gmt( $date, $is_utc = false ) {
|
||||
// Whether or not the original date actually has a timezone string
|
||||
// changes the way we need to do timezone conversion. Store this info
|
||||
// before parsing the date, and use it later.
|
||||
$has_timezone = preg_match( '#(Z|[+-]\d{2}(:\d{2})?)$#', $date );
|
||||
|
||||
$date = rest_parse_date( $date );
|
||||
|
||||
if ( empty( $date ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$utc = date( 'Y-m-d H:i:s', $date );
|
||||
$local = get_date_from_gmt( $utc );
|
||||
// At this point $date could either be a local date (if we were passed a
|
||||
// *local* date without a timezone offset) or a UTC date (otherwise).
|
||||
// Timezone conversion needs to be handled differently between these two
|
||||
// cases.
|
||||
if ( ! $is_utc && ! $has_timezone ) {
|
||||
$local = date( 'Y-m-d H:i:s', $date );
|
||||
$utc = get_gmt_from_date( $local );
|
||||
} else {
|
||||
$utc = date( 'Y-m-d H:i:s', $date );
|
||||
$local = get_date_from_gmt( $utc );
|
||||
}
|
||||
|
||||
return array( $local, $utc );
|
||||
}
|
||||
|
@ -999,12 +999,14 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
|
||||
|
||||
if ( ! empty( $date_data ) ) {
|
||||
list( $prepared_post->post_date, $prepared_post->post_date_gmt ) = $date_data;
|
||||
$prepared_post->edit_date = true;
|
||||
}
|
||||
} elseif ( ! empty( $schema['properties']['date_gmt'] ) && ! empty( $request['date_gmt'] ) ) {
|
||||
$date_data = rest_get_date_with_gmt( $request['date_gmt'], true );
|
||||
|
||||
if ( ! empty( $date_data ) ) {
|
||||
list( $prepared_post->post_date, $prepared_post->post_date_gmt ) = $date_data;
|
||||
$prepared_post->edit_date = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -383,4 +383,67 @@ class Tests_REST_API extends WP_UnitTestCase {
|
||||
$this->assertEquals( $valid, wp_check_jsonp_callback( $callback ) );
|
||||
}
|
||||
|
||||
public function rest_date_provider() {
|
||||
return array(
|
||||
// Valid dates with timezones
|
||||
array( '2017-01-16T11:30:00-05:00', gmmktime( 11, 30, 0, 1, 16, 2017 ) + 5 * HOUR_IN_SECONDS ),
|
||||
array( '2017-01-16T11:30:00-05:30', gmmktime( 11, 30, 0, 1, 16, 2017 ) + 5.5 * HOUR_IN_SECONDS ),
|
||||
array( '2017-01-16T11:30:00-05' , gmmktime( 11, 30, 0, 1, 16, 2017 ) + 5 * HOUR_IN_SECONDS ),
|
||||
array( '2017-01-16T11:30:00+05' , gmmktime( 11, 30, 0, 1, 16, 2017 ) - 5 * HOUR_IN_SECONDS ),
|
||||
array( '2017-01-16T11:30:00-00' , gmmktime( 11, 30, 0, 1, 16, 2017 ) ),
|
||||
array( '2017-01-16T11:30:00+00' , gmmktime( 11, 30, 0, 1, 16, 2017 ) ),
|
||||
array( '2017-01-16T11:30:00Z' , gmmktime( 11, 30, 0, 1, 16, 2017 ) ),
|
||||
|
||||
// Valid dates without timezones
|
||||
array( '2017-01-16T11:30:00' , gmmktime( 11, 30, 0, 1, 16, 2017 ) ),
|
||||
|
||||
// Invalid dates (TODO: support parsing partial dates as ranges, see #38641)
|
||||
array( '2017-01-16T11:30:00-5', false ),
|
||||
array( '2017-01-16T11:30', false ),
|
||||
array( '2017-01-16T11', false ),
|
||||
array( '2017-01-16T', false ),
|
||||
array( '2017-01-16', false ),
|
||||
array( '2017-01', false ),
|
||||
array( '2017', false ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider rest_date_provider
|
||||
*/
|
||||
public function test_rest_parse_date( $string, $value ) {
|
||||
$this->assertEquals( $value, rest_parse_date( $string ) );
|
||||
}
|
||||
|
||||
public function rest_date_force_utc_provider() {
|
||||
return array(
|
||||
// Valid dates with timezones
|
||||
array( '2017-01-16T11:30:00-05:00', gmmktime( 11, 30, 0, 1, 16, 2017 ) ),
|
||||
array( '2017-01-16T11:30:00-05:30', gmmktime( 11, 30, 0, 1, 16, 2017 ) ),
|
||||
array( '2017-01-16T11:30:00-05' , gmmktime( 11, 30, 0, 1, 16, 2017 ) ),
|
||||
array( '2017-01-16T11:30:00+05' , gmmktime( 11, 30, 0, 1, 16, 2017 ) ),
|
||||
array( '2017-01-16T11:30:00-00' , gmmktime( 11, 30, 0, 1, 16, 2017 ) ),
|
||||
array( '2017-01-16T11:30:00+00' , gmmktime( 11, 30, 0, 1, 16, 2017 ) ),
|
||||
array( '2017-01-16T11:30:00Z' , gmmktime( 11, 30, 0, 1, 16, 2017 ) ),
|
||||
|
||||
// Valid dates without timezones
|
||||
array( '2017-01-16T11:30:00' , gmmktime( 11, 30, 0, 1, 16, 2017 ) ),
|
||||
|
||||
// Invalid dates (TODO: support parsing partial dates as ranges, see #38641)
|
||||
array( '2017-01-16T11:30:00-5', false ),
|
||||
array( '2017-01-16T11:30', false ),
|
||||
array( '2017-01-16T11', false ),
|
||||
array( '2017-01-16T', false ),
|
||||
array( '2017-01-16', false ),
|
||||
array( '2017-01', false ),
|
||||
array( '2017', false ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider rest_date_force_utc_provider
|
||||
*/
|
||||
public function test_rest_parse_date_force_utc( $string, $value ) {
|
||||
$this->assertEquals( $value, rest_parse_date( $string, true ) );
|
||||
}
|
||||
}
|
||||
|
@ -958,6 +958,84 @@ class WP_Test_REST_Comments_Controller extends WP_Test_REST_Controller_Testcase
|
||||
$this->assertEquals( self::$post_id, $data['post'] );
|
||||
}
|
||||
|
||||
public function comment_dates_provider() {
|
||||
return array(
|
||||
'set date without timezone' => array(
|
||||
'params' => array(
|
||||
'timezone_string' => 'America/New_York',
|
||||
'date' => '2016-12-12T14:00:00',
|
||||
),
|
||||
'results' => array(
|
||||
'date' => '2016-12-12T14:00:00',
|
||||
'date_gmt' => '2016-12-12T19:00:00',
|
||||
),
|
||||
),
|
||||
'set date_gmt without timezone' => array(
|
||||
'params' => array(
|
||||
'timezone_string' => 'America/New_York',
|
||||
'date_gmt' => '2016-12-12T19:00:00',
|
||||
),
|
||||
'results' => array(
|
||||
'date' => '2016-12-12T14:00:00',
|
||||
'date_gmt' => '2016-12-12T19:00:00',
|
||||
),
|
||||
),
|
||||
'set date with timezone' => array(
|
||||
'params' => array(
|
||||
'timezone_string' => 'America/New_York',
|
||||
'date' => '2016-12-12T18:00:00-01:00',
|
||||
),
|
||||
'results' => array(
|
||||
'date' => '2016-12-12T14:00:00',
|
||||
'date_gmt' => '2016-12-12T19:00:00',
|
||||
),
|
||||
),
|
||||
'set date_gmt with timezone' => array(
|
||||
'params' => array(
|
||||
'timezone_string' => 'America/New_York',
|
||||
'date_gmt' => '2016-12-12T18:00:00-01:00',
|
||||
),
|
||||
'results' => array(
|
||||
'date' => '2016-12-12T14:00:00',
|
||||
'date_gmt' => '2016-12-12T19:00:00',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider comment_dates_provider
|
||||
*/
|
||||
public function test_create_comment_date( $params, $results ) {
|
||||
wp_set_current_user( self::$admin_id );
|
||||
update_option( 'timezone_string', $params['timezone_string'] );
|
||||
|
||||
$request = new WP_REST_Request( 'POST', '/wp/v2/comments' );
|
||||
$request->set_param( 'content', 'not empty' );
|
||||
$request->set_param( 'post', self::$post_id );
|
||||
if ( isset( $params['date'] ) ) {
|
||||
$request->set_param( 'date', $params['date'] );
|
||||
}
|
||||
if ( isset( $params['date_gmt'] ) ) {
|
||||
$request->set_param( 'date_gmt', $params['date_gmt'] );
|
||||
}
|
||||
$response = $this->server->dispatch( $request );
|
||||
|
||||
update_option( 'timezone_string', '' );
|
||||
|
||||
$this->assertEquals( 201, $response->get_status() );
|
||||
$data = $response->get_data();
|
||||
$comment = get_comment( $data['id'] );
|
||||
|
||||
$this->assertEquals( $results['date'], $data['date'] );
|
||||
$comment_date = str_replace( 'T', ' ', $results['date'] );
|
||||
$this->assertEquals( $comment_date, $comment->comment_date );
|
||||
|
||||
$this->assertEquals( $results['date_gmt'], $data['date_gmt'] );
|
||||
$comment_date_gmt = str_replace( 'T', ' ', $results['date_gmt'] );
|
||||
$this->assertEquals( $comment_date_gmt, $comment->comment_date_gmt );
|
||||
}
|
||||
|
||||
public function test_create_item_using_accepted_content_raw_value() {
|
||||
wp_set_current_user( self::$admin_id );
|
||||
|
||||
@ -1942,6 +2020,39 @@ class WP_Test_REST_Comments_Controller extends WP_Test_REST_Controller_Testcase
|
||||
$this->assertEquals( '2014-11-07T10:14:25', $comment['date'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider comment_dates_provider
|
||||
*/
|
||||
public function test_update_comment_date( $params, $results ) {
|
||||
wp_set_current_user( self::$editor_id );
|
||||
update_option( 'timezone_string', $params['timezone_string'] );
|
||||
|
||||
$comment_id = $this->factory->comment->create();
|
||||
|
||||
$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/comments/%d', $comment_id ) );
|
||||
if ( isset( $params['date'] ) ) {
|
||||
$request->set_param( 'date', $params['date'] );
|
||||
}
|
||||
if ( isset( $params['date_gmt'] ) ) {
|
||||
$request->set_param( 'date_gmt', $params['date_gmt'] );
|
||||
}
|
||||
$response = $this->server->dispatch( $request );
|
||||
|
||||
update_option( 'timezone_string', '' );
|
||||
|
||||
$this->assertEquals( 200, $response->get_status() );
|
||||
$data = $response->get_data();
|
||||
$comment = get_comment( $data['id'] );
|
||||
|
||||
$this->assertEquals( $results['date'], $data['date'] );
|
||||
$comment_date = str_replace( 'T', ' ', $results['date'] );
|
||||
$this->assertEquals( $comment_date, $comment->comment_date );
|
||||
|
||||
$this->assertEquals( $results['date_gmt'], $data['date_gmt'] );
|
||||
$comment_date_gmt = str_replace( 'T', ' ', $results['date_gmt'] );
|
||||
$this->assertEquals( $comment_date_gmt, $comment->comment_date_gmt );
|
||||
}
|
||||
|
||||
public function test_update_item_no_content() {
|
||||
$post_id = $this->factory->post->create();
|
||||
|
||||
|
@ -1096,6 +1096,110 @@ class WP_Test_REST_Posts_Controller extends WP_Test_REST_Post_Type_Controller_Te
|
||||
$this->check_create_post_response( $response );
|
||||
}
|
||||
|
||||
public function post_dates_provider() {
|
||||
$all_statuses = array(
|
||||
'draft',
|
||||
'publish',
|
||||
'future',
|
||||
'pending',
|
||||
'private',
|
||||
);
|
||||
|
||||
$cases_short = array(
|
||||
'set date without timezone' => array(
|
||||
'statuses' => $all_statuses,
|
||||
'params' => array(
|
||||
'timezone_string' => 'America/New_York',
|
||||
'date' => '2016-12-12T14:00:00',
|
||||
),
|
||||
'results' => array(
|
||||
'date' => '2016-12-12T14:00:00',
|
||||
'date_gmt' => '2016-12-12T19:00:00',
|
||||
),
|
||||
),
|
||||
'set date_gmt without timezone' => array(
|
||||
'statuses' => $all_statuses,
|
||||
'params' => array(
|
||||
'timezone_string' => 'America/New_York',
|
||||
'date_gmt' => '2016-12-12T19:00:00',
|
||||
),
|
||||
'results' => array(
|
||||
'date' => '2016-12-12T14:00:00',
|
||||
'date_gmt' => '2016-12-12T19:00:00',
|
||||
),
|
||||
),
|
||||
'set date with timezone' => array(
|
||||
'statuses' => array( 'draft', 'publish' ),
|
||||
'params' => array(
|
||||
'timezone_string' => 'America/New_York',
|
||||
'date' => '2016-12-12T18:00:00-01:00',
|
||||
),
|
||||
'results' => array(
|
||||
'date' => '2016-12-12T14:00:00',
|
||||
'date_gmt' => '2016-12-12T19:00:00',
|
||||
),
|
||||
),
|
||||
'set date_gmt with timezone' => array(
|
||||
'statuses' => array( 'draft', 'publish' ),
|
||||
'params' => array(
|
||||
'timezone_string' => 'America/New_York',
|
||||
'date_gmt' => '2016-12-12T18:00:00-01:00',
|
||||
),
|
||||
'results' => array(
|
||||
'date' => '2016-12-12T14:00:00',
|
||||
'date_gmt' => '2016-12-12T19:00:00',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$cases = array();
|
||||
foreach ( $cases_short as $description => $case ) {
|
||||
foreach ( $case['statuses'] as $status ) {
|
||||
$cases[ $description . ', status=' . $status ] = array(
|
||||
$status,
|
||||
$case['params'],
|
||||
$case['results'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $cases;
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider post_dates_provider
|
||||
*/
|
||||
public function test_create_post_date( $status, $params, $results ) {
|
||||
wp_set_current_user( self::$editor_id );
|
||||
update_option( 'timezone_string', $params['timezone_string'] );
|
||||
|
||||
$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
|
||||
$request->set_param( 'status', $status );
|
||||
$request->set_param( 'title', 'not empty' );
|
||||
if ( isset( $params['date'] ) ) {
|
||||
$request->set_param( 'date', $params['date'] );
|
||||
}
|
||||
if ( isset( $params['date_gmt'] ) ) {
|
||||
$request->set_param( 'date_gmt', $params['date_gmt'] );
|
||||
}
|
||||
$response = $this->server->dispatch( $request );
|
||||
|
||||
update_option( 'timezone_string', '' );
|
||||
|
||||
$this->assertEquals( 201, $response->get_status() );
|
||||
$data = $response->get_data();
|
||||
$post = get_post( $data['id'] );
|
||||
|
||||
$this->assertEquals( $results['date'], $data['date'] );
|
||||
$post_date = str_replace( 'T', ' ', $results['date'] );
|
||||
$this->assertEquals( $post_date, $post->post_date );
|
||||
|
||||
$this->assertEquals( $results['date_gmt'], $data['date_gmt'] );
|
||||
// TODO expect null here for drafts (see https://core.trac.wordpress.org/ticket/5698#comment:14)
|
||||
$post_date_gmt = str_replace( 'T', ' ', $results['date_gmt'] );
|
||||
$this->assertEquals( $post_date_gmt, $post->post_date_gmt );
|
||||
}
|
||||
|
||||
/**
|
||||
* @ticket 38698
|
||||
*/
|
||||
@ -1929,6 +2033,40 @@ class WP_Test_REST_Posts_Controller extends WP_Test_REST_Post_Type_Controller_Te
|
||||
$this->assertEquals( date( 'Y-m-d', strtotime( $expected_modified ) ), date( 'Y-m-d', strtotime( $new_post->post_modified ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider post_dates_provider
|
||||
*/
|
||||
public function test_update_post_date( $status, $params, $results ) {
|
||||
wp_set_current_user( self::$editor_id );
|
||||
update_option( 'timezone_string', $params['timezone_string'] );
|
||||
|
||||
$post_id = $this->factory->post->create( array( 'post_status' => $status ) );
|
||||
|
||||
$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', $post_id ) );
|
||||
if ( isset( $params['date'] ) ) {
|
||||
$request->set_param( 'date', $params['date'] );
|
||||
}
|
||||
if ( isset( $params['date_gmt'] ) ) {
|
||||
$request->set_param( 'date_gmt', $params['date_gmt'] );
|
||||
}
|
||||
$response = $this->server->dispatch( $request );
|
||||
|
||||
update_option( 'timezone_string', '' );
|
||||
|
||||
$this->assertEquals( 200, $response->get_status() );
|
||||
$data = $response->get_data();
|
||||
$post = get_post( $data['id'] );
|
||||
|
||||
$this->assertEquals( $results['date'], $data['date'] );
|
||||
$post_date = str_replace( 'T', ' ', $results['date'] );
|
||||
$this->assertEquals( $post_date, $post->post_date );
|
||||
|
||||
$this->assertEquals( $results['date_gmt'], $data['date_gmt'] );
|
||||
// TODO expect null here for drafts (see https://core.trac.wordpress.org/ticket/5698#comment:14)
|
||||
$post_date_gmt = str_replace( 'T', ' ', $results['date_gmt'] );
|
||||
$this->assertEquals( $post_date_gmt, $post->post_date_gmt );
|
||||
}
|
||||
|
||||
public function test_update_post_with_invalid_date() {
|
||||
wp_set_current_user( self::$editor_id );
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user