Completed
Pull Request — master (#2)
by Stephen
13:19
created

WP_Test_REST_Posts_Controller::assertPostsWhere()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Unit tests covering WP_REST_Posts_Controller functionality.
4
 *
5
 * @package WordPress
6
 * @subpackage REST API
7
 */
8
9
/**
10
 * @group restapi
11
 */
12
class WP_Test_REST_Posts_Controller extends WP_Test_REST_Post_Type_Controller_Testcase {
13
	protected static $post_id;
14
15
	protected static $superadmin_id;
16
	protected static $editor_id;
17
	protected static $author_id;
18
	protected static $contributor_id;
19
20
	protected static $supported_formats;
21
22
	protected $forbidden_cat;
23
	protected $posts_clauses;
24
25
	public static function wpSetUpBeforeClass( $factory ) {
26
		self::$post_id = $factory->post->create();
27
28
		self::$superadmin_id = $factory->user->create( array(
29
			'role'       => 'administrator',
30
			'user_login' => 'superadmin',
31
		) );
32
		self::$editor_id = $factory->user->create( array(
33
			'role' => 'editor',
34
		) );
35
		self::$author_id = $factory->user->create( array(
36
			'role' => 'author',
37
		) );
38
		self::$contributor_id = $factory->user->create( array(
39
			'role' => 'contributor',
40
		) );
41
42
		if ( is_multisite() ) {
43
			update_site_option( 'site_admins', array( 'superadmin' ) );
44
		}
45
46
		// Only support 'post' and 'gallery'
47
		self::$supported_formats = get_theme_support( 'post-formats' );
48
		add_theme_support( 'post-formats', array( 'post', 'gallery' ) );
49
	}
50
51
	public static function wpTearDownAfterClass() {
52
		// Restore theme support for formats.
53
		if ( self::$supported_formats ) {
54
			add_theme_support( 'post-formats', self::$supported_formats );
55
		} else {
56
			remove_theme_support( 'post-formats' );
57
		}
58
59
		wp_delete_post( self::$post_id, true );
60
61
		self::delete_user( self::$superadmin_id );
62
		self::delete_user( self::$editor_id );
63
		self::delete_user( self::$author_id );
64
		self::delete_user( self::$contributor_id );
65
	}
66
67
	public function setUp() {
68
		parent::setUp();
69
		register_post_type( 'youseeme', array( 'supports' => array(), 'show_in_rest' => true ) );
70
		add_filter( 'rest_pre_dispatch', array( $this, 'wpSetUpBeforeRequest' ), 10, 3 );
71
		add_filter( 'posts_clauses', array( $this, 'save_posts_clauses' ), 10, 2 );
72
	}
73
74
	public function wpSetUpBeforeRequest( $result, $server, $request ) {
75
		$this->posts_clauses = array();
76
		return $result;
77
	}
78
79
	public function save_posts_clauses( $orderby, $query ) {
80
		array_push( $this->posts_clauses, $orderby );
81
		return $orderby;
82
	}
83
84
	public function assertPostsClause( $clause, $pattern ) {
85
		global $wpdb;
86
		$expected_clause = str_replace( '{posts}', $wpdb->posts, $pattern );
87
		$this->assertCount( 1, $this->posts_clauses );
88
		$this->assertEquals( $expected_clause, $this->posts_clauses[0][ $clause ] );
89
	}
90
91
	public function assertPostsOrderedBy( $pattern ) {
92
		$this->assertPostsClause( 'orderby', $pattern );
93
	}
94
95
	public function assertPostsWhere( $pattern ) {
96
		$this->assertPostsClause( 'where', $pattern );
97
	}
98
99
	public function test_register_routes() {
100
		$routes = $this->server->get_routes();
101
102
		$this->assertArrayHasKey( '/wp/v2/posts', $routes );
103
		$this->assertCount( 2, $routes['/wp/v2/posts'] );
104
		$this->assertArrayHasKey( '/wp/v2/posts/(?P<id>[\d]+)', $routes );
105
		$this->assertCount( 3, $routes['/wp/v2/posts/(?P<id>[\d]+)'] );
106
	}
107
108
	public function test_context_param() {
109
		// Collection
110
		$request = new WP_REST_Request( 'OPTIONS', '/wp/v2/posts' );
111
		$response = $this->server->dispatch( $request );
112
		$data = $response->get_data();
113
		$this->assertEquals( 'view', $data['endpoints'][0]['args']['context']['default'] );
114
		$this->assertEquals( array( 'view', 'embed', 'edit' ), $data['endpoints'][0]['args']['context']['enum'] );
115
		// Single
116
		$request = new WP_REST_Request( 'OPTIONS', '/wp/v2/posts/' . self::$post_id );
117
		$response = $this->server->dispatch( $request );
118
		$data = $response->get_data();
119
		$this->assertEquals( 'view', $data['endpoints'][0]['args']['context']['default'] );
120
		$this->assertEquals( array( 'view', 'embed', 'edit' ), $data['endpoints'][0]['args']['context']['enum'] );
121
	}
122
123
	public function test_registered_query_params() {
124
		$request = new WP_REST_Request( 'OPTIONS', '/wp/v2/posts' );
125
		$response = $this->server->dispatch( $request );
126
		$data = $response->get_data();
127
		$keys = array_keys( $data['endpoints'][0]['args'] );
128
		sort( $keys );
129
		$this->assertEquals( array(
130
			'after',
131
			'author',
132
			'author_exclude',
133
			'before',
134
			'categories',
135
			'categories_exclude',
136
			'context',
137
			'exclude',
138
			'include',
139
			'offset',
140
			'order',
141
			'orderby',
142
			'page',
143
			'per_page',
144
			'search',
145
			'slug',
146
			'status',
147
			'sticky',
148
			'tags',
149
			'tags_exclude',
150
			), $keys );
151
	}
152
153
	public function test_registered_get_item_params() {
154
		$request = new WP_REST_Request( 'OPTIONS', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
155
		$response = $this->server->dispatch( $request );
156
		$data = $response->get_data();
157
		$keys = array_keys( $data['endpoints'][0]['args'] );
158
		sort( $keys );
159
		$this->assertEquals( array( 'context', 'id', 'password' ), $keys );
160
	}
161
162
	public function test_get_items() {
163
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
164
		$response = $this->server->dispatch( $request );
165
166
		$this->check_get_posts_response( $response );
167
	}
168
169
	/**
170
	 * A valid query that returns 0 results should return an empty JSON list.
171
	 *
172
	 * @issue 862
173
	 */
174
	public function test_get_items_empty_query() {
175
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
176
		$request->set_query_params( array(
177
			'author' => REST_TESTS_IMPOSSIBLY_HIGH_NUMBER,
178
		) );
179
		$response = $this->server->dispatch( $request );
180
181
		$this->assertEmpty( $response->get_data() );
182
		$this->assertEquals( 200, $response->get_status() );
183
	}
184
185
	public function test_get_items_author_query() {
186
		$this->factory->post->create( array( 'post_author' => self::$editor_id ) );
187
		$this->factory->post->create( array( 'post_author' => self::$author_id ) );
188
		// All 3 posts
189
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
190
		$response = $this->server->dispatch( $request );
191
		$this->assertEquals( 200, $response->get_status() );
192
		$this->assertEquals( 3, count( $response->get_data() ) );
193
		// 2 of 3 posts
194
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
195
		$request->set_param( 'author', array( self::$editor_id, self::$author_id ) );
196
		$response = $this->server->dispatch( $request );
197
		$this->assertEquals( 200, $response->get_status() );
198
		$data = $response->get_data();
199
		$this->assertEquals( 2, count( $data ) );
200
		$this->assertEqualSets( array( self::$editor_id, self::$author_id ), wp_list_pluck( $data, 'author' ) );
201
		// 1 of 3 posts
202
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
203
		$request->set_param( 'author', self::$editor_id );
204
		$response = $this->server->dispatch( $request );
205
		$this->assertEquals( 200, $response->get_status() );
206
		$data = $response->get_data();
207
		$this->assertEquals( 1, count( $data ) );
208
		$this->assertEquals( self::$editor_id, $data[0]['author'] );
209
	}
210
211
	public function test_get_items_author_exclude_query() {
212
		$this->factory->post->create( array( 'post_author' => self::$editor_id ) );
213
		$this->factory->post->create( array( 'post_author' => self::$author_id ) );
214
		// All 3 posts
215
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
216
		$response = $this->server->dispatch( $request );
217
		$this->assertEquals( 200, $response->get_status() );
218
		$this->assertEquals( 3, count( $response->get_data() ) );
219
		// 1 of 3 posts
220
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
221
		$request->set_param( 'author_exclude', array( self::$editor_id, self::$author_id ) );
222
		$response = $this->server->dispatch( $request );
223
		$this->assertEquals( 200, $response->get_status() );
224
		$data = $response->get_data();
225
		$this->assertEquals( 1, count( $data ) );
226
		$this->assertNotEquals( self::$editor_id, $data[0]['author'] );
227
		$this->assertNotEquals( self::$author_id, $data[0]['author'] );
228
		// 2 of 3 posts
229
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
230
		$request->set_param( 'author_exclude', self::$editor_id );
231
		$response = $this->server->dispatch( $request );
232
		$this->assertEquals( 200, $response->get_status() );
233
		$data = $response->get_data();
234
		$this->assertEquals( 2, count( $data ) );
235
		$this->assertNotEquals( self::$editor_id, $data[0]['author'] );
236
		$this->assertNotEquals( self::$editor_id, $data[1]['author'] );
237
		// invalid author_exclude errors
238
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
239
		$request->set_param( 'author_exclude', 'invalid' );
240
		$response = $this->server->dispatch( $request );
241
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
242
	}
243
244
	public function test_get_items_include_query() {
245
		$id1 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
246
		$this->factory->post->create( array( 'post_status' => 'publish' ) );
247
		$id3 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
248
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
249
		// Orderby=>desc
250
		$request->set_param( 'include', array( $id1, $id3 ) );
251
		$response = $this->server->dispatch( $request );
252
		$data = $response->get_data();
253
		$this->assertEquals( 2, count( $data ) );
254
		$this->assertEquals( $id3, $data[0]['id'] );
255
		$this->assertPostsOrderedBy( '{posts}.post_date DESC' );
256
		// Orderby=>include
257
		$request->set_param( 'orderby', 'include' );
258
		$response = $this->server->dispatch( $request );
259
		$data = $response->get_data();
260
		$this->assertEquals( 2, count( $data ) );
261
		$this->assertEquals( $id1, $data[0]['id'] );
262
		$this->assertPostsOrderedBy( "FIELD( {posts}.ID, $id1,$id3 )" );
263
		// Invalid include should error
264
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
265
		$request->set_param( 'include', 'invalid' );
266
		$response = $this->server->dispatch( $request );
267
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
268
	}
269
270
	public function test_get_items_orderby_author_query() {
271
		$id2 = $this->factory->post->create( array( 'post_status' => 'publish', 'post_author' => self::$editor_id ) );
272
		$id3 = $this->factory->post->create( array( 'post_status' => 'publish', 'post_author' => self::$editor_id ) );
273
		$id1 = $this->factory->post->create( array( 'post_status' => 'publish', 'post_author' => self::$author_id ) );
274
275
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
276
		$request->set_param( 'include', array( $id1, $id2, $id3 ) );
277
		$request->set_param( 'orderby', 'author' );
278
279
		$response = $this->server->dispatch( $request );
280
		$data = $response->get_data();
281
282
		$this->assertEquals( 200, $response->get_status() );
283
		$this->assertEquals( self::$author_id, $data[0]['author'] );
284
		$this->assertEquals( self::$editor_id, $data[1]['author'] );
285
		$this->assertEquals( self::$editor_id, $data[2]['author'] );
286
287
		$this->assertPostsOrderedBy( '{posts}.post_author DESC' );
288
	}
289
290
	public function test_get_items_orderby_modified_query() {
291
		$id1 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
292
		$id2 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
293
		$id3 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
294
295
		$this->update_post_modified( $id1, '2016-04-20 4:26:20' );
296
		$this->update_post_modified( $id2, '2016-02-01 20:24:02' );
297
		$this->update_post_modified( $id3, '2016-02-21 12:24:02' );
298
299
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
300
		$request->set_param( 'include', array( $id1, $id2, $id3 ) );
301
		$request->set_param( 'orderby', 'modified' );
302
303
		$response = $this->server->dispatch( $request );
304
		$data = $response->get_data();
305
306
		$this->assertEquals( 200, $response->get_status() );
307
		$this->assertEquals( $id1, $data[0]['id'] );
308
		$this->assertEquals( $id3, $data[1]['id'] );
309
		$this->assertEquals( $id2, $data[2]['id'] );
310
311
		$this->assertPostsOrderedBy( '{posts}.post_modified DESC' );
312
	}
313
314
	public function test_get_items_orderby_parent_query() {
315
		$id1 = $this->factory->post->create( array( 'post_status' => 'publish', 'post_type' => 'page' ) );
316
		$id2 = $this->factory->post->create( array( 'post_status' => 'publish', 'post_type' => 'page' ) );
317
		$id3 = $this->factory->post->create( array( 'post_status' => 'publish', 'post_type' => 'page', 'post_parent' => $id1 ) );
318
319
		$request = new WP_REST_Request( 'GET', '/wp/v2/pages' );
320
		$request->set_param( 'include', array( $id1, $id2, $id3 ) );
321
		$request->set_param( 'orderby', 'parent' );
322
323
		$response = $this->server->dispatch( $request );
324
		$data = $response->get_data();
325
326
		$this->assertEquals( 200, $response->get_status() );
327
		$this->assertEquals( $id3, $data[0]['id'] );
328
		// Check ordering. Default ORDER is DESC.
329
		$this->assertEquals( $id1, $data[0]['parent'] );
330
		$this->assertEquals( 0, $data[1]['parent'] );
331
		$this->assertEquals( 0, $data[2]['parent'] );
332
333
		$this->assertPostsOrderedBy( '{posts}.post_parent DESC' );
334
	}
335
336
	public function test_get_items_exclude_query() {
337
		$id1 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
338
		$id2 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
339
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
340
		$response = $this->server->dispatch( $request );
341
		$data = $response->get_data();
342
		$this->assertTrue( in_array( $id1, wp_list_pluck( $data, 'id' ), true ) );
343
		$this->assertTrue( in_array( $id2, wp_list_pluck( $data, 'id' ), true ) );
344
345
		$request->set_param( 'exclude', array( $id2 ) );
346
		$response = $this->server->dispatch( $request );
347
		$data = $response->get_data();
348
		$this->assertTrue( in_array( $id1, wp_list_pluck( $data, 'id' ), true ) );
349
		$this->assertFalse( in_array( $id2, wp_list_pluck( $data, 'id' ), true ) );
350
351
		$request->set_param( 'exclude', "$id2" );
352
		$response = $this->server->dispatch( $request );
353
		$data = $response->get_data();
354
		$this->assertTrue( in_array( $id1, wp_list_pluck( $data, 'id' ), true ) );
355
		$this->assertFalse( in_array( $id2, wp_list_pluck( $data, 'id' ), true ) );
356
357
		$request->set_param( 'exclude', 'invalid' );
358
		$response = $this->server->dispatch( $request );
359
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
360
	}
361
362
	public function test_get_items_search_query() {
363
		for ( $i = 0;  $i < 5;  $i++ ) {
364
			$this->factory->post->create( array( 'post_status' => 'publish' ) );
365
		}
366
		$this->factory->post->create( array( 'post_title' => 'Search Result', 'post_status' => 'publish' ) );
367
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
368
		$response = $this->server->dispatch( $request );
369
		$this->assertEquals( 7, count( $response->get_data() ) );
370
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
371
		$request->set_param( 'search', 'Search Result' );
372
		$response = $this->server->dispatch( $request );
373
		$data = $response->get_data();
374
		$this->assertEquals( 1, count( $data ) );
375
		$this->assertEquals( 'Search Result', $data[0]['title']['rendered'] );
376
	}
377
378
	public function test_get_items_slug_query() {
379
		$this->factory->post->create( array( 'post_title' => 'Apple', 'post_status' => 'publish' ) );
380
		$this->factory->post->create( array( 'post_title' => 'Banana', 'post_status' => 'publish' ) );
381
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
382
		$request->set_param( 'slug', 'apple' );
383
		$response = $this->server->dispatch( $request );
384
		$this->assertEquals( 200, $response->get_status() );
385
		$data = $response->get_data();
386
		$this->assertEquals( 1, count( $data ) );
387
		$this->assertEquals( 'Apple', $data[0]['title']['rendered'] );
388
	}
389
390
	public function test_get_items_multiple_slugs_array_query() {
391
		$this->factory->post->create( array( 'post_title' => 'Apple', 'post_status' => 'publish' ) );
392
		$this->factory->post->create( array( 'post_title' => 'Banana', 'post_status' => 'publish' ) );
393
		$this->factory->post->create( array( 'post_title' => 'Peach', 'post_status' => 'publish' ) );
394
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
395
		$request->set_param( 'slug', array( 'banana', 'peach' ) );
396
		$response = $this->server->dispatch( $request );
397
		$this->assertEquals( 200, $response->get_status() );
398
		$data = $response->get_data();
399
		$this->assertEquals( 2, count( $data ) );
400
		$titles = array(
401
			$data[0]['title']['rendered'],
402
			$data[1]['title']['rendered'],
403
		);
404
		sort( $titles );
405
		$this->assertEquals( array( 'Banana', 'Peach' ), $titles );
406
	}
407
408
	public function test_get_items_multiple_slugs_string_query() {
409
		$this->factory->post->create( array( 'post_title' => 'Apple', 'post_status' => 'publish' ) );
410
		$this->factory->post->create( array( 'post_title' => 'Banana', 'post_status' => 'publish' ) );
411
		$this->factory->post->create( array( 'post_title' => 'Peach', 'post_status' => 'publish' ) );
412
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
413
		$request->set_param( 'slug', 'apple,banana' );
414
		$response = $this->server->dispatch( $request );
415
		$this->assertEquals( 200, $response->get_status() );
416
		$data = $response->get_data();
417
		$this->assertEquals( 2, count( $data ) );
418
		$titles = array(
419
			$data[0]['title']['rendered'],
420
			$data[1]['title']['rendered'],
421
		);
422
		sort( $titles );
423
		$this->assertEquals( array( 'Apple', 'Banana' ), $titles );
424
	}
425
426
	public function test_get_items_status_query() {
427
		wp_set_current_user( 0 );
428
		$this->factory->post->create( array( 'post_status' => 'draft' ) );
429
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
430
		$request->set_param( 'status', 'publish' );
431
		$response = $this->server->dispatch( $request );
432
		$this->assertEquals( 200, $response->get_status() );
433
		$this->assertEquals( 1, count( $response->get_data() ) );
434
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
435
		$request->set_param( 'status', 'draft' );
436
		$response = $this->server->dispatch( $request );
437
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
438
		wp_set_current_user( self::$editor_id );
439
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
440
		$request->set_param( 'status', 'draft' );
441
		$response = $this->server->dispatch( $request );
442
		$this->assertEquals( 200, $response->get_status() );
443
		$this->assertEquals( 1, count( $response->get_data() ) );
444
	}
445
446
	public function test_get_items_multiple_statuses_string_query() {
447
		wp_set_current_user( self::$editor_id );
448
449
		$this->factory->post->create( array( 'post_status' => 'draft' ) );
450
		$this->factory->post->create( array( 'post_status' => 'private' ) );
451
		$this->factory->post->create( array( 'post_status' => 'publish' ) );
452
453
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
454
		$request->set_param( 'context', 'edit' );
455
		$request->set_param( 'status', 'draft,private' );
456
457
		$response = $this->server->dispatch( $request );
458
		$this->assertEquals( 200, $response->get_status() );
459
		$data = $response->get_data();
460
		$this->assertEquals( 2, count( $data ) );
461
		$statuses = array(
462
			$data[0]['status'],
463
			$data[1]['status'],
464
		);
465
		sort( $statuses );
466
		$this->assertEquals( array( 'draft', 'private' ), $statuses );
467
	}
468
469
	public function test_get_items_multiple_statuses_array_query() {
470
		wp_set_current_user( self::$editor_id );
471
472
		$this->factory->post->create( array( 'post_status' => 'draft' ) );
473
		$this->factory->post->create( array( 'post_status' => 'pending' ) );
474
		$this->factory->post->create( array( 'post_status' => 'publish' ) );
475
476
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
477
		$request->set_param( 'context', 'edit' );
478
		$request->set_param( 'status', array( 'draft', 'pending' ) );
479
480
		$response = $this->server->dispatch( $request );
481
		$this->assertEquals( 200, $response->get_status() );
482
		$data = $response->get_data();
483
		$this->assertEquals( 2, count( $data ) );
484
		$statuses = array(
485
			$data[0]['status'],
486
			$data[1]['status'],
487
		);
488
		sort( $statuses );
489
		$this->assertEquals( array( 'draft', 'pending' ), $statuses );
490
	}
491
492
	public function test_get_items_multiple_statuses_one_invalid_query() {
493
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
494
		$request->set_param( 'context', 'edit' );
495
		$request->set_param( 'status', array( 'draft', 'nonsense' ) );
496
		$response = $this->server->dispatch( $request );
497
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
498
	}
499
500
	public function test_get_items_invalid_status_query() {
501
		wp_set_current_user( 0 );
502
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
503
		$request->set_param( 'status', 'invalid' );
504
		$response = $this->server->dispatch( $request );
505
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
506
	}
507
508
	public function test_get_items_status_without_permissions() {
509
		$draft_id = $this->factory->post->create( array(
510
			'post_status' => 'draft',
511
		) );
512
		wp_set_current_user( 0 );
513
514
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
515
		$response = $this->server->dispatch( $request );
516
517
		$this->assertEquals( 200, $response->get_status() );
518
519
		$all_data = $response->get_data();
520
		foreach ( $all_data as $post ) {
521
			$this->assertNotEquals( $draft_id, $post['id'] );
522
		}
523
	}
524
525
	public function test_get_items_order_and_orderby() {
526
		$this->factory->post->create( array( 'post_title' => 'Apple Pie', 'post_status' => 'publish' ) );
527
		$this->factory->post->create( array( 'post_title' => 'Apple Sauce', 'post_status' => 'publish' ) );
528
		$this->factory->post->create( array( 'post_title' => 'Apple Cobbler', 'post_status' => 'publish' ) );
529
		$this->factory->post->create( array( 'post_title' => 'Apple Coffee Cake', 'post_status' => 'publish' ) );
530
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
531
		$request->set_param( 'search', 'Apple' );
532
		// order defaults to 'desc'
533
		$request->set_param( 'orderby', 'title' );
534
		$response = $this->server->dispatch( $request );
535
		$data = $response->get_data();
536
		$this->assertEquals( 'Apple Sauce', $data[0]['title']['rendered'] );
537
		$this->assertPostsOrderedBy( '{posts}.post_title DESC' );
538
		// order=>asc
539
		$request->set_param( 'order', 'asc' );
540
		$response = $this->server->dispatch( $request );
541
		$data = $response->get_data();
542
		$this->assertEquals( 'Apple Cobbler', $data[0]['title']['rendered'] );
543
		$this->assertPostsOrderedBy( '{posts}.post_title ASC' );
544
		// order=>asc,id should fail
545
		$request->set_param( 'order', 'asc,id' );
546
		$response = $this->server->dispatch( $request );
547
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
548
		// orderby=>content should fail (invalid param test)
549
		$request->set_param( 'order', 'asc' );
550
		$request->set_param( 'orderby', 'content' );
551
		$response = $this->server->dispatch( $request );
552
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
553
	}
554
555
	public function test_get_items_with_orderby_include_without_include_param() {
556
		$this->factory->post->create( array( 'post_status' => 'publish' ) );
557
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
558
		$request->set_param( 'orderby', 'include' );
559
560
		$response = $this->server->dispatch( $request );
561
562
		$this->assertErrorResponse( 'rest_orderby_include_missing_include', $response, 400 );
563
	}
564
565
	public function test_get_items_with_orderby_id() {
566
		$id1 = $this->factory->post->create( array( 'post_status' => 'publish', 'post_date' => '2016-01-13 02:26:48' ) );
567
		$id2 = $this->factory->post->create( array( 'post_status' => 'publish', 'post_date' => '2016-01-12 02:26:48' ) );
568
		$id3 = $this->factory->post->create( array( 'post_status' => 'publish', 'post_date' => '2016-01-11 02:26:48' ) );
569
570
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
571
		$request->set_param( 'orderby', 'id' );
572
		$request->set_param( 'include', array( $id1, $id2, $id3 ) );
573
574
		$response = $this->server->dispatch( $request );
575
		$data = $response->get_data();
576
577
		// Default ORDER is DESC.
578
		$this->assertEquals( $id3, $data[0]['id'] );
579
		$this->assertEquals( $id2, $data[1]['id'] );
580
		$this->assertEquals( $id1, $data[2]['id'] );
581
		$this->assertPostsOrderedBy( '{posts}.ID DESC' );
582
	}
583
584
	public function test_get_items_with_orderby_slug() {
585
		$id1 = $this->factory->post->create( array( 'post_title' => 'ABC', 'post_name' => 'xyz', 'post_status' => 'publish' ) );
586
		$id2 = $this->factory->post->create( array( 'post_title' => 'XYZ', 'post_name' => 'abc', 'post_status' => 'publish' ) );
587
588
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
589
		$request->set_param( 'orderby', 'slug' );
590
		$request->set_param( 'include', array( $id1, $id2 ) );
591
592
		$response = $this->server->dispatch( $request );
593
		$data = $response->get_data();
594
595
		// Default ORDER is DESC.
596
		$this->assertEquals( 'xyz', $data[0]['slug'] );
597
		$this->assertEquals( 'abc', $data[1]['slug'] );
598
		$this->assertPostsOrderedBy( '{posts}.post_name DESC' );
599
	}
600
601
	public function test_get_items_with_orderby_relevance() {
602
		$id1 = $this->factory->post->create( array( 'post_title' => 'Title is more relevant', 'post_content' => 'Content is', 'post_status' => 'publish' ) );
603
		$id2 = $this->factory->post->create( array( 'post_title' => 'Title is', 'post_content' => 'Content is less relevant', 'post_status' => 'publish' ) );
604
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
605
		$request->set_param( 'orderby', 'relevance' );
606
		$request->set_param( 'search', 'relevant' );
607
		$response = $this->server->dispatch( $request );
608
		$this->assertEquals( 200, $response->get_status() );
609
		$data = $response->get_data();
610
		$this->assertCount( 2, $data );
611
		$this->assertEquals( $id1, $data[0]['id'] );
612
		$this->assertEquals( $id2, $data[1]['id'] );
613
		$this->assertPostsOrderedBy( '{posts}.post_title LIKE \'%relevant%\' DESC, {posts}.post_date DESC' );
614
	}
615
616
	public function test_get_items_with_orderby_relevance_two_terms() {
617
		$id1 = $this->factory->post->create( array( 'post_title' => 'Title is more relevant', 'post_content' => 'Content is', 'post_status' => 'publish' ) );
618
		$id2 = $this->factory->post->create( array( 'post_title' => 'Title is', 'post_content' => 'Content is less relevant', 'post_status' => 'publish' ) );
619
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
620
		$request->set_param( 'orderby', 'relevance' );
621
		$request->set_param( 'search', 'relevant content' );
622
		$response = $this->server->dispatch( $request );
623
		$this->assertEquals( 200, $response->get_status() );
624
		$data = $response->get_data();
625
		$this->assertCount( 2, $data );
626
		$this->assertEquals( $id1, $data[0]['id'] );
627
		$this->assertEquals( $id2, $data[1]['id'] );
628
		$this->assertPostsOrderedBy( '(CASE WHEN {posts}.post_title LIKE \'%relevant content%\' THEN 1 WHEN {posts}.post_title LIKE \'%relevant%\' AND {posts}.post_title LIKE \'%content%\' THEN 2 WHEN {posts}.post_title LIKE \'%relevant%\' OR {posts}.post_title LIKE \'%content%\' THEN 3 WHEN {posts}.post_excerpt LIKE \'%relevant content%\' THEN 4 WHEN {posts}.post_content LIKE \'%relevant content%\' THEN 5 ELSE 6 END), {posts}.post_date DESC' );
629
	}
630
631
	public function test_get_items_with_orderby_relevance_missing_search() {
632
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
633
		$request->set_param( 'orderby', 'relevance' );
634
		$response = $this->server->dispatch( $request );
635
		$this->assertErrorResponse( 'rest_no_search_term_defined', $response, 400 );
636
	}
637
638
	public function test_get_items_offset_query() {
639
		$id1 = self::$post_id;
0 ignored issues
show
Unused Code introduced by
$id1 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
640
		$id2 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
0 ignored issues
show
Unused Code introduced by
$id2 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
641
		$id3 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
0 ignored issues
show
Unused Code introduced by
$id3 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
642
		$id4 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
0 ignored issues
show
Unused Code introduced by
$id4 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
643
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
644
		$request->set_param( 'offset', 1 );
645
		$response = $this->server->dispatch( $request );
646
		$this->assertCount( 3, $response->get_data() );
647
		// 'offset' works with 'per_page'
648
		$request->set_param( 'per_page', 2 );
649
		$response = $this->server->dispatch( $request );
650
		$this->assertCount( 2, $response->get_data() );
651
		// 'offset' takes priority over 'page'
652
		$request->set_param( 'page', 2 );
653
		$response = $this->server->dispatch( $request );
654
		$this->assertCount( 2, $response->get_data() );
655
		// Invalid 'offset' should error
656
		$request->set_param( 'offset', 'moreplease' );
657
		$response = $this->server->dispatch( $request );
658
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
659
	}
660
661
	public function test_get_items_tags_query() {
662
		$id1 = self::$post_id;
663
		$id2 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
0 ignored issues
show
Unused Code introduced by
$id2 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
664
		$id3 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
0 ignored issues
show
Unused Code introduced by
$id3 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
665
		$id4 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
0 ignored issues
show
Unused Code introduced by
$id4 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
666
		$tag = wp_insert_term( 'My Tag', 'post_tag' );
667
668
		wp_set_object_terms( $id1, array( $tag['term_id'] ), 'post_tag' );
669
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
670
		$request->set_param( 'tags', array( $tag['term_id'] ) );
671
672
		$response = $this->server->dispatch( $request );
673
		$data = $response->get_data();
674
		$this->assertCount( 1, $data );
675
		$this->assertEquals( $id1, $data[0]['id'] );
676
	}
677
678
	public function test_get_items_tags_exclude_query() {
679
		$id1 = self::$post_id;
680
		$id2 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
681
		$id3 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
682
		$id4 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
683
		$tag = wp_insert_term( 'My Tag', 'post_tag' );
684
685
		wp_set_object_terms( $id1, array( $tag['term_id'] ), 'post_tag' );
686
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
687
		$request->set_param( 'tags_exclude', array( $tag['term_id'] ) );
688
689
		$response = $this->server->dispatch( $request );
690
		$data = $response->get_data();
691
		$this->assertCount( 3, $data );
692
		$this->assertEquals( $id4, $data[0]['id'] );
693
		$this->assertEquals( $id3, $data[1]['id'] );
694
		$this->assertEquals( $id2, $data[2]['id'] );
695
	}
696
697
	public function test_get_items_tags_and_categories_query() {
698
		$id1 = self::$post_id;
699
		$id2 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
700
		$id3 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
0 ignored issues
show
Unused Code introduced by
$id3 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
701
		$id4 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
0 ignored issues
show
Unused Code introduced by
$id4 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
702
		$tag = wp_insert_term( 'My Tag', 'post_tag' );
703
		$category = wp_insert_term( 'My Category', 'category' );
704
705
		wp_set_object_terms( $id1, array( $tag['term_id'] ), 'post_tag' );
706
		wp_set_object_terms( $id2, array( $tag['term_id'] ), 'post_tag' );
707
		wp_set_object_terms( $id1, array( $category['term_id'] ), 'category' );
708
709
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
710
		$request->set_param( 'tags', array( $tag['term_id'] ) );
711
		$request->set_param( 'categories', array( $category['term_id'] ) );
712
713
		$response = $this->server->dispatch( $request );
714
		$this->assertCount( 1, $response->get_data() );
715
716
		$request->set_param( 'tags', array( 'my-tag' ) );
717
		$response = $this->server->dispatch( $request );
718
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
719
	}
720
721
	public function test_get_items_tags_and_categories_exclude_query() {
722
		$id1 = self::$post_id;
723
		$id2 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
724
		$id3 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
0 ignored issues
show
Unused Code introduced by
$id3 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
725
		$id4 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
0 ignored issues
show
Unused Code introduced by
$id4 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
726
		$tag = wp_insert_term( 'My Tag', 'post_tag' );
727
		$category = wp_insert_term( 'My Category', 'category' );
728
729
		wp_set_object_terms( $id1, array( $tag['term_id'] ), 'post_tag' );
730
		wp_set_object_terms( $id2, array( $tag['term_id'] ), 'post_tag' );
731
		wp_set_object_terms( $id1, array( $category['term_id'] ), 'category' );
732
733
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
734
		$request->set_param( 'tags', array( $tag['term_id'] ) );
735
		$request->set_param( 'categories_exclude', array( $category['term_id'] ) );
736
737
		$response = $this->server->dispatch( $request );
738
		$data = $response->get_data();
739
		$this->assertCount( 1, $data );
740
		$this->assertEquals( $id2, $data[0]['id'] );
741
742
		$request->set_param( 'tags_exclude', array( 'my-tag' ) );
743
		$response = $this->server->dispatch( $request );
744
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
745
	}
746
747
	public function test_get_items_sticky() {
748
		$id1 = self::$post_id;
0 ignored issues
show
Unused Code introduced by
$id1 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
749
		$id2 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
750
751
		update_option( 'sticky_posts', array( $id2 ) );
752
753
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
754
		$request->set_param( 'sticky', true );
755
756
		$response = $this->server->dispatch( $request );
757
		$this->assertCount( 1, $response->get_data() );
758
759
		$posts = $response->get_data();
760
		$post = $posts[0];
761
		$this->assertEquals( $id2, $post['id'] );
762
763
		$request->set_param( 'sticky', 'nothanks' );
764
		$response = $this->server->dispatch( $request );
765
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
766
	}
767
768
	public function test_get_items_sticky_with_include() {
769
		$id1 = self::$post_id;
770
		$id2 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
771
		$id3 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
0 ignored issues
show
Unused Code introduced by
$id3 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
772
773
		update_option( 'sticky_posts', array( $id2 ) );
774
775
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
776
		$request->set_param( 'sticky', true );
777
		$request->set_param( 'include', array( $id1 ) );
778
779
		$response = $this->server->dispatch( $request );
780
		$this->assertCount( 0, $response->get_data() );
781
782
		// FIXME Since this request returns zero posts, the query is executed twice.
783
		$this->assertCount( 2, $this->posts_clauses );
784
		$this->posts_clauses = array_slice( $this->posts_clauses, 0, 1 );
785
786
		$this->assertPostsWhere( " AND {posts}.ID IN (0) AND {posts}.post_type = 'post' AND (({posts}.post_status = 'publish'))" );
787
788
		update_option( 'sticky_posts', array( $id1, $id2 ) );
789
790
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
791
		$request->set_param( 'sticky', true );
792
		$request->set_param( 'include', array( $id1 ) );
793
794
		$response = $this->server->dispatch( $request );
795
796
		$this->assertCount( 1, $response->get_data() );
797
798
		$posts = $response->get_data();
799
		$post = $posts[0];
800
		$this->assertEquals( $id1, $post['id'] );
801
802
		$this->assertPostsWhere( " AND {posts}.ID IN ($id1) AND {posts}.post_type = 'post' AND (({posts}.post_status = 'publish'))" );
803
	}
804
805
	public function test_get_items_sticky_no_sticky_posts() {
806
		$id1 = self::$post_id;
0 ignored issues
show
Unused Code introduced by
$id1 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
807
808
		update_option( 'sticky_posts', array() );
809
810
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
811
		$request->set_param( 'sticky', true );
812
813
		$response = $this->server->dispatch( $request );
814
		$this->assertCount( 0, $response->get_data() );
815
816
		// FIXME Since this request returns zero posts, the query is executed twice.
817
		$this->assertCount( 2, $this->posts_clauses );
818
		$this->posts_clauses = array_slice( $this->posts_clauses, 0, 1 );
819
820
		$this->assertPostsWhere( " AND {posts}.ID IN (0) AND {posts}.post_type = 'post' AND (({posts}.post_status = 'publish'))" );
821
	}
822
823
	public function test_get_items_sticky_with_include_no_sticky_posts() {
824
		$id1 = self::$post_id;
825
826
		update_option( 'sticky_posts', array() );
827
828
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
829
		$request->set_param( 'sticky', true );
830
		$request->set_param( 'include', array( $id1 ) );
831
832
		$response = $this->server->dispatch( $request );
833
		$this->assertCount( 0, $response->get_data() );
834
835
		// FIXME Since this request returns zero posts, the query is executed twice.
836
		$this->assertCount( 2, $this->posts_clauses );
837
		$this->posts_clauses = array_slice( $this->posts_clauses, 0, 1 );
838
839
		$this->assertPostsWhere( " AND {posts}.ID IN (0) AND {posts}.post_type = 'post' AND (({posts}.post_status = 'publish'))" );
840
	}
841
842
	public function test_get_items_not_sticky() {
843
		$id1 = self::$post_id;
844
		$id2 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
845
846
		update_option( 'sticky_posts', array( $id2 ) );
847
848
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
849
		$request->set_param( 'sticky', false );
850
851
		$response = $this->server->dispatch( $request );
852
		$this->assertCount( 1, $response->get_data() );
853
854
		$posts = $response->get_data();
855
		$post = $posts[0];
856
		$this->assertEquals( $id1, $post['id'] );
857
858
		$this->assertPostsWhere( " AND {posts}.ID NOT IN ($id2) AND {posts}.post_type = 'post' AND (({posts}.post_status = 'publish'))" );
859
	}
860
861
	public function test_get_items_not_sticky_with_exclude() {
862
		$id1 = self::$post_id;
863
		$id2 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
864
		$id3 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
865
866
		update_option( 'sticky_posts', array( $id2 ) );
867
868
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
869
		$request->set_param( 'sticky', false );
870
		$request->set_param( 'exclude', array( $id3 ) );
871
872
		$response = $this->server->dispatch( $request );
873
		$this->assertCount( 1, $response->get_data() );
874
875
		$posts = $response->get_data();
876
		$post = $posts[0];
877
		$this->assertEquals( $id1, $post['id'] );
878
879
		$this->assertPostsWhere( " AND {posts}.ID NOT IN ($id3,$id2) AND {posts}.post_type = 'post' AND (({posts}.post_status = 'publish'))" );
880
	}
881
882
	public function test_get_items_not_sticky_with_exclude_no_sticky_posts() {
883
		$id1 = self::$post_id;
884
		$id2 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
885
		$id3 = $this->factory->post->create( array( 'post_status' => 'publish' ) );
886
887
		update_option( 'sticky_posts', array() );
888
889
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
890
		$request->set_param( 'sticky', false );
891
		$request->set_param( 'exclude', array( $id3 ) );
892
893
		$response = $this->server->dispatch( $request );
894
		$this->assertCount( 2, $response->get_data() );
895
896
		$posts = $response->get_data();
897
		$ids = wp_list_pluck( $posts, 'id' );
898
		sort( $ids );
899
		$this->assertEquals( array( $id1, $id2 ), $ids );
900
901
		$this->assertPostsWhere( " AND {posts}.ID NOT IN ($id3) AND {posts}.post_type = 'post' AND (({posts}.post_status = 'publish'))" );
902
	}
903
904
	public function test_get_items_pagination_headers() {
905
		// Start of the index
906
		for ( $i = 0; $i < 49; $i++ ) {
907
			$this->factory->post->create( array(
908
				'post_title'   => "Post {$i}",
909
				) );
910
		}
911
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
912
		$response = $this->server->dispatch( $request );
913
		$headers = $response->get_headers();
914
		$this->assertEquals( 50, $headers['X-WP-Total'] );
915
		$this->assertEquals( 5, $headers['X-WP-TotalPages'] );
916
		$next_link = add_query_arg( array(
917
			'page'    => 2,
918
			), rest_url( '/wp/v2/posts' ) );
919
		$this->assertFalse( stripos( $headers['Link'], 'rel="prev"' ) );
920
		$this->assertContains( '<' . $next_link . '>; rel="next"', $headers['Link'] );
921
		// 3rd page
922
		$this->factory->post->create( array(
923
				'post_title'   => 'Post 51',
924
				) );
925
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
926
		$request->set_param( 'page', 3 );
927
		$response = $this->server->dispatch( $request );
928
		$headers = $response->get_headers();
929
		$this->assertEquals( 51, $headers['X-WP-Total'] );
930
		$this->assertEquals( 6, $headers['X-WP-TotalPages'] );
931
		$prev_link = add_query_arg( array(
932
			'page'    => 2,
933
			), rest_url( '/wp/v2/posts' ) );
934
		$this->assertContains( '<' . $prev_link . '>; rel="prev"', $headers['Link'] );
935
		$next_link = add_query_arg( array(
936
			'page'    => 4,
937
			), rest_url( '/wp/v2/posts' ) );
938
		$this->assertContains( '<' . $next_link . '>; rel="next"', $headers['Link'] );
939
		// Last page
940
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
941
		$request->set_param( 'page', 6 );
942
		$response = $this->server->dispatch( $request );
943
		$headers = $response->get_headers();
944
		$this->assertEquals( 51, $headers['X-WP-Total'] );
945
		$this->assertEquals( 6, $headers['X-WP-TotalPages'] );
946
		$prev_link = add_query_arg( array(
947
			'page'    => 5,
948
			), rest_url( '/wp/v2/posts' ) );
949
		$this->assertContains( '<' . $prev_link . '>; rel="prev"', $headers['Link'] );
950
		$this->assertFalse( stripos( $headers['Link'], 'rel="next"' ) );
951
952
		// Out of bounds
953
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
954
		$request->set_param( 'page', 8 );
955
		$response = $this->server->dispatch( $request );
956
		$headers = $response->get_headers();
0 ignored issues
show
Unused Code introduced by
$headers is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
957
		$this->assertErrorResponse( 'rest_post_invalid_page_number', $response, 400 );
958
959
		// With query params.
960
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
961
		$request->set_query_params( array( 'per_page' => 5, 'page' => 2 ) );
962
		$response = $this->server->dispatch( $request );
963
		$headers = $response->get_headers();
964
		$this->assertEquals( 51, $headers['X-WP-Total'] );
965
		$this->assertEquals( 11, $headers['X-WP-TotalPages'] );
966
		$prev_link = add_query_arg( array(
967
			'per_page' => 5,
968
			'page'     => 1,
969
			), rest_url( '/wp/v2/posts' ) );
970
		$this->assertContains( '<' . $prev_link . '>; rel="prev"', $headers['Link'] );
971
		$next_link = add_query_arg( array(
972
			'per_page' => 5,
973
			'page'     => 3,
974
			), rest_url( '/wp/v2/posts' ) );
975
		$this->assertContains( '<' . $next_link . '>; rel="next"', $headers['Link'] );
976
	}
977
978
	public function test_get_items_private_status_query_var() {
979
		// Private query vars inaccessible to unauthorized users
980
		wp_set_current_user( 0 );
981
		$draft_id = $this->factory->post->create( array( 'post_status' => 'draft' ) );
982
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
983
		$request->set_param( 'status', 'draft' );
984
		$response = $this->server->dispatch( $request );
985
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
986
987
		// But they are accessible to authorized users
988
		wp_set_current_user( self::$editor_id );
989
		$response = $this->server->dispatch( $request );
990
		$data = $response->get_data();
991
		$this->assertCount( 1, $data );
992
		$this->assertEquals( $draft_id, $data[0]['id'] );
993
	}
994
995
	public function test_get_items_invalid_per_page() {
996
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
997
		$request->set_query_params( array( 'per_page' => -1 ) );
998
		$response = $this->server->dispatch( $request );
999
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
1000
	}
1001
1002
	/**
1003
	 * @ticket 39061
1004
	 */
1005
	public function test_get_items_invalid_max_pages() {
1006
		// Out of bounds
1007
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
1008
		$request->set_param( 'page', REST_TESTS_IMPOSSIBLY_HIGH_NUMBER );
1009
		$response = $this->server->dispatch( $request );
1010
		$this->assertErrorResponse( 'rest_post_invalid_page_number', $response, 400 );
1011
	}
1012
1013
	public function test_get_items_invalid_context() {
1014
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
1015
		$request->set_param( 'context', 'banana' );
1016
		$response = $this->server->dispatch( $request );
1017
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
1018
	}
1019
1020
	public function test_get_items_invalid_date() {
1021
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
1022
		$request->set_param( 'after', rand_str() );
1023
		$request->set_param( 'before', rand_str() );
1024
		$response = $this->server->dispatch( $request );
1025
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
1026
	}
1027
1028
	public function test_get_items_valid_date() {
1029
		$post1 = $this->factory->post->create( array( 'post_date' => '2016-01-15T00:00:00Z' ) );
0 ignored issues
show
Unused Code introduced by
$post1 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1030
		$post2 = $this->factory->post->create( array( 'post_date' => '2016-01-16T00:00:00Z' ) );
1031
		$post3 = $this->factory->post->create( array( 'post_date' => '2016-01-17T00:00:00Z' ) );
0 ignored issues
show
Unused Code introduced by
$post3 is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1032
1033
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
1034
		$request->set_param( 'after', '2016-01-15T00:00:00Z' );
1035
		$request->set_param( 'before', '2016-01-17T00:00:00Z' );
1036
		$response = $this->server->dispatch( $request );
1037
		$data = $response->get_data();
1038
		$this->assertCount( 1, $data );
1039
		$this->assertEquals( $post2, $data[0]['id'] );
1040
	}
1041
1042
	public function test_get_items_all_post_formats() {
1043
		$request = new WP_REST_Request( 'OPTIONS', '/wp/v2/posts' );
1044
		$response = $this->server->dispatch( $request );
1045
		$data = $response->get_data();
1046
1047
		$formats = array_values( get_post_format_slugs() );
1048
1049
		$this->assertEquals( $formats, $data['schema']['properties']['format']['enum'] );
1050
	}
1051
1052
	public function test_get_item() {
1053
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
1054
		$response = $this->server->dispatch( $request );
1055
1056
		$this->check_get_post_response( $response, 'view' );
1057
	}
1058
1059
	public function test_get_item_links() {
1060
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
1061
		$response = $this->server->dispatch( $request );
1062
1063
		$links = $response->get_links();
1064
1065
		$this->assertEquals( rest_url( '/wp/v2/posts/' . self::$post_id ), $links['self'][0]['href'] );
1066
		$this->assertEquals( rest_url( '/wp/v2/posts' ), $links['collection'][0]['href'] );
1067
1068
		$this->assertEquals( rest_url( '/wp/v2/types/' . get_post_type( self::$post_id ) ), $links['about'][0]['href'] );
1069
1070
		$replies_url = rest_url( '/wp/v2/comments' );
1071
		$replies_url = add_query_arg( 'post', self::$post_id, $replies_url );
1072
		$this->assertEquals( $replies_url, $links['replies'][0]['href'] );
1073
1074
		$this->assertEquals( rest_url( '/wp/v2/posts/' . self::$post_id . '/revisions' ), $links['version-history'][0]['href'] );
1075
1076
		$attachments_url = rest_url( '/wp/v2/media' );
1077
		$attachments_url = add_query_arg( 'parent', self::$post_id, $attachments_url );
1078
		$this->assertEquals( $attachments_url, $links['https://api.w.org/attachment'][0]['href'] );
1079
1080
		$term_links = $links['https://api.w.org/term'];
1081
		$tag_link = $cat_link = $format_link = null;
1082
		foreach ( $term_links as $link ) {
1083
			if ( 'post_tag' === $link['attributes']['taxonomy'] ) {
1084
				$tag_link = $link;
1085
			} elseif ( 'category' === $link['attributes']['taxonomy'] ) {
1086
				$cat_link = $link;
1087
			} elseif ( 'post_format' === $link['attributes']['taxonomy'] ) {
1088
				$format_link = $link;
1089
			}
1090
		}
1091
		$this->assertNotEmpty( $tag_link );
1092
		$this->assertNotEmpty( $cat_link );
1093
		$this->assertNull( $format_link );
1094
1095
		$tags_url = add_query_arg( 'post', self::$post_id, rest_url( '/wp/v2/tags' ) );
1096
		$this->assertEquals( $tags_url, $tag_link['href'] );
1097
1098
		$category_url = add_query_arg( 'post', self::$post_id, rest_url( '/wp/v2/categories' ) );
1099
		$this->assertEquals( $category_url, $cat_link['href'] );
1100
	}
1101
1102
	public function test_get_item_links_no_author() {
1103
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
1104
		$response = $this->server->dispatch( $request );
1105
		$links = $response->get_links();
1106
		$this->assertFalse( isset( $links['author'] ) );
1107
		wp_update_post( array( 'ID' => self::$post_id, 'post_author' => self::$author_id ) );
1108
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
1109
		$response = $this->server->dispatch( $request );
1110
		$links = $response->get_links();
1111
		$this->assertEquals( rest_url( '/wp/v2/users/' . self::$author_id ), $links['author'][0]['href'] );
1112
	}
1113
1114
	public function test_get_post_without_permission() {
1115
		$draft_id = $this->factory->post->create( array(
1116
			'post_status' => 'draft',
1117
		) );
1118
		wp_set_current_user( 0 );
1119
1120
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', $draft_id ) );
1121
		$response = $this->server->dispatch( $request );
1122
1123
		$this->assertErrorResponse( 'rest_forbidden', $response, 403 );
1124
	}
1125
1126
	public function test_get_post_invalid_id() {
1127
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . REST_TESTS_IMPOSSIBLY_HIGH_NUMBER );
1128
		$response = $this->server->dispatch( $request );
1129
1130
		$this->assertErrorResponse( 'rest_post_invalid_id', $response, 404 );
1131
	}
1132
1133
	public function test_get_post_list_context_with_permission() {
1134
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
1135
		$request->set_query_params( array(
1136
			'context' => 'edit',
1137
		) );
1138
1139
		wp_set_current_user( self::$editor_id );
1140
1141
		$response = $this->server->dispatch( $request );
1142
1143
		$this->check_get_posts_response( $response, 'edit' );
1144
	}
1145
1146
	public function test_get_post_list_context_without_permission() {
1147
		wp_set_current_user( 0 );
1148
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts' );
1149
		$request->set_query_params( array(
1150
			'context' => 'edit',
1151
		) );
1152
		$response = $this->server->dispatch( $request );
1153
1154
		$this->assertErrorResponse( 'rest_forbidden_context', $response, 401 );
1155
	}
1156
1157
	public function test_get_post_context_without_permission() {
1158
		wp_set_current_user( 0 );
1159
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
1160
		$request->set_query_params( array(
1161
			'context' => 'edit',
1162
		) );
1163
		$response = $this->server->dispatch( $request );
1164
1165
		$this->assertErrorResponse( 'rest_forbidden_context', $response, 401 );
1166
	}
1167
1168
	public function test_get_post_with_password() {
1169
		$post_id = $this->factory->post->create( array(
1170
			'post_password' => '$inthebananastand',
1171
		) );
1172
1173
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', $post_id ) );
1174
		$response = $this->server->dispatch( $request );
1175
1176
		$this->check_get_post_response( $response, 'view' );
1177
1178
		$data = $response->get_data();
1179
		$this->assertEquals( '', $data['content']['rendered'] );
1180
		$this->assertTrue( $data['content']['protected'] );
1181
		$this->assertEquals( '', $data['excerpt']['rendered'] );
1182
		$this->assertTrue( $data['excerpt']['protected'] );
1183
	}
1184
1185
	public function test_get_post_with_password_using_password() {
1186
		$post_id = $this->factory->post->create( array(
1187
			'post_password' => '$inthebananastand',
1188
			'post_content'  => 'Some secret content.',
1189
			'post_excerpt'  => 'Some secret excerpt.',
1190
		) );
1191
1192
		$post = get_post( $post_id );
1193
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', $post_id ) );
1194
		$request->set_param( 'password', '$inthebananastand' );
1195
		$response = $this->server->dispatch( $request );
1196
1197
		$this->check_get_post_response( $response, 'view' );
1198
1199
		$data = $response->get_data();
1200
		$this->assertEquals( wpautop( $post->post_content ), $data['content']['rendered'] );
1201
		$this->assertTrue( $data['content']['protected'] );
1202
		$this->assertEquals( wpautop( $post->post_excerpt ), $data['excerpt']['rendered'] );
1203
		$this->assertTrue( $data['excerpt']['protected'] );
1204
	}
1205
1206
	public function test_get_post_with_password_using_incorrect_password() {
1207
		$post_id = $this->factory->post->create( array(
1208
			'post_password' => '$inthebananastand',
1209
		) );
1210
1211
		$post = get_post( $post_id );
0 ignored issues
show
Unused Code introduced by
$post is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
1212
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', $post_id ) );
1213
		$request->set_param( 'password', 'wrongpassword' );
1214
		$response = $this->server->dispatch( $request );
1215
1216
		$this->assertErrorResponse( 'rest_post_incorrect_password', $response, 403 );
1217
	}
1218
1219
	public function test_get_post_with_password_without_permission() {
1220
		$post_id = $this->factory->post->create( array(
1221
			'post_password' => '$inthebananastand',
1222
			'post_content'  => 'Some secret content.',
1223
			'post_excerpt'  => 'Some secret excerpt.',
1224
		) );
1225
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', $post_id ) );
1226
		$response = $this->server->dispatch( $request );
1227
		$data = $response->get_data();
1228
		$this->check_get_post_response( $response, 'view' );
1229
		$this->assertEquals( '', $data['content']['rendered'] );
1230
		$this->assertTrue( $data['content']['protected'] );
1231
		$this->assertEquals( '', $data['excerpt']['rendered'] );
1232
		$this->assertTrue( $data['excerpt']['protected'] );
1233
	}
1234
1235
	public function test_get_item_read_permission_custom_post_status() {
1236
		register_post_status( 'testpubstatus', array( 'public' => true ) );
1237
		register_post_status( 'testprivtatus', array( 'public' => false ) );
1238
		// Public status
1239
		wp_update_post( array( 'ID' => self::$post_id, 'post_status' => 'testpubstatus' ) );
1240
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
1241
		$response = $this->server->dispatch( $request );
1242
		$this->assertEquals( 200, $response->get_status() );
1243
		// Private status
1244
		wp_update_post( array( 'ID' => self::$post_id, 'post_status' => 'testprivtatus' ) );
1245
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
1246
		$response = $this->server->dispatch( $request );
1247
		$this->assertEquals( 403, $response->get_status() );
1248
	}
1249
1250
	public function test_prepare_item() {
1251
		wp_set_current_user( self::$editor_id );
1252
1253
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
1254
		$request->set_query_params( array( 'context' => 'edit' ) );
1255
		$response = $this->server->dispatch( $request );
1256
1257
		$this->check_get_post_response( $response, 'edit' );
1258
	}
1259
1260
	public function test_create_item() {
1261
		wp_set_current_user( self::$editor_id );
1262
1263
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1264
		$request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
1265
		$params = $this->set_post_data();
1266
		$request->set_body_params( $params );
1267
		$response = $this->server->dispatch( $request );
1268
1269
		$this->check_create_post_response( $response );
1270
	}
1271
1272
	public function post_dates_provider() {
1273
		$all_statuses = array(
1274
			'draft',
1275
			'publish',
1276
			'future',
1277
			'pending',
1278
			'private',
1279
		);
1280
1281
		$cases_short = array(
1282
			'set date without timezone' => array(
1283
				'statuses' => $all_statuses,
1284
				'params'   => array(
1285
					'timezone_string' => 'America/New_York',
1286
					'date'            => '2016-12-12T14:00:00',
1287
				),
1288
				'results' => array(
1289
					'date'            => '2016-12-12T14:00:00',
1290
					'date_gmt'        => '2016-12-12T19:00:00',
1291
				),
1292
			),
1293
			'set date_gmt without timezone' => array(
1294
				'statuses' => $all_statuses,
1295
				'params'   => array(
1296
					'timezone_string' => 'America/New_York',
1297
					'date_gmt'        => '2016-12-12T19:00:00',
1298
				),
1299
				'results' => array(
1300
					'date'            => '2016-12-12T14:00:00',
1301
					'date_gmt'        => '2016-12-12T19:00:00',
1302
				),
1303
			),
1304
			'set date with timezone' => array(
1305
				'statuses' => array( 'draft', 'publish' ),
1306
				'params'   => array(
1307
					'timezone_string' => 'America/New_York',
1308
					'date'            => '2016-12-12T18:00:00-01:00',
1309
				),
1310
				'results' => array(
1311
					'date'            => '2016-12-12T14:00:00',
1312
					'date_gmt'        => '2016-12-12T19:00:00',
1313
				),
1314
			),
1315
			'set date_gmt with timezone' => array(
1316
				'statuses' => array( 'draft', 'publish' ),
1317
				'params'   => array(
1318
					'timezone_string' => 'America/New_York',
1319
					'date_gmt'        => '2016-12-12T18:00:00-01:00',
1320
				),
1321
				'results' => array(
1322
					'date'            => '2016-12-12T14:00:00',
1323
					'date_gmt'        => '2016-12-12T19:00:00',
1324
				),
1325
			),
1326
		);
1327
1328
		$cases = array();
1329
		foreach ( $cases_short as $description => $case ) {
1330
			foreach ( $case['statuses'] as $status ) {
1331
				$cases[ $description . ', status=' . $status ] = array(
1332
					$status,
1333
					$case['params'],
1334
					$case['results'],
1335
				);
1336
			}
1337
		}
1338
1339
		return $cases;
1340
	}
1341
1342
	/**
1343
	 * @dataProvider post_dates_provider
1344
	 */
1345
	public function test_create_post_date( $status, $params, $results ) {
1346
		wp_set_current_user( self::$editor_id );
1347
		update_option( 'timezone_string', $params['timezone_string'] );
1348
1349
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1350
		$request->set_param( 'status', $status );
1351
		$request->set_param( 'title', 'not empty' );
1352
		if ( isset( $params['date'] ) ) {
1353
			$request->set_param( 'date', $params['date'] );
1354
		}
1355
		if ( isset( $params['date_gmt'] ) ) {
1356
			$request->set_param( 'date_gmt', $params['date_gmt'] );
1357
		}
1358
		$response = $this->server->dispatch( $request );
1359
1360
		update_option( 'timezone_string', '' );
1361
1362
		$this->assertEquals( 201, $response->get_status() );
1363
		$data = $response->get_data();
1364
		$post = get_post( $data['id'] );
1365
1366
		$this->assertEquals( $results['date'], $data['date'] );
1367
		$post_date = str_replace( 'T', ' ', $results['date'] );
1368
		$this->assertEquals( $post_date, $post->post_date );
1369
1370
		$this->assertEquals( $results['date_gmt'], $data['date_gmt'] );
1371
		$post_date_gmt = str_replace( 'T', ' ', $results['date_gmt'] );
1372
		$this->assertEquals( $post_date_gmt, $post->post_date_gmt );
1373
	}
1374
1375
	/**
1376
	 * @ticket 38698
1377
	 */
1378
	public function test_create_item_with_template() {
1379
		wp_set_current_user( self::$editor_id );
1380
		add_filter( 'theme_post_templates', array( $this, 'filter_theme_post_templates' ) );
1381
1382
		// reregister the route as we now have a template available.
1383
		$GLOBALS['wp_rest_server']->override_by_default = true;
1384
		$controller = new WP_REST_Posts_Controller( 'post' );
1385
		$controller->register_routes();
1386
		$GLOBALS['wp_rest_server']->override_by_default = false;
1387
1388
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1389
		$params = $this->set_post_data( array(
1390
			'template' => 'post-my-test-template.php',
1391
		) );
1392
		$request->set_body_params( $params );
1393
		$response = $this->server->dispatch( $request );
1394
1395
		$data = $response->get_data();
1396
		$post_template = get_page_template_slug( get_post( $data['id'] ) );
0 ignored issues
show
Bug introduced by
It seems like get_post($data['id']) targeting get_post() can also be of type array; however, get_page_template_slug() does only seem to accept integer|object<WP_Post>|null, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
1397
1398
		remove_filter( 'theme_post_templates', array( $this, 'filter_theme_post_templates' ) );
1399
1400
		$this->assertEquals( 'post-my-test-template.php', $data['template'] );
1401
		$this->assertEquals( 'post-my-test-template.php', $post_template );
1402
	}
1403
1404
	/**
1405
	 * @ticket 38698
1406
	 */
1407
	public function test_create_item_with_template_none_available() {
1408
		wp_set_current_user( self::$editor_id );
1409
1410
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1411
		$params = $this->set_post_data( array(
1412
			'template' => 'post-my-test-template.php',
1413
		) );
1414
		$request->set_body_params( $params );
1415
		$response = $this->server->dispatch( $request );
1416
1417
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
1418
	}
1419
1420
	/**
1421
	 * @ticket 38877
1422
	 */
1423
	public function test_create_item_with_template_none() {
1424
		wp_set_current_user( self::$editor_id );
1425
		add_filter( 'theme_post_templates', array( $this, 'filter_theme_post_templates' ) );
1426
		update_post_meta( self::$post_id, '_wp_page_template', 'post-my-test-template.php' );
1427
1428
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
1429
		$params = $this->set_post_data( array(
1430
			'template' => '',
1431
		) );
1432
		$request->set_body_params( $params );
1433
		$response = $this->server->dispatch( $request );
1434
1435
		$data = $response->get_data();
1436
		$post_template = get_page_template_slug( get_post( $data['id'] ) );
0 ignored issues
show
Bug introduced by
It seems like get_post($data['id']) targeting get_post() can also be of type array; however, get_page_template_slug() does only seem to accept integer|object<WP_Post>|null, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
1437
1438
		$this->assertEquals( '', $data['template'] );
1439
		$this->assertEquals( '', $post_template );
1440
	}
1441
1442
	public function test_rest_create_item() {
1443
		wp_set_current_user( self::$editor_id );
1444
1445
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1446
		$request->add_header( 'content-type', 'application/json' );
1447
		$params = $this->set_post_data();
1448
		$request->set_body( wp_json_encode( $params ) );
0 ignored issues
show
Security Bug introduced by
It seems like wp_json_encode($params) targeting wp_json_encode() can also be of type false; however, WP_REST_Request::set_body() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
1449
		$response = $this->server->dispatch( $request );
1450
1451
		$this->check_create_post_response( $response );
1452
	}
1453
1454
	public function test_create_post_invalid_id() {
1455
		wp_set_current_user( self::$editor_id );
1456
1457
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1458
		$params = $this->set_post_data( array(
1459
			'id' => '3',
1460
		) );
1461
		$request->set_body_params( $params );
1462
		$response = $this->server->dispatch( $request );
1463
1464
		$this->assertErrorResponse( 'rest_post_exists', $response, 400 );
1465
	}
1466
1467
	public function test_create_post_as_contributor() {
1468
		wp_set_current_user( self::$contributor_id );
1469
		update_option( 'timezone_string', 'America/Chicago' );
1470
1471
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1472
		$params = $this->set_post_data( array(
1473
			// This results in a special `post_date_gmt` value of
1474
			// '0000-00-00 00:00:00'.  See #38883.
1475
			'status' => 'pending',
1476
		) );
1477
1478
		$request->set_body_params( $params );
1479
		$response = $this->server->dispatch( $request );
1480
		$this->assertEquals( 201, $response->get_status() );
1481
1482
		$data = $response->get_data();
1483
		$post = get_post( $data['id'] );
1484
		$this->assertEquals( '0000-00-00 00:00:00', $post->post_date_gmt );
1485
		$this->assertNotEquals( '0000-00-00T00:00:00', $data['date_gmt'] );
1486
1487
		$this->check_create_post_response( $response );
1488
1489
		update_option( 'timezone_string', '' );
1490
	}
1491
1492
	public function test_create_post_sticky() {
1493
		wp_set_current_user( self::$editor_id );
1494
1495
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1496
		$params = $this->set_post_data( array(
1497
			'sticky' => true,
1498
		) );
1499
		$request->set_body_params( $params );
1500
		$response = $this->server->dispatch( $request );
1501
1502
		$new_data = $response->get_data();
1503
		$this->assertEquals( true, $new_data['sticky'] );
1504
		$post = get_post( $new_data['id'] );
1505
		$this->assertEquals( true, is_sticky( $post->ID ) );
1506
	}
1507
1508
	public function test_create_post_sticky_as_contributor() {
1509
		wp_set_current_user( self::$contributor_id );
1510
1511
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1512
		$params = $this->set_post_data( array(
1513
			'sticky' => true,
1514
			'status' => 'pending',
1515
		) );
1516
		$request->set_body_params( $params );
1517
		$response = $this->server->dispatch( $request );
1518
1519
		$this->assertErrorResponse( 'rest_cannot_assign_sticky', $response, 403 );
1520
	}
1521
1522
	public function test_create_post_other_author_without_permission() {
1523
		wp_set_current_user( self::$author_id );
1524
1525
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1526
		$params = $this->set_post_data(array(
1527
			'author' => self::$editor_id,
1528
		));
1529
		$request->set_body_params( $params );
1530
		$response = $this->server->dispatch( $request );
1531
1532
		$this->assertErrorResponse( 'rest_cannot_edit_others', $response, 403 );
1533
	}
1534
1535
	public function test_create_post_without_permission() {
1536
		wp_set_current_user( 0 );
1537
1538
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1539
		$params = $this->set_post_data( array(
1540
			'status' => 'draft',
1541
		) );
1542
		$request->set_body_params( $params );
1543
		$response = $this->server->dispatch( $request );
1544
1545
		$this->assertErrorResponse( 'rest_cannot_create', $response, 401 );
1546
	}
1547
1548
	public function test_create_post_draft() {
1549
		wp_set_current_user( self::$editor_id );
1550
1551
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1552
		$params = $this->set_post_data( array(
1553
			'status' => 'draft',
1554
		) );
1555
		$request->set_body_params( $params );
1556
		$response = $this->server->dispatch( $request );
1557
1558
		$data = $response->get_data();
1559
		$new_post = get_post( $data['id'] );
1560
		$this->assertEquals( 'draft', $data['status'] );
1561
		$this->assertEquals( 'draft', $new_post->post_status );
1562
		// Confirm dates are shimmed for gmt_offset
1563
		$post_modified_gmt = date( 'Y-m-d H:i:s', strtotime( $new_post->post_modified ) + ( get_option( 'gmt_offset' ) * 3600 ) );
1564
		$post_date_gmt = date( 'Y-m-d H:i:s', strtotime( $new_post->post_date ) + ( get_option( 'gmt_offset' ) * 3600 ) );
1565
1566
		$this->assertEquals( mysql_to_rfc3339( $post_modified_gmt ), $data['modified_gmt'] );
1567
		$this->assertEquals( mysql_to_rfc3339( $post_date_gmt ), $data['date_gmt'] );
1568
	}
1569
1570
	public function test_create_post_private() {
1571
		wp_set_current_user( self::$editor_id );
1572
1573
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1574
		$params = $this->set_post_data( array(
1575
			'status' => 'private',
1576
		) );
1577
		$request->set_body_params( $params );
1578
		$response = $this->server->dispatch( $request );
1579
1580
		$data = $response->get_data();
1581
		$new_post = get_post( $data['id'] );
1582
		$this->assertEquals( 'private', $data['status'] );
1583
		$this->assertEquals( 'private', $new_post->post_status );
1584
	}
1585
1586
	public function test_create_post_private_without_permission() {
1587
		wp_set_current_user( self::$author_id );
1588
		$user = wp_get_current_user();
1589
		$user->add_cap( 'publish_posts', false );
1590
		// Flush capabilities, https://core.trac.wordpress.org/ticket/28374
1591
		$user->get_role_caps();
1592
		$user->update_user_level_from_caps();
1593
1594
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1595
		$params = $this->set_post_data( array(
1596
			'status' => 'private',
1597
			'author' => self::$author_id,
1598
		) );
1599
		$request->set_body_params( $params );
1600
		$response = $this->server->dispatch( $request );
1601
1602
		$this->assertErrorResponse( 'rest_cannot_publish', $response, 403 );
1603
	}
1604
1605
	public function test_create_post_publish_without_permission() {
1606
		wp_set_current_user( self::$author_id );
1607
		$user = wp_get_current_user();
1608
		$user->add_cap( 'publish_posts', false );
1609
		// Flush capabilities, https://core.trac.wordpress.org/ticket/28374
1610
		$user->get_role_caps();
1611
		$user->update_user_level_from_caps();
1612
1613
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1614
		$params = $this->set_post_data( array(
1615
			'status' => 'publish',
1616
		) );
1617
		$request->set_body_params( $params );
1618
		$response = $this->server->dispatch( $request );
1619
1620
		$this->assertErrorResponse( 'rest_cannot_publish', $response, 403 );
1621
	}
1622
1623
	public function test_create_post_invalid_status() {
1624
		wp_set_current_user( self::$editor_id );
1625
1626
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1627
		$params = $this->set_post_data( array(
1628
			'status' => 'teststatus',
1629
		) );
1630
		$request->set_body_params( $params );
1631
		$response = $this->server->dispatch( $request );
1632
1633
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
1634
	}
1635
1636
	public function test_create_post_with_format() {
1637
		wp_set_current_user( self::$editor_id );
1638
1639
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1640
		$params = $this->set_post_data( array(
1641
			'format' => 'gallery',
1642
		) );
1643
		$request->set_body_params( $params );
1644
		$response = $this->server->dispatch( $request );
1645
1646
		$data = $response->get_data();
1647
		$new_post = get_post( $data['id'] );
1648
		$this->assertEquals( 'gallery', $data['format'] );
1649
		$this->assertEquals( 'gallery', get_post_format( $new_post->ID ) );
1650
	}
1651
1652
	public function test_create_post_with_standard_format() {
1653
		wp_set_current_user( self::$editor_id );
1654
1655
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1656
		$params = $this->set_post_data( array(
1657
			'format' => 'standard',
1658
		) );
1659
		$request->set_body_params( $params );
1660
		$response = $this->server->dispatch( $request );
1661
1662
		$data = $response->get_data();
1663
		$new_post = get_post( $data['id'] );
1664
		$this->assertEquals( 'standard', $data['format'] );
1665
		$this->assertFalse( get_post_format( $new_post->ID ) );
1666
	}
1667
1668
	public function test_create_post_with_invalid_format() {
1669
		wp_set_current_user( self::$editor_id );
1670
1671
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1672
		$params = $this->set_post_data( array(
1673
			'format' => 'testformat',
1674
		) );
1675
		$request->set_body_params( $params );
1676
		$response = $this->server->dispatch( $request );
1677
1678
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
1679
	}
1680
1681
	/**
1682
	 * Test with a valid format, but one unsupported by the theme.
1683
	 *
1684
	 * https://core.trac.wordpress.org/ticket/38610
1685
	 */
1686
	public function test_create_post_with_unsupported_format() {
1687
		wp_set_current_user( self::$editor_id );
1688
1689
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1690
		$params = $this->set_post_data( array(
1691
			'format' => 'link',
1692
		) );
1693
		$request->set_body_params( $params );
1694
		$response = $this->server->dispatch( $request );
1695
		$this->assertEquals( 201, $response->get_status() );
1696
1697
		$data = $response->get_data();
1698
		$this->assertEquals( 'link', $data['format'] );
1699
	}
1700
1701
	public function test_create_update_post_with_featured_media() {
1702
1703
		$file = DIR_TESTDATA . '/images/canola.jpg';
1704
		$this->attachment_id = $this->factory->attachment->create_object( $file, 0, array(
1705
			'post_mime_type' => 'image/jpeg',
1706
			'menu_order' => rand( 1, 100 ),
1707
		) );
1708
1709
		wp_set_current_user( self::$editor_id );
1710
1711
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1712
		$params = $this->set_post_data( array(
1713
			'featured_media' => $this->attachment_id,
1714
		) );
1715
		$request->set_body_params( $params );
1716
		$response = $this->server->dispatch( $request );
1717
		$data = $response->get_data();
1718
		$new_post = get_post( $data['id'] );
1719
		$this->assertEquals( $this->attachment_id, $data['featured_media'] );
1720
		$this->assertEquals( $this->attachment_id, (int) get_post_thumbnail_id( $new_post->ID ) );
1721
1722
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts/' . $new_post->ID );
1723
		$params = $this->set_post_data( array(
1724
			'featured_media' => 0,
1725
		) );
1726
		$request->set_body_params( $params );
1727
		$response = $this->server->dispatch( $request );
1728
		$data = $response->get_data();
1729
		$this->assertEquals( 0, $data['featured_media'] );
1730
		$this->assertEquals( 0, (int) get_post_thumbnail_id( $new_post->ID ) );
1731
	}
1732
1733
	public function test_create_post_invalid_author() {
1734
		wp_set_current_user( self::$editor_id );
1735
1736
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1737
		$params = $this->set_post_data( array(
1738
			'author' => -1,
1739
		) );
1740
		$request->set_body_params( $params );
1741
		$response = $this->server->dispatch( $request );
1742
1743
		$this->assertErrorResponse( 'rest_invalid_author', $response, 400 );
1744
	}
1745
1746
	public function test_create_post_invalid_author_without_permission() {
1747
		wp_set_current_user( self::$author_id );
1748
1749
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1750
		$params = $this->set_post_data( array(
1751
			'author' => self::$editor_id,
1752
		) );
1753
		$request->set_body_params( $params );
1754
		$response = $this->server->dispatch( $request );
1755
1756
		$this->assertErrorResponse( 'rest_cannot_edit_others', $response, 403 );
1757
	}
1758
1759
	public function test_create_post_with_password() {
1760
		wp_set_current_user( self::$editor_id );
1761
1762
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1763
		$params = $this->set_post_data( array(
1764
			'password' => 'testing',
1765
		) );
1766
		$request->set_body_params( $params );
1767
		$response = $this->server->dispatch( $request );
1768
1769
		$data = $response->get_data();
1770
		$this->assertEquals( 'testing', $data['password'] );
1771
	}
1772
1773
	public function test_create_post_with_falsy_password() {
1774
		wp_set_current_user( self::$editor_id );
1775
1776
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1777
		$params = $this->set_post_data( array(
1778
			'password' => '0',
1779
		) );
1780
		$request->set_body_params( $params );
1781
		$response = $this->server->dispatch( $request );
1782
1783
		$data = $response->get_data();
1784
1785
		$this->assertEquals( '0', $data['password'] );
1786
	}
1787
1788
	public function test_create_post_with_empty_string_password_and_sticky() {
1789
		wp_set_current_user( self::$editor_id );
1790
1791
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1792
		$params = $this->set_post_data( array(
1793
			'password' => '',
1794
			'sticky'   => true,
1795
		) );
1796
		$request->set_body_params( $params );
1797
		$response = $this->server->dispatch( $request );
1798
1799
		$this->assertEquals( 201, $response->get_status() );
1800
		$data = $response->get_data();
1801
		$this->assertEquals( '', $data['password'] );
1802
	}
1803
1804
	public function test_create_post_with_password_and_sticky_fails() {
1805
		wp_set_current_user( self::$editor_id );
1806
1807
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1808
		$params = $this->set_post_data( array(
1809
			'password' => '123',
1810
			'sticky'   => true,
1811
		) );
1812
		$request->set_body_params( $params );
1813
		$response = $this->server->dispatch( $request );
1814
1815
		$this->assertErrorResponse( 'rest_invalid_field', $response, 400 );
1816
	}
1817
1818
	public function test_create_post_custom_date() {
1819
		wp_set_current_user( self::$editor_id );
1820
1821
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1822
		$params = $this->set_post_data( array(
1823
			'date' => '2010-01-01T02:00:00Z',
1824
		) );
1825
		$request->set_body_params( $params );
1826
		$response = $this->server->dispatch( $request );
1827
1828
		$data = $response->get_data();
1829
		$new_post = get_post( $data['id'] );
1830
		$time = gmmktime( 2, 0, 0, 1, 1, 2010 );
1831
		$this->assertEquals( '2010-01-01T02:00:00', $data['date'] );
1832
		$this->assertEquals( $time, strtotime( $new_post->post_date ) );
1833
	}
1834
1835
	public function test_create_post_custom_date_with_timezone() {
1836
		wp_set_current_user( self::$editor_id );
1837
1838
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1839
		$params = $this->set_post_data( array(
1840
			'date' => '2010-01-01T02:00:00-10:00',
1841
		) );
1842
		$request->set_body_params( $params );
1843
		$response = $this->server->dispatch( $request );
1844
1845
		$data = $response->get_data();
1846
		$new_post = get_post( $data['id'] );
1847
		$time = gmmktime( 12, 0, 0, 1, 1, 2010 );
1848
1849
		$this->assertEquals( '2010-01-01T12:00:00', $data['date'] );
1850
		$this->assertEquals( '2010-01-01T12:00:00', $data['modified'] );
1851
1852
		$this->assertEquals( $time, strtotime( $new_post->post_date ) );
1853
		$this->assertEquals( $time, strtotime( $new_post->post_modified ) );
1854
	}
1855
1856
	public function test_create_post_with_db_error() {
1857
		wp_set_current_user( self::$editor_id );
1858
1859
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1860
		$params  = $this->set_post_data( array() );
1861
		$request->set_body_params( $params );
1862
1863
		/**
1864
		 * Disable showing error as the below is going to intentionally
1865
		 * trigger a DB error.
1866
		 */
1867
		global $wpdb;
1868
		$wpdb->suppress_errors = true;
1869
		add_filter( 'query', array( $this, 'error_insert_query' ) );
1870
1871
		$response = $this->server->dispatch( $request );
1872
		remove_filter( 'query', array( $this, 'error_insert_query' ) );
1873
		$wpdb->show_errors = true;
1874
1875
		$this->assertErrorResponse( 'db_insert_error', $response, 500 );
1876
	}
1877
1878
	public function test_create_post_with_invalid_date() {
1879
		wp_set_current_user( self::$editor_id );
1880
1881
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1882
		$params = $this->set_post_data( array(
1883
			'date' => '2010-60-01T02:00:00Z',
1884
		) );
1885
		$request->set_body_params( $params );
1886
		$response = $this->server->dispatch( $request );
1887
1888
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
1889
	}
1890
1891
	public function test_create_post_with_invalid_date_gmt() {
1892
		wp_set_current_user( self::$editor_id );
1893
1894
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1895
		$params = $this->set_post_data( array(
1896
			'date_gmt' => '2010-60-01T02:00:00',
1897
		) );
1898
		$request->set_body_params( $params );
1899
		$response = $this->server->dispatch( $request );
1900
1901
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
1902
	}
1903
1904
	public function test_create_post_with_quotes_in_title() {
1905
		wp_set_current_user( self::$editor_id );
1906
1907
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1908
		$params = $this->set_post_data( array(
1909
			'title' => "Rob O'Rourke's Diary",
1910
		) );
1911
		$request->set_body_params( $params );
1912
		$response = $this->server->dispatch( $request );
1913
		$new_data = $response->get_data();
1914
		$this->assertEquals( "Rob O'Rourke's Diary", $new_data['title']['raw'] );
1915
	}
1916
1917
	public function test_create_post_with_categories() {
1918
		wp_set_current_user( self::$editor_id );
1919
		$category = wp_insert_term( 'Test Category', 'category' );
1920
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1921
		$params = $this->set_post_data( array(
1922
			'password'   => 'testing',
1923
			'categories' => array(
1924
				$category['term_id']
1925
			),
1926
		) );
1927
		$request->set_body_params( $params );
1928
		$response = $this->server->dispatch( $request );
1929
1930
		$data = $response->get_data();
1931
		$this->assertEquals( array( $category['term_id'] ), $data['categories'] );
1932
	}
1933
1934
	public function test_create_post_with_categories_as_csv() {
1935
		wp_set_current_user( self::$editor_id );
1936
		$category = wp_insert_term( 'Chicken', 'category' );
1937
		$category2 = wp_insert_term( 'Ribs', 'category' );
1938
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1939
		$params = $this->set_post_data( array(
1940
			'categories' => $category['term_id'] . ',' . $category2['term_id'],
1941
		) );
1942
		$request->set_body_params( $params );
1943
		$response = $this->server->dispatch( $request );
1944
1945
		$data = $response->get_data();
1946
		$this->assertEquals( array( $category['term_id'], $category2['term_id'] ), $data['categories'] );
1947
	}
1948
1949
	public function test_create_post_with_invalid_categories() {
1950
		wp_set_current_user( self::$editor_id );
1951
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1952
		$params = $this->set_post_data( array(
1953
			'password'   => 'testing',
1954
			'categories' => array(
1955
				REST_TESTS_IMPOSSIBLY_HIGH_NUMBER
1956
			),
1957
		) );
1958
		$request->set_body_params( $params );
1959
		$response = $this->server->dispatch( $request );
1960
1961
		$data = $response->get_data();
1962
		$this->assertEquals( array(), $data['categories'] );
1963
	}
1964
1965
	/**
1966
	 * @ticket 38505
1967
	 */
1968
	public function test_create_post_with_categories_that_cannot_be_assigned_by_current_user() {
1969
		$cats = self::factory()->category->create_many( 2 );
1970
		$this->forbidden_cat = $cats[1];
1971
1972
		wp_set_current_user( self::$editor_id );
1973
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
1974
		$params = $this->set_post_data( array(
1975
			'password'   => 'testing',
1976
			'categories' => $cats,
1977
		) );
1978
		$request->set_body_params( $params );
1979
1980
		add_filter( 'map_meta_cap', array( $this, 'revoke_assign_term' ), 10, 4 );
1981
		$response = $this->server->dispatch( $request );
1982
		remove_filter( 'map_meta_cap', array( $this, 'revoke_assign_term' ), 10, 4 );
1983
1984
		$this->assertErrorResponse( 'rest_cannot_assign_term', $response, 403 );
1985
	}
1986
1987
	public function revoke_assign_term( $caps, $cap, $user_id, $args ) {
1988
		if ( 'assign_term' === $cap && isset( $args[0] ) && $this->forbidden_cat == $args[0] ) {
1989
			$caps = array( 'do_not_allow' );
1990
		}
1991
		return $caps;
1992
	}
1993
1994
	public function test_update_item() {
1995
		wp_set_current_user( self::$editor_id );
1996
1997
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
1998
		$request->add_header( 'content-type', 'application/x-www-form-urlencoded' );
1999
		$params = $this->set_post_data();
2000
		$request->set_body_params( $params );
2001
		$response = $this->server->dispatch( $request );
2002
2003
		$this->check_update_post_response( $response );
2004
		$new_data = $response->get_data();
2005
		$this->assertEquals( self::$post_id, $new_data['id'] );
2006
		$this->assertEquals( $params['title'], $new_data['title']['raw'] );
2007
		$this->assertEquals( $params['content'], $new_data['content']['raw'] );
2008
		$this->assertEquals( $params['excerpt'], $new_data['excerpt']['raw'] );
2009
		$post = get_post( self::$post_id );
2010
		$this->assertEquals( $params['title'], $post->post_title );
2011
		$this->assertEquals( $params['content'], $post->post_content );
2012
		$this->assertEquals( $params['excerpt'], $post->post_excerpt );
2013
	}
2014
2015
	public function test_update_item_no_change() {
2016
		wp_set_current_user( self::$editor_id );
2017
		$post = get_post( self::$post_id );
2018
2019
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2020
		$request->set_param( 'author', $post->post_author );
2021
2022
		// Run twice to make sure that the update still succeeds even if no DB
2023
		// rows are updated.
2024
		$response = $this->server->dispatch( $request );
2025
		$this->check_update_post_response( $response );
2026
2027
		$response = $this->server->dispatch( $request );
2028
		$this->check_update_post_response( $response );
2029
	}
2030
2031
	public function test_rest_update_post() {
2032
		wp_set_current_user( self::$editor_id );
2033
2034
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2035
		$request->add_header( 'content-type', 'application/json' );
2036
		$params = $this->set_post_data();
2037
		$request->set_body( wp_json_encode( $params ) );
0 ignored issues
show
Security Bug introduced by
It seems like wp_json_encode($params) targeting wp_json_encode() can also be of type false; however, WP_REST_Request::set_body() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
2038
		$response = $this->server->dispatch( $request );
2039
2040
		$this->check_update_post_response( $response );
2041
		$new_data = $response->get_data();
2042
		$this->assertEquals( self::$post_id, $new_data['id'] );
2043
		$this->assertEquals( $params['title'], $new_data['title']['raw'] );
2044
		$this->assertEquals( $params['content'], $new_data['content']['raw'] );
2045
		$this->assertEquals( $params['excerpt'], $new_data['excerpt']['raw'] );
2046
		$post = get_post( self::$post_id );
2047
		$this->assertEquals( $params['title'], $post->post_title );
2048
		$this->assertEquals( $params['content'], $post->post_content );
2049
		$this->assertEquals( $params['excerpt'], $post->post_excerpt );
2050
	}
2051
2052
	public function test_rest_update_post_raw() {
2053
		wp_set_current_user( self::$editor_id );
2054
2055
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2056
		$request->add_header( 'content-type', 'application/json' );
2057
		$params = $this->set_raw_post_data();
2058
		$request->set_body( wp_json_encode( $params ) );
0 ignored issues
show
Security Bug introduced by
It seems like wp_json_encode($params) targeting wp_json_encode() can also be of type false; however, WP_REST_Request::set_body() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
2059
		$response = $this->server->dispatch( $request );
2060
2061
		$this->check_update_post_response( $response );
2062
		$new_data = $response->get_data();
2063
		$this->assertEquals( self::$post_id, $new_data['id'] );
2064
		$this->assertEquals( $params['title']['raw'], $new_data['title']['raw'] );
2065
		$this->assertEquals( $params['content']['raw'], $new_data['content']['raw'] );
2066
		$this->assertEquals( $params['excerpt']['raw'], $new_data['excerpt']['raw'] );
2067
		$post = get_post( self::$post_id );
2068
		$this->assertEquals( $params['title']['raw'], $post->post_title );
2069
		$this->assertEquals( $params['content']['raw'], $post->post_content );
2070
		$this->assertEquals( $params['excerpt']['raw'], $post->post_excerpt );
2071
	}
2072
2073
	public function test_update_post_without_extra_params() {
2074
		wp_set_current_user( self::$editor_id );
2075
2076
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2077
		$params = $this->set_post_data();
2078
		unset( $params['type'] );
2079
		unset( $params['name'] );
2080
		unset( $params['author'] );
2081
		unset( $params['status'] );
2082
		$request->set_body_params( $params );
2083
		$response = $this->server->dispatch( $request );
2084
2085
		$this->check_update_post_response( $response );
2086
	}
2087
2088
	public function test_update_post_without_permission() {
2089
		wp_set_current_user( self::$editor_id );
2090
		$user = wp_get_current_user();
2091
		$user->add_cap( 'edit_published_posts', false );
2092
		// Flush capabilities, https://core.trac.wordpress.org/ticket/28374
2093
		$user->get_role_caps();
2094
		$user->update_user_level_from_caps();
2095
2096
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2097
		$params = $this->set_post_data();
2098
		$request->set_body_params( $params );
2099
		$response = $this->server->dispatch( $request );
2100
2101
		$this->assertErrorResponse( 'rest_cannot_edit', $response, 403 );
2102
	}
2103
2104
	public function test_update_post_sticky_as_contributor() {
2105
		wp_set_current_user( self::$contributor_id );
2106
2107
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2108
		$params = $this->set_post_data( array(
2109
			'sticky' => true,
2110
			'status' => 'pending',
2111
		) );
2112
		$request->set_body_params( $params );
2113
		$response = $this->server->dispatch( $request );
2114
2115
		$this->assertErrorResponse( 'rest_cannot_edit', $response, 403 );
2116
	}
2117
2118
	public function test_update_post_invalid_id() {
2119
		wp_set_current_user( self::$editor_id );
2120
2121
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', REST_TESTS_IMPOSSIBLY_HIGH_NUMBER ) );
2122
		$response = $this->server->dispatch( $request );
2123
2124
		$this->assertErrorResponse( 'rest_post_invalid_id', $response, 404 );
2125
	}
2126
2127
	public function test_update_post_invalid_route() {
2128
		wp_set_current_user( self::$editor_id );
2129
2130
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/pages/%d', self::$post_id ) );
2131
		$response = $this->server->dispatch( $request );
2132
2133
		$this->assertErrorResponse( 'rest_post_invalid_id', $response, 404 );
2134
	}
2135
2136
	public function test_update_post_with_format() {
2137
		wp_set_current_user( self::$editor_id );
2138
2139
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2140
		$params = $this->set_post_data( array(
2141
			'format' => 'gallery',
2142
		) );
2143
		$request->set_body_params( $params );
2144
		$response = $this->server->dispatch( $request );
2145
2146
		$data = $response->get_data();
2147
		$new_post = get_post( $data['id'] );
2148
		$this->assertEquals( 'gallery', $data['format'] );
2149
		$this->assertEquals( 'gallery', get_post_format( $new_post->ID ) );
2150
	}
2151
2152
	public function test_update_post_with_standard_format() {
2153
		wp_set_current_user( self::$editor_id );
2154
2155
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2156
		$params = $this->set_post_data( array(
2157
			'format' => 'standard',
2158
		) );
2159
		$request->set_body_params( $params );
2160
		$response = $this->server->dispatch( $request );
2161
2162
		$data = $response->get_data();
2163
		$new_post = get_post( $data['id'] );
2164
		$this->assertEquals( 'standard', $data['format'] );
2165
		$this->assertFalse( get_post_format( $new_post->ID ) );
2166
	}
2167
2168
	public function test_update_post_with_invalid_format() {
2169
		wp_set_current_user( self::$editor_id );
2170
2171
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2172
		$params = $this->set_post_data( array(
2173
			'format' => 'testformat',
2174
		) );
2175
		$request->set_body_params( $params );
2176
		$response = $this->server->dispatch( $request );
2177
2178
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
2179
	}
2180
2181
	/**
2182
	 * Test with a valid format, but one unsupported by the theme.
2183
	 *
2184
	 * https://core.trac.wordpress.org/ticket/38610
2185
	 */
2186
	public function test_update_post_with_unsupported_format() {
2187
		wp_set_current_user( self::$editor_id );
2188
2189
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2190
		$params = $this->set_post_data( array(
2191
			'format' => 'link',
2192
		) );
2193
		$request->set_body_params( $params );
2194
		$response = $this->server->dispatch( $request );
2195
		$this->assertEquals( 200, $response->get_status() );
2196
2197
		$data = $response->get_data();
2198
		$this->assertEquals( 'link', $data['format'] );
2199
	}
2200
2201
	public function test_update_post_ignore_readonly() {
2202
		wp_set_current_user( self::$editor_id );
2203
2204
		$new_content = rand_str();
2205
		$expected_modified = current_time( 'mysql' );
2206
2207
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2208
		$params = $this->set_post_data( array(
2209
			'modified' => '2010-06-01T02:00:00Z',
2210
			'content'  => $new_content,
2211
		) );
2212
		$request->set_body_params( $params );
2213
		$response = $this->server->dispatch( $request );
2214
2215
		// The readonly modified param should be ignored, request should be a success.
2216
		$data = $response->get_data();
2217
		$new_post = get_post( $data['id'] );
2218
2219
		$this->assertEquals( $new_content, $data['content']['raw'] );
2220
		$this->assertEquals( $new_content, $new_post->post_content );
2221
2222
		// The modified date should equal the current time.
2223
		$this->assertEquals( date( 'Y-m-d', strtotime( mysql_to_rfc3339( $expected_modified ) ) ), date( 'Y-m-d', strtotime( $data['modified'] ) ) );
2224
		$this->assertEquals( date( 'Y-m-d', strtotime( $expected_modified ) ), date( 'Y-m-d', strtotime( $new_post->post_modified ) ) );
2225
	}
2226
2227
	/**
2228
	 * @dataProvider post_dates_provider
2229
	 */
2230
	public function test_update_post_date( $status, $params, $results ) {
2231
		wp_set_current_user( self::$editor_id );
2232
		update_option( 'timezone_string', $params['timezone_string'] );
2233
2234
		$post_id = $this->factory->post->create( array( 'post_status' => $status ) );
2235
2236
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', $post_id ) );
2237
		if ( isset( $params['date'] ) ) {
2238
			$request->set_param( 'date', $params['date'] );
2239
		}
2240
		if ( isset( $params['date_gmt'] ) ) {
2241
			$request->set_param( 'date_gmt', $params['date_gmt'] );
2242
		}
2243
		$response = $this->server->dispatch( $request );
2244
2245
		update_option( 'timezone_string', '' );
2246
2247
		$this->assertEquals( 200, $response->get_status() );
2248
		$data = $response->get_data();
2249
		$post = get_post( $data['id'] );
2250
2251
		$this->assertEquals( $results['date'], $data['date'] );
2252
		$post_date = str_replace( 'T', ' ', $results['date'] );
2253
		$this->assertEquals( $post_date, $post->post_date );
2254
2255
		$this->assertEquals( $results['date_gmt'], $data['date_gmt'] );
2256
		$post_date_gmt = str_replace( 'T', ' ', $results['date_gmt'] );
2257
		$this->assertEquals( $post_date_gmt, $post->post_date_gmt );
2258
	}
2259
2260
	public function test_update_post_with_invalid_date() {
2261
		wp_set_current_user( self::$editor_id );
2262
2263
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2264
		$params = $this->set_post_data( array(
2265
			'date' => rand_str(),
2266
		) );
2267
		$request->set_body_params( $params );
2268
		$response = $this->server->dispatch( $request );
2269
2270
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
2271
	}
2272
2273
	public function test_update_post_with_invalid_date_gmt() {
2274
		wp_set_current_user( self::$editor_id );
2275
2276
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2277
		$params = $this->set_post_data( array(
2278
			'date_gmt' => rand_str(),
2279
		) );
2280
		$request->set_body_params( $params );
2281
		$response = $this->server->dispatch( $request );
2282
2283
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
2284
	}
2285
2286
	public function test_empty_post_date_gmt_shimmed_using_post_date() {
2287
		global $wpdb;
2288
2289
		wp_set_current_user( self::$editor_id );
2290
		update_option( 'timezone_string', 'America/Chicago' );
2291
2292
		// Need to set dates using wpdb directly because `wp_update_post` and
2293
		// `wp_insert_post` have additional validation on dates.
2294
		$post_id = $this->factory->post->create();
2295
		$wpdb->update(
2296
			$wpdb->posts,
2297
			array(
2298
				'post_date'     => '2016-02-23 12:00:00',
2299
				'post_date_gmt' => '0000-00-00 00:00:00',
2300
			),
2301
			array(
2302
				'ID' => $post_id,
2303
			),
2304
			array( '%s', '%s' ),
2305
			array( '%d' )
2306
		);
2307
		wp_cache_delete( $post_id, 'posts' );
2308
2309
		$post = get_post( $post_id );
2310
		$this->assertEquals( $post->post_date,     '2016-02-23 12:00:00' );
2311
		$this->assertEquals( $post->post_date_gmt, '0000-00-00 00:00:00' );
2312
2313
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', $post_id ) );
2314
		$response = $this->server->dispatch( $request );
2315
		$this->assertEquals( 200, $response->get_status() );
2316
		$data = $response->get_data();
2317
2318
		$this->assertEquals( '2016-02-23T12:00:00', $data['date'] );
2319
		$this->assertEquals( '2016-02-23T18:00:00', $data['date_gmt'] );
2320
2321
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', $post_id ) );
2322
		$request->set_param( 'date', '2016-02-23T13:00:00' );
2323
		$response = $this->server->dispatch( $request );
2324
		$this->assertEquals( 200, $response->get_status() );
2325
		$data = $response->get_data();
2326
2327
		$this->assertEquals( '2016-02-23T13:00:00', $data['date'] );
2328
		$this->assertEquals( '2016-02-23T19:00:00', $data['date_gmt'] );
2329
2330
		$post = get_post( $post_id );
2331
		$this->assertEquals( $post->post_date,     '2016-02-23 13:00:00' );
2332
		$this->assertEquals( $post->post_date_gmt, '2016-02-23 19:00:00' );
2333
2334
		update_option( 'timezone_string', '' );
2335
	}
2336
2337
	public function test_update_post_slug() {
2338
		wp_set_current_user( self::$editor_id );
2339
2340
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2341
		$params = $this->set_post_data( array(
2342
			'slug' => 'sample-slug',
2343
		) );
2344
		$request->set_body_params( $params );
2345
		$response = $this->server->dispatch( $request );
2346
2347
		$new_data = $response->get_data();
2348
		$this->assertEquals( 'sample-slug', $new_data['slug'] );
2349
		$post = get_post( $new_data['id'] );
2350
		$this->assertEquals( 'sample-slug', $post->post_name );
2351
	}
2352
2353
	public function test_update_post_slug_accented_chars() {
2354
		wp_set_current_user( self::$editor_id );
2355
2356
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2357
		$params = $this->set_post_data( array(
2358
			'slug' => 'tęst-acceńted-chäræcters',
2359
		) );
2360
		$request->set_body_params( $params );
2361
		$response = $this->server->dispatch( $request );
2362
2363
		$new_data = $response->get_data();
2364
		$this->assertEquals( 'test-accented-charaecters', $new_data['slug'] );
2365
		$post = get_post( $new_data['id'] );
2366
		$this->assertEquals( 'test-accented-charaecters', $post->post_name );
2367
	}
2368
2369
	public function test_update_post_sticky() {
2370
		wp_set_current_user( self::$editor_id );
2371
2372
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2373
		$params = $this->set_post_data( array(
2374
			'sticky' => true,
2375
		) );
2376
		$request->set_body_params( $params );
2377
		$response = $this->server->dispatch( $request );
2378
2379
		$new_data = $response->get_data();
2380
		$this->assertEquals( true, $new_data['sticky'] );
2381
		$post = get_post( $new_data['id'] );
2382
		$this->assertEquals( true, is_sticky( $post->ID ) );
2383
2384
		// Updating another field shouldn't change sticky status
2385
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2386
		$params = $this->set_post_data( array(
2387
			'title'       => 'This should not reset sticky',
2388
		) );
2389
		$request->set_body_params( $params );
2390
		$response = $this->server->dispatch( $request );
2391
2392
		$new_data = $response->get_data();
2393
		$this->assertEquals( true, $new_data['sticky'] );
2394
		$post = get_post( $new_data['id'] );
2395
		$this->assertEquals( true, is_sticky( $post->ID ) );
2396
	}
2397
2398
	public function test_update_post_excerpt() {
2399
		wp_set_current_user( self::$editor_id );
2400
2401
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2402
		$request->set_body_params( array(
2403
			'excerpt' => 'An Excerpt',
2404
		) );
2405
2406
		$response = $this->server->dispatch( $request );
2407
		$new_data = $response->get_data();
2408
		$this->assertEquals( 'An Excerpt', $new_data['excerpt']['raw'] );
2409
	}
2410
2411
	public function test_update_post_empty_excerpt() {
2412
		wp_set_current_user( self::$editor_id );
2413
2414
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2415
		$request->set_body_params( array(
2416
			'excerpt' => '',
2417
		) );
2418
2419
		$response = $this->server->dispatch( $request );
2420
		$new_data = $response->get_data();
2421
		$this->assertEquals( '', $new_data['excerpt']['raw'] );
2422
	}
2423
2424
	public function test_update_post_content() {
2425
		wp_set_current_user( self::$editor_id );
2426
2427
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2428
		$request->set_body_params( array(
2429
			'content' => 'Some Content',
2430
		) );
2431
2432
		$response = $this->server->dispatch( $request );
2433
		$new_data = $response->get_data();
2434
		$this->assertEquals( 'Some Content', $new_data['content']['raw'] );
2435
	}
2436
2437
	public function test_update_post_empty_content() {
2438
		wp_set_current_user( self::$editor_id );
2439
2440
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2441
		$request->set_body_params( array(
2442
			'content' => '',
2443
		) );
2444
2445
		$response = $this->server->dispatch( $request );
2446
		$new_data = $response->get_data();
2447
		$this->assertEquals( '', $new_data['content']['raw'] );
2448
	}
2449
2450
	public function test_update_post_with_empty_password() {
2451
		wp_set_current_user( self::$editor_id );
2452
		wp_update_post( array(
2453
			'ID'            => self::$post_id,
2454
			'post_password' => 'foo',
2455
		) );
2456
2457
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2458
		$params = $this->set_post_data( array(
2459
			'password' => '',
2460
		) );
2461
		$request->set_body_params( $params );
2462
		$response = $this->server->dispatch( $request );
2463
		$data = $response->get_data();
2464
		$this->assertEquals( '', $data['password'] );
2465
	}
2466
2467
	public function test_update_post_with_password_and_sticky_fails() {
2468
		wp_set_current_user( self::$editor_id );
2469
2470
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2471
		$params = $this->set_post_data( array(
2472
			'password' => '123',
2473
			'sticky'   => true,
2474
		) );
2475
		$request->set_body_params( $params );
2476
		$response = $this->server->dispatch( $request );
2477
2478
		$this->assertErrorResponse( 'rest_invalid_field', $response, 400 );
2479
	}
2480
2481
	public function test_update_stick_post_with_password_fails() {
2482
		wp_set_current_user( self::$editor_id );
2483
2484
		stick_post( self::$post_id );
2485
2486
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2487
		$params = $this->set_post_data( array(
2488
			'password' => '123',
2489
		) );
2490
		$request->set_body_params( $params );
2491
		$response = $this->server->dispatch( $request );
2492
2493
		$this->assertErrorResponse( 'rest_invalid_field', $response, 400 );
2494
	}
2495
2496
	public function test_update_password_protected_post_with_sticky_fails() {
2497
		wp_set_current_user( self::$editor_id );
2498
2499
		wp_update_post( array( 'ID' => self::$post_id, 'post_password' => '123' ) );
2500
2501
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2502
		$params = $this->set_post_data( array(
2503
			'sticky' => true,
2504
		) );
2505
		$request->set_body_params( $params );
2506
		$response = $this->server->dispatch( $request );
2507
2508
		$this->assertErrorResponse( 'rest_invalid_field', $response, 400 );
2509
	}
2510
2511
	public function test_update_post_with_quotes_in_title() {
2512
		wp_set_current_user( self::$editor_id );
2513
2514
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2515
		$params = $this->set_post_data( array(
2516
			'title' => "Rob O'Rourke's Diary",
2517
		) );
2518
		$request->set_body_params( $params );
2519
		$response = $this->server->dispatch( $request );
2520
		$new_data = $response->get_data();
2521
		$this->assertEquals( "Rob O'Rourke's Diary", $new_data['title']['raw'] );
2522
	}
2523
2524
	public function test_update_post_with_categories() {
2525
2526
		wp_set_current_user( self::$editor_id );
2527
		$category = wp_insert_term( 'Test Category', 'category' );
2528
2529
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2530
		$params = $this->set_post_data( array(
2531
			'title' => 'Tester',
2532
			'categories' => array(
2533
				$category['term_id'],
2534
			),
2535
		) );
2536
		$request->set_body_params( $params );
2537
		$response = $this->server->dispatch( $request );
2538
		$new_data = $response->get_data();
2539
		$this->assertEquals( array( $category['term_id'] ), $new_data['categories'] );
2540
		$categories_path = '';
2541
		$links = $response->get_links();
2542
		foreach ( $links['https://api.w.org/term'] as $link ) {
2543
			if ( 'category' === $link['attributes']['taxonomy'] ) {
2544
				$categories_path = $link['href'];
2545
			}
2546
		}
2547
		$query = parse_url( $categories_path, PHP_URL_QUERY );
2548
		parse_str( $query, $args );
2549
		$request = new WP_REST_Request( 'GET', $args['rest_route'] );
2550
		unset( $args['rest_route'] );
2551
		$request->set_query_params( $args );
2552
		$response = $this->server->dispatch( $request );
2553
		$data = $response->get_data();
2554
		$this->assertCount( 1, $data );
2555
		$this->assertEquals( 'Test Category', $data[0]['name'] );
2556
	}
2557
2558
	public function test_update_post_with_empty_categories() {
2559
2560
		wp_set_current_user( self::$editor_id );
2561
		$category = wp_insert_term( 'Test Category', 'category' );
2562
		wp_set_object_terms( self::$post_id, $category['term_id'], 'category' );
2563
2564
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2565
		$params = $this->set_post_data( array(
2566
			'title' => 'Tester',
2567
			'categories' => array(),
2568
		) );
2569
		$request->set_body_params( $params );
2570
		$response = $this->server->dispatch( $request );
2571
		$new_data = $response->get_data();
2572
		$this->assertEquals( array(), $new_data['categories'] );
2573
	}
2574
2575
	/**
2576
	 * @ticket 38505
2577
	 */
2578
	public function test_update_post_with_categories_that_cannot_be_assigned_by_current_user() {
2579
		$cats = self::factory()->category->create_many( 2 );
2580
		$this->forbidden_cat = $cats[1];
2581
2582
		wp_set_current_user( self::$editor_id );
2583
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2584
		$params = $this->set_post_data( array(
2585
			'password'   => 'testing',
2586
			'categories' => $cats,
2587
		) );
2588
		$request->set_body_params( $params );
2589
2590
		add_filter( 'map_meta_cap', array( $this, 'revoke_assign_term' ), 10, 4 );
2591
		$response = $this->server->dispatch( $request );
2592
		remove_filter( 'map_meta_cap', array( $this, 'revoke_assign_term' ), 10, 4 );
2593
2594
		$this->assertErrorResponse( 'rest_cannot_assign_term', $response, 403 );
2595
	}
2596
2597
	/**
2598
	 * @ticket 38698
2599
	 */
2600
	public function test_update_item_with_template() {
2601
		wp_set_current_user( self::$editor_id );
2602
		add_filter( 'theme_post_templates', array( $this, 'filter_theme_post_templates' ) );
2603
2604
		// reregister the route as we now have a template available.
2605
		$GLOBALS['wp_rest_server']->override_by_default = true;
2606
		$controller = new WP_REST_Posts_Controller( 'post' );
2607
		$controller->register_routes();
2608
		$GLOBALS['wp_rest_server']->override_by_default = false;
2609
2610
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2611
		$params = $this->set_post_data( array(
2612
			'template' => 'post-my-test-template.php',
2613
		) );
2614
		$request->set_body_params( $params );
2615
		$response = $this->server->dispatch( $request );
2616
2617
		$data = $response->get_data();
2618
		$post_template = get_page_template_slug( get_post( $data['id'] ) );
0 ignored issues
show
Bug introduced by
It seems like get_post($data['id']) targeting get_post() can also be of type array; however, get_page_template_slug() does only seem to accept integer|object<WP_Post>|null, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
2619
2620
		$this->assertEquals( 'post-my-test-template.php', $data['template'] );
2621
		$this->assertEquals( 'post-my-test-template.php', $post_template );
2622
	}
2623
2624
	/**
2625
	 * @ticket 38877
2626
	 */
2627
	public function test_update_item_with_template_none() {
2628
		wp_set_current_user( self::$editor_id );
2629
		add_filter( 'theme_post_templates', array( $this, 'filter_theme_post_templates' ) );
2630
		update_post_meta( self::$post_id, '_wp_page_template', 'post-my-test-template.php' );
2631
2632
		// reregister the route as we now have a template available.
2633
		$GLOBALS['wp_rest_server']->override_by_default = true;
2634
		$controller = new WP_REST_Posts_Controller( 'post' );
2635
		$controller->register_routes();
2636
		$GLOBALS['wp_rest_server']->override_by_default = false;
2637
2638
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2639
		$params = $this->set_post_data( array(
2640
			'template' => '',
2641
		) );
2642
		$request->set_body_params( $params );
2643
		$response = $this->server->dispatch( $request );
2644
2645
		$data = $response->get_data();
2646
		$post_template = get_page_template_slug( get_post( $data['id'] ) );
0 ignored issues
show
Bug introduced by
It seems like get_post($data['id']) targeting get_post() can also be of type array; however, get_page_template_slug() does only seem to accept integer|object<WP_Post>|null, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
2647
2648
		$this->assertEquals( '', $data['template'] );
2649
		$this->assertEquals( '', $post_template );
2650
	}
2651
2652
2653
	public function verify_post_roundtrip( $input = array(), $expected_output = array() ) {
2654
		// Create the post
2655
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
2656
		foreach ( $input as $name => $value ) {
2657
			$request->set_param( $name, $value );
2658
		}
2659
		$response = $this->server->dispatch( $request );
2660
		$this->assertEquals( 201, $response->get_status() );
2661
		$actual_output = $response->get_data();
2662
2663
		// Compare expected API output to actual API output
2664
		$this->assertEquals( $expected_output['title']['raw']       , $actual_output['title']['raw'] );
2665
		$this->assertEquals( $expected_output['title']['rendered']  , trim( $actual_output['title']['rendered'] ) );
2666
		$this->assertEquals( $expected_output['content']['raw']     , $actual_output['content']['raw'] );
2667
		$this->assertEquals( $expected_output['content']['rendered'], trim( $actual_output['content']['rendered'] ) );
2668
		$this->assertEquals( $expected_output['excerpt']['raw']     , $actual_output['excerpt']['raw'] );
2669
		$this->assertEquals( $expected_output['excerpt']['rendered'], trim( $actual_output['excerpt']['rendered'] ) );
2670
2671
		// Compare expected API output to WP internal values
2672
		$post = get_post( $actual_output['id'] );
2673
		$this->assertEquals( $expected_output['title']['raw']  , $post->post_title );
2674
		$this->assertEquals( $expected_output['content']['raw'], $post->post_content );
2675
		$this->assertEquals( $expected_output['excerpt']['raw'], $post->post_excerpt );
2676
2677
		// Update the post
2678
		$request = new WP_REST_Request( 'PUT', sprintf( '/wp/v2/posts/%d', $actual_output['id'] ) );
2679
		foreach ( $input as $name => $value ) {
2680
			$request->set_param( $name, $value );
2681
		}
2682
		$response = $this->server->dispatch( $request );
2683
		$this->assertEquals( 200, $response->get_status() );
2684
		$actual_output = $response->get_data();
2685
2686
		// Compare expected API output to actual API output
2687
		$this->assertEquals( $expected_output['title']['raw']       , $actual_output['title']['raw'] );
2688
		$this->assertEquals( $expected_output['title']['rendered']  , trim( $actual_output['title']['rendered'] ) );
2689
		$this->assertEquals( $expected_output['content']['raw']     , $actual_output['content']['raw'] );
2690
		$this->assertEquals( $expected_output['content']['rendered'], trim( $actual_output['content']['rendered'] ) );
2691
		$this->assertEquals( $expected_output['excerpt']['raw']     , $actual_output['excerpt']['raw'] );
2692
		$this->assertEquals( $expected_output['excerpt']['rendered'], trim( $actual_output['excerpt']['rendered'] ) );
2693
2694
		// Compare expected API output to WP internal values
2695
		$post = get_post( $actual_output['id'] );
2696
		$this->assertEquals( $expected_output['title']['raw']  , $post->post_title );
2697
		$this->assertEquals( $expected_output['content']['raw'], $post->post_content );
2698
		$this->assertEquals( $expected_output['excerpt']['raw'], $post->post_excerpt );
2699
	}
2700
2701
	public static function post_roundtrip_provider() {
2702
		return array(
2703
			array(
2704
				// Raw values.
2705
				array(
2706
					'title'   => '\o/ ¯\_(ツ)_/¯',
2707
					'content' => '\o/ ¯\_(ツ)_/¯',
2708
					'excerpt' => '\o/ ¯\_(ツ)_/¯',
2709
				),
2710
				// Expected returned values.
2711
				array(
2712
					'title' => array(
2713
						'raw'      => '\o/ ¯\_(ツ)_/¯',
2714
						'rendered' => '\o/ ¯\_(ツ)_/¯',
2715
					),
2716
					'content' => array(
2717
						'raw'      => '\o/ ¯\_(ツ)_/¯',
2718
						'rendered' => '<p>\o/ ¯\_(ツ)_/¯</p>',
2719
					),
2720
					'excerpt' => array(
2721
						'raw'      => '\o/ ¯\_(ツ)_/¯',
2722
						'rendered' => '<p>\o/ ¯\_(ツ)_/¯</p>',
2723
					),
2724
				)
2725
			),
2726
			array(
2727
				// Raw values.
2728
				array(
2729
					'title'   => '\\\&\\\ &amp; &invalid; < &lt; &amp;lt;',
2730
					'content' => '\\\&\\\ &amp; &invalid; < &lt; &amp;lt;',
2731
					'excerpt' => '\\\&\\\ &amp; &invalid; < &lt; &amp;lt;',
2732
				),
2733
				// Expected returned values.
2734
				array(
2735
					'title' => array(
2736
						'raw'      => '\\\&amp;\\\ &amp; &amp;invalid; &lt; &lt; &amp;lt;',
2737
						'rendered' => '\\\&amp;\\\ &amp; &amp;invalid; &lt; &lt; &amp;lt;',
2738
					),
2739
					'content' => array(
2740
						'raw'      => '\\\&amp;\\\ &amp; &amp;invalid; &lt; &lt; &amp;lt;',
2741
						'rendered' => '<p>\\\&amp;\\\ &amp; &amp;invalid; &lt; &lt; &amp;lt;</p>',
2742
					),
2743
					'excerpt' => array(
2744
						'raw'      => '\\\&amp;\\\ &amp; &amp;invalid; &lt; &lt; &amp;lt;',
2745
						'rendered' => '<p>\\\&amp;\\\ &amp; &amp;invalid; &lt; &lt; &amp;lt;</p>',
2746
					),
2747
				),
2748
			),
2749
			array(
2750
				// Raw values.
2751
				array(
2752
					'title'   => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
2753
					'content' => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
2754
					'excerpt' => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
2755
				),
2756
				// Expected returned values.
2757
				array(
2758
					'title' => array(
2759
						'raw'      => 'div <strong>strong</strong> oh noes',
2760
						'rendered' => 'div <strong>strong</strong> oh noes',
2761
					),
2762
					'content' => array(
2763
						'raw'      => '<div>div</div> <strong>strong</strong> oh noes',
2764
						'rendered' => "<div>div</div>\n<p> <strong>strong</strong> oh noes</p>",
2765
					),
2766
					'excerpt' => array(
2767
						'raw'      => '<div>div</div> <strong>strong</strong> oh noes',
2768
						'rendered' => "<div>div</div>\n<p> <strong>strong</strong> oh noes</p>",
2769
					),
2770
				)
2771
			),
2772
			array(
2773
				// Raw values.
2774
				array(
2775
					'title'   => '<a href="#" target="_blank" data-unfiltered=true>link</a>',
2776
					'content' => '<a href="#" target="_blank" data-unfiltered=true>link</a>',
2777
					'excerpt' => '<a href="#" target="_blank" data-unfiltered=true>link</a>',
2778
				),
2779
				// Expected returned values.
2780
				array(
2781
					'title' => array(
2782
						'raw'      => '<a href="#">link</a>',
2783
						'rendered' => '<a href="#">link</a>',
2784
					),
2785
					'content' => array(
2786
						'raw'      => '<a href="#" target="_blank">link</a>',
2787
						'rendered' => '<p><a href="#" target="_blank">link</a></p>',
2788
					),
2789
					'excerpt' => array(
2790
						'raw'      => '<a href="#" target="_blank">link</a>',
2791
						'rendered' => '<p><a href="#" target="_blank">link</a></p>',
2792
					),
2793
				)
2794
			),
2795
		);
2796
	}
2797
2798
	/**
2799
	 * @dataProvider post_roundtrip_provider
2800
	 */
2801
	public function test_post_roundtrip_as_author( $raw, $expected ) {
2802
		wp_set_current_user( self::$author_id );
2803
		$this->assertFalse( current_user_can( 'unfiltered_html' ) );
2804
		$this->verify_post_roundtrip( $raw, $expected );
2805
	}
2806
2807
	public function test_post_roundtrip_as_editor_unfiltered_html() {
2808
		wp_set_current_user( self::$editor_id );
2809
		if ( is_multisite() ) {
2810
			$this->assertFalse( current_user_can( 'unfiltered_html' ) );
2811
			$this->verify_post_roundtrip( array(
2812
				'title'   => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
2813
				'content' => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
2814
				'excerpt' => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
2815
			), array(
2816
				'title' => array(
2817
					'raw'      => 'div <strong>strong</strong> oh noes',
2818
					'rendered' => 'div <strong>strong</strong> oh noes',
2819
				),
2820
				'content' => array(
2821
					'raw'      => '<div>div</div> <strong>strong</strong> oh noes',
2822
					'rendered' => "<div>div</div>\n<p> <strong>strong</strong> oh noes</p>",
2823
				),
2824
				'excerpt' => array(
2825
					'raw'      => '<div>div</div> <strong>strong</strong> oh noes',
2826
					'rendered' => "<div>div</div>\n<p> <strong>strong</strong> oh noes</p>",
2827
				),
2828
			) );
2829
		} else {
2830
			$this->assertTrue( current_user_can( 'unfiltered_html' ) );
2831
			$this->verify_post_roundtrip( array(
2832
				'title'   => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
2833
				'content' => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
2834
				'excerpt' => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
2835
			), array(
2836
				'title' => array(
2837
					'raw'      => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
2838
					'rendered' => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
2839
				),
2840
				'content' => array(
2841
					'raw'      => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
2842
					'rendered' => "<div>div</div>\n<p> <strong>strong</strong> <script>oh noes</script></p>",
2843
				),
2844
				'excerpt' => array(
2845
					'raw'      => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
2846
					'rendered' => "<div>div</div>\n<p> <strong>strong</strong> <script>oh noes</script></p>",
2847
				),
2848
			) );
2849
		}
2850
	}
2851
2852
	public function test_post_roundtrip_as_superadmin_unfiltered_html() {
2853
		wp_set_current_user( self::$superadmin_id );
2854
		$this->assertTrue( current_user_can( 'unfiltered_html' ) );
2855
		$this->verify_post_roundtrip( array(
2856
			'title'   => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
2857
			'content' => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
2858
			'excerpt' => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
2859
		), array(
2860
			'title' => array(
2861
				'raw'      => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
2862
				'rendered' => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
2863
			),
2864
			'content' => array(
2865
				'raw'      => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
2866
				'rendered' => "<div>div</div>\n<p> <strong>strong</strong> <script>oh noes</script></p>",
2867
			),
2868
			'excerpt' => array(
2869
				'raw'      => '<div>div</div> <strong>strong</strong> <script>oh noes</script>',
2870
				'rendered' => "<div>div</div>\n<p> <strong>strong</strong> <script>oh noes</script></p>",
2871
			),
2872
		) );
2873
	}
2874
2875
	public function test_delete_item() {
2876
		$post_id = $this->factory->post->create( array( 'post_title' => 'Deleted post' ) );
2877
		wp_set_current_user( self::$editor_id );
2878
2879
		$request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/posts/%d', $post_id ) );
2880
		$request->set_param( 'force', 'false' );
2881
		$response = $this->server->dispatch( $request );
2882
2883
		$this->assertEquals( 200, $response->get_status() );
2884
		$data = $response->get_data();
2885
		$this->assertEquals( 'Deleted post', $data['title']['raw'] );
2886
		$this->assertEquals( 'trash', $data['status'] );
2887
	}
2888
2889
	public function test_delete_item_skip_trash() {
2890
		$post_id = $this->factory->post->create( array( 'post_title' => 'Deleted post' ) );
2891
		wp_set_current_user( self::$editor_id );
2892
2893
		$request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/posts/%d', $post_id ) );
2894
		$request['force'] = true;
2895
		$response = $this->server->dispatch( $request );
2896
2897
		$this->assertEquals( 200, $response->get_status() );
2898
		$data = $response->get_data();
2899
		$this->assertTrue( $data['deleted'] );
2900
		$this->assertNotEmpty( $data['previous'] );
2901
	}
2902
2903
	public function test_delete_item_already_trashed() {
2904
		$post_id = $this->factory->post->create( array( 'post_title' => 'Deleted post' ) );
2905
		wp_set_current_user( self::$editor_id );
2906
		$request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/posts/%d', $post_id ) );
2907
		$response = $this->server->dispatch( $request );
2908
		$this->assertEquals( 200, $response->get_status() );
2909
		$response = $this->server->dispatch( $request );
2910
		$this->assertErrorResponse( 'rest_already_trashed', $response, 410 );
2911
	}
2912
2913
	public function test_delete_post_invalid_id() {
2914
		wp_set_current_user( self::$editor_id );
2915
2916
		$request = new WP_REST_Request( 'DELETE', '/wp/v2/posts/' . REST_TESTS_IMPOSSIBLY_HIGH_NUMBER );
2917
		$response = $this->server->dispatch( $request );
2918
2919
		$this->assertErrorResponse( 'rest_post_invalid_id', $response, 404 );
2920
	}
2921
2922
	public function test_delete_post_invalid_post_type() {
2923
		$page_id = $this->factory->post->create( array( 'post_type' => 'page' ) );
2924
		wp_set_current_user( self::$editor_id );
2925
2926
		$request = new WP_REST_Request( 'DELETE', '/wp/v2/posts/' . $page_id );
2927
		$response = $this->server->dispatch( $request );
2928
2929
		$this->assertErrorResponse( 'rest_post_invalid_id', $response, 404 );
2930
	}
2931
2932
	public function test_delete_post_without_permission() {
2933
		wp_set_current_user( self::$author_id );
2934
2935
		$request = new WP_REST_Request( 'DELETE', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2936
		$response = $this->server->dispatch( $request );
2937
2938
		$this->assertErrorResponse( 'rest_cannot_delete', $response, 403 );
2939
	}
2940
2941
	public function test_register_post_type_invalid_controller() {
2942
2943
		register_post_type( 'invalid-controller', array( 'show_in_rest' => true, 'rest_controller_class' => 'Fake_Class_Baba' ) );
2944
		create_initial_rest_routes();
2945
		$routes = $this->server->get_routes();
2946
		$this->assertFalse( isset( $routes['/wp/v2/invalid-controller'] ) );
2947
		_unregister_post_type( 'invalid-controller' );
2948
2949
	}
2950
2951
	public function test_get_item_schema() {
2952
		$request = new WP_REST_Request( 'OPTIONS', '/wp/v2/posts' );
2953
		$response = $this->server->dispatch( $request );
2954
		$data = $response->get_data();
2955
		$properties = $data['schema']['properties'];
2956
		$this->assertEquals( 24, count( $properties ) );
2957
		$this->assertArrayHasKey( 'author', $properties );
2958
		$this->assertArrayHasKey( 'comment_status', $properties );
2959
		$this->assertArrayHasKey( 'content', $properties );
2960
		$this->assertArrayHasKey( 'date', $properties );
2961
		$this->assertArrayHasKey( 'date_gmt', $properties );
2962
		$this->assertArrayHasKey( 'excerpt', $properties );
2963
		$this->assertArrayHasKey( 'featured_media', $properties );
2964
		$this->assertArrayHasKey( 'guid', $properties );
2965
		$this->assertArrayHasKey( 'format', $properties );
2966
		$this->assertArrayHasKey( 'id', $properties );
2967
		$this->assertArrayHasKey( 'link', $properties );
2968
		$this->assertArrayHasKey( 'meta', $properties );
2969
		$this->assertArrayHasKey( 'modified', $properties );
2970
		$this->assertArrayHasKey( 'modified_gmt', $properties );
2971
		$this->assertArrayHasKey( 'password', $properties );
2972
		$this->assertArrayHasKey( 'ping_status', $properties );
2973
		$this->assertArrayHasKey( 'slug', $properties );
2974
		$this->assertArrayHasKey( 'status', $properties );
2975
		$this->assertArrayHasKey( 'sticky', $properties );
2976
		$this->assertArrayHasKey( 'template', $properties );
2977
		$this->assertArrayHasKey( 'title', $properties );
2978
		$this->assertArrayHasKey( 'type', $properties );
2979
		$this->assertArrayHasKey( 'tags', $properties );
2980
		$this->assertArrayHasKey( 'categories', $properties );
2981
	}
2982
2983
	/**
2984
	 * @ticket 39805
2985
	 */
2986
	public function test_get_post_view_context_properties() {
2987
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
2988
		$request->set_param( 'context', 'view' );
2989
		$response = $this->server->dispatch( $request );
2990
		$keys = array_keys( $response->get_data() );
2991
		sort( $keys );
2992
2993
		$expected_keys = array(
2994
			'author',
2995
			'categories',
2996
			'comment_status',
2997
			'content',
2998
			'date',
2999
			'date_gmt',
3000
			'excerpt',
3001
			'featured_media',
3002
			'format',
3003
			'guid',
3004
			'id',
3005
			'link',
3006
			'meta',
3007
			'modified',
3008
			'modified_gmt',
3009
			'ping_status',
3010
			'slug',
3011
			'status',
3012
			'sticky',
3013
			'tags',
3014
			'template',
3015
			'title',
3016
			'type',
3017
		);
3018
3019
		$this->assertEquals( $expected_keys, $keys );
3020
	}
3021
3022
	public function test_get_post_edit_context_properties() {
3023
		wp_set_current_user( self::$editor_id );
3024
3025
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
3026
		$request->set_param( 'context', 'edit' );
3027
		$response = $this->server->dispatch( $request );
3028
		$keys = array_keys( $response->get_data() );
3029
		sort( $keys );
3030
3031
		$expected_keys = array(
3032
			'author',
3033
			'categories',
3034
			'comment_status',
3035
			'content',
3036
			'date',
3037
			'date_gmt',
3038
			'excerpt',
3039
			'featured_media',
3040
			'format',
3041
			'guid',
3042
			'id',
3043
			'link',
3044
			'meta',
3045
			'modified',
3046
			'modified_gmt',
3047
			'password',
3048
			'ping_status',
3049
			'slug',
3050
			'status',
3051
			'sticky',
3052
			'tags',
3053
			'template',
3054
			'title',
3055
			'type',
3056
		);
3057
3058
		$this->assertEquals( $expected_keys, $keys );
3059
	}
3060
3061
	public function test_get_post_embed_context_properties() {
3062
		$request = new WP_REST_Request( 'GET', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
3063
		$request->set_param( 'context', 'embed' );
3064
		$response = $this->server->dispatch( $request );
3065
		$keys = array_keys( $response->get_data() );
3066
		sort( $keys );
3067
3068
		$expected_keys = array(
3069
			'author',
3070
			'date',
3071
			'excerpt',
3072
			'featured_media',
3073
			'id',
3074
			'link',
3075
			'slug',
3076
			'title',
3077
			'type',
3078
		);
3079
3080
		$this->assertEquals( $expected_keys, $keys );
3081
	}
3082
3083
	public function test_status_array_enum_args() {
3084
		$request = new WP_REST_Request( 'GET', '/wp/v2' );
3085
		$response = $this->server->dispatch( $request );
3086
		$data = $response->get_data();
3087
		$list_posts_args = $data['routes']['/wp/v2/posts']['endpoints'][0]['args'];
3088
		$status_arg = $list_posts_args['status'];
3089
		$this->assertEquals( 'array', $status_arg['type'] );
3090
		$this->assertEquals( array(
3091
			'type' => 'string',
3092
			'enum' => array( 'publish', 'future', 'draft', 'pending', 'private', 'trash', 'auto-draft', 'inherit', 'any' ),
3093
		), $status_arg['items'] );
3094
	}
3095
3096
	public function test_get_additional_field_registration() {
3097
3098
		$schema = array(
3099
			'type'        => 'integer',
3100
			'description' => 'Some integer of mine',
3101
			'enum'        => array( 1, 2, 3, 4 ),
3102
			'context'     => array( 'view', 'edit' ),
3103
		);
3104
3105
		register_rest_field( 'post', 'my_custom_int', array(
3106
			'schema'          => $schema,
3107
			'get_callback'    => array( $this, 'additional_field_get_callback' ),
3108
			'update_callback' => array( $this, 'additional_field_update_callback' ),
3109
		) );
3110
3111
		$request = new WP_REST_Request( 'OPTIONS', '/wp/v2/posts' );
3112
3113
		$response = $this->server->dispatch( $request );
3114
		$data = $response->get_data();
3115
3116
		$this->assertArrayHasKey( 'my_custom_int', $data['schema']['properties'] );
3117
		$this->assertEquals( $schema, $data['schema']['properties']['my_custom_int'] );
3118
3119
		wp_set_current_user( 1 );
3120
3121
		$post_id = $this->factory->post->create();
3122
3123
		$request = new WP_REST_Request( 'GET', '/wp/v2/posts/' . $post_id );
3124
3125
		$response = $this->server->dispatch( $request );
3126
		$this->assertArrayHasKey( 'my_custom_int', $response->data );
3127
3128
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts/' . $post_id );
3129
		$request->set_body_params(array(
3130
			'my_custom_int' => 123,
3131
		));
3132
3133
		$response = $this->server->dispatch( $request );
0 ignored issues
show
Unused Code introduced by
$response is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
3134
		$this->assertEquals( 123, get_post_meta( $post_id, 'my_custom_int', true ) );
3135
3136
		$request = new WP_REST_Request( 'POST', '/wp/v2/posts' );
3137
		$request->set_body_params(array(
3138
			'my_custom_int' => 123,
3139
			'title' => 'hello',
3140
		));
3141
3142
		$response = $this->server->dispatch( $request );
3143
3144
		$this->assertEquals( 123, $response->data['my_custom_int'] );
3145
3146
		global $wp_rest_additional_fields;
3147
		$wp_rest_additional_fields = array();
3148
	}
3149
3150
	public function test_additional_field_update_errors() {
3151
		$schema = array(
3152
			'type'        => 'integer',
3153
			'description' => 'Some integer of mine',
3154
			'enum'        => array( 1, 2, 3, 4 ),
3155
			'context'     => array( 'view', 'edit' ),
3156
		);
3157
3158
		register_rest_field( 'post', 'my_custom_int', array(
3159
			'schema'          => $schema,
3160
			'get_callback'    => array( $this, 'additional_field_get_callback' ),
3161
			'update_callback' => array( $this, 'additional_field_update_callback' ),
3162
		) );
3163
3164
		wp_set_current_user( self::$editor_id );
3165
		// Check for error on update.
3166
		$request = new WP_REST_Request( 'POST', sprintf( '/wp/v2/posts/%d', self::$post_id ) );
3167
		$request->set_body_params( array(
3168
			'my_custom_int' => 'returnError',
3169
		) );
3170
3171
		$response = $this->server->dispatch( $request );
3172
3173
		$this->assertErrorResponse( 'rest_invalid_param', $response, 400 );
3174
3175
		global $wp_rest_additional_fields;
3176
		$wp_rest_additional_fields = array();
3177
	}
3178
3179
	public function additional_field_get_callback( $object ) {
3180
		return get_post_meta( $object['id'], 'my_custom_int', true );
3181
	}
3182
3183
	public function additional_field_update_callback( $value, $post ) {
3184
		if ( 'returnError' === $value ) {
3185
			return new WP_Error( 'rest_invalid_param', 'Testing an error.', array( 'status' => 400 ) );
3186
		}
3187
		update_post_meta( $post->ID, 'my_custom_int', $value );
3188
	}
3189
3190
	public function tearDown() {
3191
		_unregister_post_type( 'youseeeme' );
3192
		if ( isset( $this->attachment_id ) ) {
3193
			$this->remove_added_uploads();
3194
		}
3195
		remove_filter( 'rest_pre_dispatch', array( $this, 'wpSetUpBeforeRequest' ), 10, 3 );
3196
		remove_filter( 'posts_clauses', array( $this, 'save_posts_clauses' ), 10, 2 );
3197
		parent::tearDown();
3198
	}
3199
3200
	/**
3201
	 * Internal function used to disable an insert query which
3202
	 * will trigger a wpdb error for testing purposes.
3203
	 */
3204
	public function error_insert_query( $query ) {
3205
		if ( strpos( $query, 'INSERT' ) === 0 ) {
3206
			$query = '],';
3207
		}
3208
		return $query;
3209
	}
3210
3211
	public function filter_theme_post_templates( $post_templates ) {
3212
		return array(
3213
			'post-my-test-template.php' => 'My Test Template',
3214
		);
3215
	}
3216
}
3217