WordPress REST API (Version 2) - Version 2.0-beta14

Version Description

Download this release

Release Info

Developer rachelbaker
Plugin Icon 128x128 WordPress REST API (Version 2)
Version 2.0-beta14
Comparing to
See all releases

Code changes from version 2.0-beta13.1 to 2.0-beta14

CHANGELOG.md CHANGED
@@ -1,8 +1,255 @@
1
  # Changelog
2
 
3
- ## 2.0 Beta 13.1 (May 25, 2016)
4
 
5
- - SECURITY: Return error when request can't context==edit for users.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
 
7
  ## 2.0 Beta 13.0 (March 29, 2016)
8
 
1
  # Changelog
2
 
3
+ ## 2.0 Beta 14.0 (September 30, 2016)
4
 
5
+ - Add support for password protected posts
6
+
7
+ Password protected posts are now fully supported, you can create edit and read password protected posts in the REST API. There is now a `protected` attribute in the `content` and `excerpt` fields in post response.
8
+
9
+ To view password protected posts via the API, use the `password` query parameter to provide the post's password.
10
+
11
+ (props @joehoyle, [#2720][gh-2720])
12
+
13
+ - Allow returning an error from field update callbacks
14
+
15
+ Fields added via `register_rest_field` can now return an instance of `WP_Error` in the `update_callback`.
16
+
17
+ (props @rmccue, [#2702][gh-2702])
18
+
19
+ - Update the wp-api.js client from the client-js repo.
20
+
21
+ (props @joehoyle, [#2746][gh-2746])
22
+
23
+ - Add `relevance` `orderby` to posts endpoint
24
+
25
+ (props @websupporter, [#2579][gh-2579])
26
+
27
+ - Ability to order by `slug`, `email` and `url` on the users endpoints.
28
+
29
+ (props @joehoyle, [#2721][gh-2721])
30
+
31
+ - Add `sticky` parameter to the posts endpoint.
32
+
33
+ (props @joehoyle, [#2708][gh-2708])
34
+
35
+ - Add link to comment children, allowing threaded comment querying
36
+
37
+ (props @BE-Webdesign, [#2662][gh-2662], [#1612][gh-1612])
38
+
39
+ - Avoid unnecessary SQL query by passing `$user_nicename`
40
+
41
+ (props @danielbachhuber, [#2435][gh-2435])
42
+
43
+ - Don't allow reading / creating of posts with no parent
44
+
45
+ (props @rachelbaker, [#2744][gh-2744])
46
+
47
+ - Mark Users' `capabilities` property as readonly
48
+
49
+ (props @danielbachhuber, [#2440][gh-2440])
50
+
51
+ - Mark some post properties as readonly
52
+
53
+ (props @danielbachhuber, [#2438][gh-2438], [#2439][gh-2439])
54
+
55
+ - Use WPINC instead of wp-includes/
56
+
57
+ (props @websupporter, [#2461][gh-2461])
58
+
59
+ - Return error, if user can't list users & content=edit
60
+
61
+ (props @websupporter, [#2463][gh-2463])
62
+
63
+ - Conditionally model the term response based on its schema
64
+
65
+ (props @danielbachhuber, [#2470][gh-2470])
66
+
67
+ - Include Post data on the response object when declared
68
+
69
+ (props @websupporter, [#2423][gh-2423], [#2416][gh-2416])
70
+
71
+ - Add boolean type support to rest_validate_request_arg()
72
+
73
+ (props @westonruter, [#2478][gh-2478])
74
+
75
+ - Fix create/update requests not processing data included in the schema
76
+
77
+ (props @websupporter, [#2479][gh-2479])
78
+
79
+ - Remove Unused Parameter in lib/endpoints/class-wp-rest-controller.php
80
+
81
+ (props @hideokamoto, [#2500][gh-2500])
82
+
83
+ - Update post schema status description to reflect csv support.
84
+
85
+ (props @coderkevin, [#2534][gh-2534])
86
+
87
+ - Allow Comments to be created with a passed `author_ip`
88
+
89
+ (props @rachelbaker, [#1880][gh-1880])
90
+
91
+ - The get_the_excerpt filter expects the post object as of WP 4.5.
92
+
93
+ (props @lgedeon, [#2553][gh-2553])
94
+
95
+ - Introduce WP_REST_Controller::get_post() for allowing plugins to mutate
96
+ get_post()'s return value
97
+
98
+ (props @westonruter, [#2535][gh-2535])
99
+
100
+ - Use `show_in_rest` to determine "public" post types to check
101
+
102
+ (props @danielbachhuber, [#2384][gh-2384])
103
+
104
+ - #2426 Fix inconsistent type for user caps
105
+
106
+ (props @BE-Webdesign, [#2429][gh-2429], [#2426][gh-2426])
107
+
108
+ - Define user `type` as a string, not an array
109
+
110
+ (props @danielbachhuber, [#2556][gh-2556])
111
+
112
+ - Fix failing test: Typecast the user_id in search to a string
113
+
114
+ (props @rachelbaker, [#2617][gh-2617])
115
+
116
+ - #2587 Fix registered date schema
117
+
118
+ (props @BE-Webdesign, [#2628][gh-2628], [#2587][gh-2587])
119
+
120
+ - Fix forum url and installer-name in readme
121
+
122
+ (props @torounit, [#2656][gh-2656])
123
+
124
+ - Document options of the "status" parameter for Post collection GETs
125
+
126
+ (props @kadamwhite, [#2645][gh-2645])
127
+
128
+ - Improve WP_REST_Controller::filter_response_by_context().
129
+
130
+ (props @tfrommen, [#2641][gh-2641])
131
+
132
+ - #2424 Consistent slashes in rest_url() usage
133
+
134
+ (props @BE-Webdesign, [#2428][gh-2428], [#2424][gh-2424])
135
+
136
+ - Add filters to allow for relevance search
137
+
138
+ (props @websupporter, [#2665][gh-2665])
139
+
140
+ - Alter default comment sort order to be "desc"
141
+
142
+ (props @kadamwhite, [#2684][gh-2684])
143
+
144
+ - Add raw and rendered to revisions schema
145
+
146
+ (props @websupporter, [#2693][gh-2693])
147
+
148
+ - "WP API" -> "WordPress REST API" in README files
149
+
150
+ (props @kadamwhite, [#2697][gh-2697])
151
+
152
+ - Improve boolean validation from schema
153
+
154
+ (props @BE-Webdesign, [#2704][gh-2704], [#2616][gh-2616])
155
+
156
+ - Fix typo (PUT vs POST) in readme.md
157
+
158
+ (props @kadamwhite, [#2716][gh-2716])
159
+
160
+ - Add Codecov configuration
161
+
162
+ (props @danielbachhuber, [#2718][gh-2718])
163
+
164
+ - Fix inefficiency in users endpoint using `search => **`
165
+
166
+ (props @joehoyle, [#2722][gh-2722])
167
+
168
+ - Ensure the terms list is a list
169
+
170
+ (props @joehoyle, [#2724][gh-2724])
171
+
172
+ - Added @return on handle_featured_media() doc
173
+
174
+ (props @vishalkakadiya, [#2725][gh-2725])
175
+
176
+ - #2730 Update attachments fields added with `register_rest_field`
177
+
178
+ (props @BE-Webdesign, [#2731][gh-2731], [#2730][gh-2730])
179
+
180
+ - #2582 Ensure the `roles` property is always an array
181
+
182
+ (props @BE-Webdesign, [#2728][gh-2728], [#2582][gh-2582])
183
+
184
+ - Move post_password_required filtering to preparation
185
+
186
+ (props @rmccue, [#2735][gh-2735])
187
+
188
+ - Use wrapper for `sanitize_title` to avoid messed up slugs.
189
+
190
+ (props @joehoyle, [#2723][gh-2723])
191
+
192
+ - Force per_page to override the filter variable
193
+
194
+ (props @rmccue, [#2699][gh-2699])
195
+
196
+ [gh-1612]: https://github.com/WP-API/WP-API/issues/1612
197
+ [gh-1880]: https://github.com/WP-API/WP-API/issues/1880
198
+ [gh-2384]: https://github.com/WP-API/WP-API/issues/2384
199
+ [gh-2416]: https://github.com/WP-API/WP-API/issues/2416
200
+ [gh-2423]: https://github.com/WP-API/WP-API/issues/2423
201
+ [gh-2424]: https://github.com/WP-API/WP-API/issues/2424
202
+ [gh-2426]: https://github.com/WP-API/WP-API/issues/2426
203
+ [gh-2428]: https://github.com/WP-API/WP-API/issues/2428
204
+ [gh-2429]: https://github.com/WP-API/WP-API/issues/2429
205
+ [gh-2435]: https://github.com/WP-API/WP-API/issues/2435
206
+ [gh-2436]: https://github.com/WP-API/WP-API/issues/2436
207
+ [gh-2438]: https://github.com/WP-API/WP-API/issues/2438
208
+ [gh-2439]: https://github.com/WP-API/WP-API/issues/2439
209
+ [gh-2440]: https://github.com/WP-API/WP-API/issues/2440
210
+ [gh-2441]: https://github.com/WP-API/WP-API/issues/2441
211
+ [gh-2461]: https://github.com/WP-API/WP-API/issues/2461
212
+ [gh-2463]: https://github.com/WP-API/WP-API/issues/2463
213
+ [gh-2470]: https://github.com/WP-API/WP-API/issues/2470
214
+ [gh-2478]: https://github.com/WP-API/WP-API/issues/2478
215
+ [gh-2479]: https://github.com/WP-API/WP-API/issues/2479
216
+ [gh-2500]: https://github.com/WP-API/WP-API/issues/2500
217
+ [gh-2534]: https://github.com/WP-API/WP-API/issues/2534
218
+ [gh-2535]: https://github.com/WP-API/WP-API/issues/2535
219
+ [gh-2553]: https://github.com/WP-API/WP-API/issues/2553
220
+ [gh-2556]: https://github.com/WP-API/WP-API/issues/2556
221
+ [gh-2579]: https://github.com/WP-API/WP-API/issues/2579
222
+ [gh-2582]: https://github.com/WP-API/WP-API/issues/2582
223
+ [gh-2587]: https://github.com/WP-API/WP-API/issues/2587
224
+ [gh-2616]: https://github.com/WP-API/WP-API/issues/2616
225
+ [gh-2617]: https://github.com/WP-API/WP-API/issues/2617
226
+ [gh-2628]: https://github.com/WP-API/WP-API/issues/2628
227
+ [gh-2641]: https://github.com/WP-API/WP-API/issues/2641
228
+ [gh-2645]: https://github.com/WP-API/WP-API/issues/2645
229
+ [gh-2656]: https://github.com/WP-API/WP-API/issues/2656
230
+ [gh-2662]: https://github.com/WP-API/WP-API/issues/2662
231
+ [gh-2665]: https://github.com/WP-API/WP-API/issues/2665
232
+ [gh-2684]: https://github.com/WP-API/WP-API/issues/2684
233
+ [gh-2693]: https://github.com/WP-API/WP-API/issues/2693
234
+ [gh-2697]: https://github.com/WP-API/WP-API/issues/2697
235
+ [gh-2699]: https://github.com/WP-API/WP-API/issues/2699
236
+ [gh-2702]: https://github.com/WP-API/WP-API/issues/2702
237
+ [gh-2704]: https://github.com/WP-API/WP-API/issues/2704
238
+ [gh-2708]: https://github.com/WP-API/WP-API/issues/2708
239
+ [gh-2716]: https://github.com/WP-API/WP-API/issues/2716
240
+ [gh-2718]: https://github.com/WP-API/WP-API/issues/2718
241
+ [gh-2720]: https://github.com/WP-API/WP-API/issues/2720
242
+ [gh-2721]: https://github.com/WP-API/WP-API/issues/2721
243
+ [gh-2722]: https://github.com/WP-API/WP-API/issues/2722
244
+ [gh-2723]: https://github.com/WP-API/WP-API/issues/2723
245
+ [gh-2724]: https://github.com/WP-API/WP-API/issues/2724
246
+ [gh-2725]: https://github.com/WP-API/WP-API/issues/2725
247
+ [gh-2728]: https://github.com/WP-API/WP-API/issues/2728
248
+ [gh-2730]: https://github.com/WP-API/WP-API/issues/2730
249
+ [gh-2731]: https://github.com/WP-API/WP-API/issues/2731
250
+ [gh-2735]: https://github.com/WP-API/WP-API/issues/2735
251
+ [gh-2744]: https://github.com/WP-API/WP-API/issues/2744
252
+ [gh-2746]: https://github.com/WP-API/WP-API/issues/2746
253
 
254
  ## 2.0 Beta 13.0 (March 29, 2016)
255
 
README.md CHANGED
@@ -6,13 +6,12 @@ Access your WordPress site's data through an easy-to-use HTTP REST API.
6
  [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/WP-API/WP-API/badges/quality-score.png?b=develop)](https://scrutinizer-ci.com/g/WP-API/WP-API/?branch=develop)
7
  [![codecov.io](http://codecov.io/github/WP-API/WP-API/coverage.svg?branch=develop)](http://codecov.io/github/WP-API/WP-API?branch=develop)
8
 
9
- ## WARNING
 
10
 
11
- The **"develop"** branch is undergoing substantial changes and is **NOT COMPLETE OR STABLE**. [Read the in-progress documentation](http://v2.wp-api.org/) to introduce yourself to endpoints, internal patterns, and implementation details.
12
 
13
- The **"master"** branch represents a **BETA** of our next version release.
14
-
15
- The latest **stable** version is available from the [WordPress Plugin Directory](https://wordpress.org/plugins/rest-api/).
16
 
17
  ## About
18
 
@@ -26,15 +25,15 @@ site's data in simple JSON format, including users, posts, taxonomies and more.
26
  Retrieving or updating data is as simple as sending a HTTP request.
27
 
28
  Want to get your site's posts? Simply send a `GET` request to `/wp-json/wp/v2/posts`.
29
- Update user with ID 4? Send a `POST` request to `/wp-json/wp/v2/users/4`. Get all
30
  posts with the search term "awesome"? `GET /wp-json/wp/v2/posts?filter[s]=awesome`.
31
  It's that easy.
32
 
33
- WP API exposes a simple yet easy interface to WP Query, the posts API, post meta
34
- API, users API, revisions API and many more. Chances are, if you can do it with
35
- WordPress, WP API will let you do it.
36
 
37
- WP API also includes an easy-to-use JavaScript API based on Backbone models,
38
  allowing plugin and theme developers to get up and running without needing to
39
  know anything about the details of getting connected.
40
 
@@ -42,34 +41,39 @@ Check out [our documentation][docs] for information on what's available in the
42
  API and how to use it. We've also got documentation on extending the API with
43
  extra data for plugin and theme developers!
44
 
45
- There's no fixed timeline for integration into core at this time, but getting closer!
 
46
 
47
 
48
  ## Installation
49
 
50
- Drop this directory in and activate it. You need to be using pretty permalinks
51
- to use the plugin, as it uses custom rewrite rules to power the API.
 
52
 
53
- Also, be sure to use the Subversion `trunk` branch of WordPress Core as there are potentially recent commits to Core that the REST API relies on. See the [WordPress.org website](https://wordpress.org/download/svn/) for simple instructions.
 
 
54
 
55
  ## Issue Tracking
56
 
57
- All tickets for the project are being tracked on [GitHub][]. You can also take a
58
- look at the [recent updates][] for the project.
59
 
60
  ## Contributing
61
 
62
- Want to get involved? Check out [Contributing.md][contributing] for details on submitting fixes and new features.
 
63
 
64
  ## Security
65
 
66
  We take the security of the API extremely seriously. If you think you've found
67
  a security issue with the API (whether information disclosure, privilege
68
- escalation, or another issue), we'd appreciate responsible disclosure as soon as
69
- possible.
70
 
71
- To report a security issue, you can either email `security[at]wordpress.org`, or
72
- [file an issue on HackerOne][hackerone]. We will attempt to give an initial
73
  response to security issues within 48 hours at most, however keep in mind that
74
  the team is distributed across various timezones, and delays may occur as we
75
  discuss internally.
6
  [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/WP-API/WP-API/badges/quality-score.png?b=develop)](https://scrutinizer-ci.com/g/WP-API/WP-API/?branch=develop)
7
  [![codecov.io](http://codecov.io/github/WP-API/WP-API/coverage.svg?branch=develop)](http://codecov.io/github/WP-API/WP-API?branch=develop)
8
 
9
+ The **"develop"** branch is version 2 which is "beta" but stable and recommended for production. [Read the documentation](http://v2.wp-api.org/)
10
+ to introduce yourself to endpoints, internal patterns, and implementation details.
11
 
12
+ The **"master"** branch represents the **legacy** version of the REST API.
13
 
14
+ The latest **stable** version is also available from the [WordPress Plugin Directory](https://wordpress.org/plugins/rest-api/).
 
 
15
 
16
  ## About
17
 
25
  Retrieving or updating data is as simple as sending a HTTP request.
26
 
27
  Want to get your site's posts? Simply send a `GET` request to `/wp-json/wp/v2/posts`.
28
+ Update user with ID 4? Send a `PUT` request to `/wp-json/wp/v2/users/4`. Get all
29
  posts with the search term "awesome"? `GET /wp-json/wp/v2/posts?filter[s]=awesome`.
30
  It's that easy.
31
 
32
+ The WordPress REST API exposes a simple yet easy interface to WP Query, the posts
33
+ API, post meta API, users API, revisions API and many more. Chances are, if you
34
+ can do it with WordPress, the API will let you do it.
35
 
36
+ The REST API also includes an easy-to-use JavaScript API based on Backbone models,
37
  allowing plugin and theme developers to get up and running without needing to
38
  know anything about the details of getting connected.
39
 
41
  API and how to use it. We've also got documentation on extending the API with
42
  extra data for plugin and theme developers!
43
 
44
+ There's no fixed timeline for integration into core at this time, but getting
45
+ closer!
46
 
47
 
48
  ## Installation
49
 
50
+ Drop this directory into your plugins folder and activate it. You need to be
51
+ using pretty permalinks to use the plugin, as it uses custom rewrite rules to
52
+ power the API.
53
 
54
+ Also, be sure to use the Subversion `trunk` branch of WordPress Core as there
55
+ are potentially recent commits to Core that the REST API relies on. See the
56
+ [WordPress.org website](https://wordpress.org/download/svn/) for simple instructions.
57
 
58
  ## Issue Tracking
59
 
60
+ All tickets for the project are being tracked on [GitHub][]. You can also take
61
+ a look at the [recent updates][] for the project.
62
 
63
  ## Contributing
64
 
65
+ Want to get involved? Check out [Contributing.md][contributing] for details on
66
+ submitting fixes and new features.
67
 
68
  ## Security
69
 
70
  We take the security of the API extremely seriously. If you think you've found
71
  a security issue with the API (whether information disclosure, privilege
72
+ escalation, or another issue), we'd appreciate responsible disclosure as soon
73
+ as possible.
74
 
75
+ To report a security issue, you can either email `security[at]wordpress.org`,
76
+ or [file an issue on HackerOne][hackerone]. We will attempt to give an initial
77
  response to security issues within 48 hours at most, however keep in mind that
78
  the team is distributed across various timezones, and delays may occur as we
79
  discuss internally.
lib/endpoints/class-wp-rest-attachments-controller.php CHANGED
@@ -48,7 +48,7 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller {
48
 
49
  // Attaching media to a post requires ability to edit said post
50
  if ( ! empty( $request['post'] ) ) {
51
- $parent = get_post( (int) $request['post'] );
52
  $post_parent_type = get_post_type_object( $parent->post_type );
53
  if ( ! current_user_can( $post_parent_type->cap->edit_post, $request['post'] ) ) {
54
  return new WP_Error( 'rest_cannot_edit', __( 'Sorry, you are not allowed to upload media to this resource.' ), array( 'status' => rest_authorization_required_code() ) );
@@ -123,7 +123,7 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller {
123
  }
124
  return $id;
125
  }
126
- $attachment = get_post( $id );
127
 
128
  /** Include admin functions to get access to wp_generate_attachment_metadata() */
129
  require_once ABSPATH . 'wp-admin/includes/admin.php';
@@ -134,13 +134,16 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller {
134
  update_post_meta( $id, '_wp_attachment_image_alt', sanitize_text_field( $request['alt_text'] ) );
135
  }
136
 
137
- $this->update_additional_fields_for_object( $attachment, $request );
 
 
 
138
 
139
  $request->set_param( 'context', 'edit' );
140
  $response = $this->prepare_item_for_response( $attachment, $request );
141
  $response = rest_ensure_response( $response );
142
  $response->set_status( 201 );
143
- $response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $id ) ) );
144
 
145
  /**
146
  * Fires after a single attachment is created or updated via the REST API.
@@ -177,7 +180,13 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller {
177
  update_post_meta( $data['id'], '_wp_attachment_image_alt', $request['alt_text'] );
178
  }
179
 
180
- $attachment = get_post( $request['id'] );
 
 
 
 
 
 
181
  $request->set_param( 'context', 'edit' );
182
  $response = $this->prepare_item_for_response( $attachment, $request );
183
  $response = rest_ensure_response( $response );
48
 
49
  // Attaching media to a post requires ability to edit said post
50
  if ( ! empty( $request['post'] ) ) {
51
+ $parent = $this->get_post( (int) $request['post'] );
52
  $post_parent_type = get_post_type_object( $parent->post_type );
53
  if ( ! current_user_can( $post_parent_type->cap->edit_post, $request['post'] ) ) {
54
  return new WP_Error( 'rest_cannot_edit', __( 'Sorry, you are not allowed to upload media to this resource.' ), array( 'status' => rest_authorization_required_code() ) );
123
  }
124
  return $id;
125
  }
126
+ $attachment = $this->get_post( $id );
127
 
128
  /** Include admin functions to get access to wp_generate_attachment_metadata() */
129
  require_once ABSPATH . 'wp-admin/includes/admin.php';
134
  update_post_meta( $id, '_wp_attachment_image_alt', sanitize_text_field( $request['alt_text'] ) );
135
  }
136
 
137
+ $fields_update = $this->update_additional_fields_for_object( $attachment, $request );
138
+ if ( is_wp_error( $fields_update ) ) {
139
+ return $fields_update;
140
+ }
141
 
142
  $request->set_param( 'context', 'edit' );
143
  $response = $this->prepare_item_for_response( $attachment, $request );
144
  $response = rest_ensure_response( $response );
145
  $response->set_status( 201 );
146
+ $response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $id ) ) );
147
 
148
  /**
149
  * Fires after a single attachment is created or updated via the REST API.
180
  update_post_meta( $data['id'], '_wp_attachment_image_alt', $request['alt_text'] );
181
  }
182
 
183
+ $attachment = $this->get_post( $request['id'] );
184
+
185
+ $fields_update = $this->update_additional_fields_for_object( $attachment, $request );
186
+ if ( is_wp_error( $fields_update ) ) {
187
+ return $fields_update;
188
+ }
189
+
190
  $request->set_param( 'context', 'edit' );
191
  $response = $this->prepare_item_for_response( $attachment, $request );
192
  $response = rest_ensure_response( $response );
lib/endpoints/class-wp-rest-comments-controller.php CHANGED
@@ -71,7 +71,7 @@ class WP_REST_Comments_Controller extends WP_REST_Controller {
71
 
72
  if ( ! empty( $request['post'] ) ) {
73
  foreach ( (array) $request['post'] as $post_id ) {
74
- $post = get_post( $post_id );
75
  if ( ! empty( $post_id ) && $post && ! $this->check_read_post_permission( $post ) ) {
76
  return new WP_Error( 'rest_cannot_read_post', __( 'Sorry, you cannot read the post for this comment.' ), array( 'status' => rest_authorization_required_code() ) );
77
  } else if ( 0 === $post_id && ! current_user_can( 'moderate_comments' ) ) {
@@ -193,7 +193,7 @@ class WP_REST_Comments_Controller extends WP_REST_Controller {
193
  $response->header( 'X-WP-Total', $total_comments );
194
  $response->header( 'X-WP-TotalPages', $max_pages );
195
 
196
- $base = add_query_arg( $request->get_query_params(), rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ) );
197
  if ( $request['page'] > 1 ) {
198
  $prev_page = $request['page'] - 1;
199
  if ( $prev_page > $max_pages ) {
@@ -230,7 +230,7 @@ class WP_REST_Comments_Controller extends WP_REST_Controller {
230
  return new WP_Error( 'rest_cannot_read', __( 'Sorry, you cannot read this comment.' ), array( 'status' => rest_authorization_required_code() ) );
231
  }
232
 
233
- $post = get_post( $comment->comment_post_ID );
234
 
235
  if ( $post && ! $this->check_read_post_permission( $post ) ) {
236
  return new WP_Error( 'rest_cannot_read_post', __( 'Sorry, you cannot read the post for this comment.' ), array( 'status' => rest_authorization_required_code() ) );
@@ -258,7 +258,7 @@ class WP_REST_Comments_Controller extends WP_REST_Controller {
258
  }
259
 
260
  if ( ! empty( $comment->comment_post_ID ) ) {
261
- $post = get_post( $comment->comment_post_ID );
262
  if ( empty( $post ) ) {
263
  return new WP_Error( 'rest_post_invalid_id', __( 'Invalid post id.' ), array( 'status' => 404 ) );
264
  }
@@ -293,7 +293,11 @@ class WP_REST_Comments_Controller extends WP_REST_Controller {
293
  return new WP_Error( 'rest_comment_invalid_status', __( 'Sorry, you cannot set status for comments.' ), array( 'status' => rest_authorization_required_code() ) );
294
  }
295
 
296
- if ( ! empty( $request['post'] ) && $post = get_post( (int) $request['post'] ) ) {
 
 
 
 
297
 
298
  if ( ! $this->check_read_post_permission( $post ) ) {
299
  return new WP_Error( 'rest_cannot_read_post', __( 'Sorry, you cannot read the post for this comment.' ), array( 'status' => rest_authorization_required_code() ) );
@@ -346,7 +350,7 @@ class WP_REST_Comments_Controller extends WP_REST_Controller {
346
  if ( ! isset( $prepared_comment['comment_author_url'] ) ) {
347
  $prepared_comment['comment_author_url'] = '';
348
  }
349
- $prepared_comment['comment_author_IP'] = '127.0.0.1';
350
  $prepared_comment['comment_agent'] = '';
351
  $prepared_comment['comment_approved'] = wp_allow_comment( $prepared_comment );
352
 
@@ -371,14 +375,17 @@ class WP_REST_Comments_Controller extends WP_REST_Controller {
371
  }
372
 
373
  $comment = get_comment( $comment_id );
374
- $this->update_additional_fields_for_object( $comment, $request );
 
 
 
375
 
376
  $context = current_user_can( 'moderate_comments' ) ? 'edit' : 'view';
377
  $request->set_param( 'context', $context );
378
  $response = $this->prepare_item_for_response( $comment, $request );
379
  $response = rest_ensure_response( $response );
380
  $response->set_status( 201 );
381
- $response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $comment_id ) ) );
382
 
383
  /**
384
  * Fires after a comment is created or updated via the REST API.
@@ -451,7 +458,10 @@ class WP_REST_Comments_Controller extends WP_REST_Controller {
451
  }
452
 
453
  $comment = get_comment( $id );
454
- $this->update_additional_fields_for_object( $comment, $request );
 
 
 
455
 
456
  $request->set_param( 'context', 'edit' );
457
  $response = $this->prepare_item_for_response( $comment, $request );
@@ -605,28 +615,28 @@ class WP_REST_Comments_Controller extends WP_REST_Controller {
605
  protected function prepare_links( $comment ) {
606
  $links = array(
607
  'self' => array(
608
- 'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $comment->comment_ID ) ),
609
  ),
610
  'collection' => array(
611
- 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ),
612
  ),
613
  );
614
 
615
  if ( 0 !== (int) $comment->user_id ) {
616
  $links['author'] = array(
617
- 'href' => rest_url( '/wp/v2/users/' . $comment->user_id ),
618
  'embeddable' => true,
619
  );
620
  }
621
 
622
  if ( 0 !== (int) $comment->comment_post_ID ) {
623
- $post = get_post( $comment->comment_post_ID );
624
  if ( ! empty( $post->ID ) ) {
625
  $obj = get_post_type_object( $post->post_type );
626
  $base = ! empty( $obj->rest_base ) ? $obj->rest_base : $obj->name;
627
 
628
  $links['up'] = array(
629
- 'href' => rest_url( '/wp/v2/' . $base . '/' . $comment->comment_post_ID ),
630
  'embeddable' => true,
631
  'post_type' => $post->post_type,
632
  );
@@ -635,11 +645,22 @@ class WP_REST_Comments_Controller extends WP_REST_Controller {
635
 
636
  if ( 0 !== (int) $comment->comment_parent ) {
637
  $links['in-reply-to'] = array(
638
- 'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $comment->comment_parent ) ),
639
  'embeddable' => true,
640
  );
641
  }
642
 
 
 
 
 
 
 
 
 
 
 
 
643
  return $links;
644
  }
645
 
@@ -739,6 +760,10 @@ class WP_REST_Comments_Controller extends WP_REST_Controller {
739
  $prepared_comment['comment_author_url'] = $request['author_url'];
740
  }
741
 
 
 
 
 
742
  if ( isset( $request['type'] ) ) {
743
  $prepared_comment['comment_type'] = $request['type'];
744
  }
@@ -795,8 +820,11 @@ class WP_REST_Comments_Controller extends WP_REST_Controller {
795
  'author_ip' => array(
796
  'description' => __( 'IP address for the object author.' ),
797
  'type' => 'string',
 
798
  'context' => array( 'edit' ),
799
- 'readonly' => true,
 
 
800
  ),
801
  'author_name' => array(
802
  'description' => __( 'Display name for the object author.' ),
@@ -999,7 +1027,7 @@ class WP_REST_Comments_Controller extends WP_REST_Controller {
999
  'type' => 'string',
1000
  'sanitize_callback' => 'sanitize_key',
1001
  'validate_callback' => 'rest_validate_request_arg',
1002
- 'default' => 'asc',
1003
  'enum' => array(
1004
  'asc',
1005
  'desc',
@@ -1124,9 +1152,13 @@ class WP_REST_Comments_Controller extends WP_REST_Controller {
1124
  * @return boolean Can we read it?
1125
  */
1126
  protected function check_read_permission( $comment ) {
1127
-
1128
- if ( 1 === (int) $comment->comment_approved ) {
1129
- return true;
 
 
 
 
1130
  }
1131
 
1132
  if ( 0 === get_current_user_id() ) {
@@ -1137,13 +1169,6 @@ class WP_REST_Comments_Controller extends WP_REST_Controller {
1137
  return false;
1138
  }
1139
 
1140
- $post = get_post( $comment->comment_post_ID );
1141
- if ( $comment->comment_post_ID && $post ) {
1142
- if ( ! $this->check_read_post_permission( $post ) ) {
1143
- return false;
1144
- }
1145
- }
1146
-
1147
  if ( ! empty( $comment->user_id ) && get_current_user_id() === (int) $comment->user_id ) {
1148
  return true;
1149
  }
71
 
72
  if ( ! empty( $request['post'] ) ) {
73
  foreach ( (array) $request['post'] as $post_id ) {
74
+ $post = $this->get_post( $post_id );
75
  if ( ! empty( $post_id ) && $post && ! $this->check_read_post_permission( $post ) ) {
76
  return new WP_Error( 'rest_cannot_read_post', __( 'Sorry, you cannot read the post for this comment.' ), array( 'status' => rest_authorization_required_code() ) );
77
  } else if ( 0 === $post_id && ! current_user_can( 'moderate_comments' ) ) {
193
  $response->header( 'X-WP-Total', $total_comments );
194
  $response->header( 'X-WP-TotalPages', $max_pages );
195
 
196
+ $base = add_query_arg( $request->get_query_params(), rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ) );
197
  if ( $request['page'] > 1 ) {
198
  $prev_page = $request['page'] - 1;
199
  if ( $prev_page > $max_pages ) {
230
  return new WP_Error( 'rest_cannot_read', __( 'Sorry, you cannot read this comment.' ), array( 'status' => rest_authorization_required_code() ) );
231
  }
232
 
233
+ $post = $this->get_post( $comment->comment_post_ID );
234
 
235
  if ( $post && ! $this->check_read_post_permission( $post ) ) {
236
  return new WP_Error( 'rest_cannot_read_post', __( 'Sorry, you cannot read the post for this comment.' ), array( 'status' => rest_authorization_required_code() ) );
258
  }
259
 
260
  if ( ! empty( $comment->comment_post_ID ) ) {
261
+ $post = $this->get_post( $comment->comment_post_ID );
262
  if ( empty( $post ) ) {
263
  return new WP_Error( 'rest_post_invalid_id', __( 'Invalid post id.' ), array( 'status' => 404 ) );
264
  }
293
  return new WP_Error( 'rest_comment_invalid_status', __( 'Sorry, you cannot set status for comments.' ), array( 'status' => rest_authorization_required_code() ) );
294
  }
295
 
296
+ if ( empty( $request['post'] ) && ! current_user_can( 'moderate_comments' ) ) {
297
+ return new WP_Error( 'rest_comment_invalid_post_id', __( 'Sorry, you cannot create this comment without a post' ), array( 'status' => rest_authorization_required_code() ) );
298
+ }
299
+
300
+ if ( ! empty( $request['post'] ) && $post = $this->get_post( (int) $request['post'] ) ) {
301
 
302
  if ( ! $this->check_read_post_permission( $post ) ) {
303
  return new WP_Error( 'rest_cannot_read_post', __( 'Sorry, you cannot read the post for this comment.' ), array( 'status' => rest_authorization_required_code() ) );
350
  if ( ! isset( $prepared_comment['comment_author_url'] ) ) {
351
  $prepared_comment['comment_author_url'] = '';
352
  }
353
+
354
  $prepared_comment['comment_agent'] = '';
355
  $prepared_comment['comment_approved'] = wp_allow_comment( $prepared_comment );
356
 
375
  }
376
 
377
  $comment = get_comment( $comment_id );
378
+ $fields_update = $this->update_additional_fields_for_object( $comment, $request );
379
+ if ( is_wp_error( $fields_update ) ) {
380
+ return $fields_update;
381
+ }
382
 
383
  $context = current_user_can( 'moderate_comments' ) ? 'edit' : 'view';
384
  $request->set_param( 'context', $context );
385
  $response = $this->prepare_item_for_response( $comment, $request );
386
  $response = rest_ensure_response( $response );
387
  $response->set_status( 201 );
388
+ $response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $comment_id ) ) );
389
 
390
  /**
391
  * Fires after a comment is created or updated via the REST API.
458
  }
459
 
460
  $comment = get_comment( $id );
461
+ $fields_update = $this->update_additional_fields_for_object( $comment, $request );
462
+ if ( is_wp_error( $fields_update ) ) {
463
+ return $fields_update;
464
+ }
465
 
466
  $request->set_param( 'context', 'edit' );
467
  $response = $this->prepare_item_for_response( $comment, $request );
615
  protected function prepare_links( $comment ) {
616
  $links = array(
617
  'self' => array(
618
+ 'href' => rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $comment->comment_ID ) ),
619
  ),
620
  'collection' => array(
621
+ 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ),
622
  ),
623
  );
624
 
625
  if ( 0 !== (int) $comment->user_id ) {
626
  $links['author'] = array(
627
+ 'href' => rest_url( 'wp/v2/users/' . $comment->user_id ),
628
  'embeddable' => true,
629
  );
630
  }
631
 
632
  if ( 0 !== (int) $comment->comment_post_ID ) {
633
+ $post = $this->get_post( $comment->comment_post_ID );
634
  if ( ! empty( $post->ID ) ) {
635
  $obj = get_post_type_object( $post->post_type );
636
  $base = ! empty( $obj->rest_base ) ? $obj->rest_base : $obj->name;
637
 
638
  $links['up'] = array(
639
+ 'href' => rest_url( 'wp/v2/' . $base . '/' . $comment->comment_post_ID ),
640
  'embeddable' => true,
641
  'post_type' => $post->post_type,
642
  );
645
 
646
  if ( 0 !== (int) $comment->comment_parent ) {
647
  $links['in-reply-to'] = array(
648
+ 'href' => rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $comment->comment_parent ) ),
649
  'embeddable' => true,
650
  );
651
  }
652
 
653
+ // Only grab one comment to verify the comment has children.
654
+ $comment_children = $comment->get_children( array( 'number' => 1, 'count' => true ) );
655
+ if ( ! empty( $comment_children ) ) {
656
+ $args = array( 'parent' => $comment->comment_ID );
657
+ $rest_url = add_query_arg( $args, rest_url( $this->namespace . '/' . $this->rest_base ) );
658
+
659
+ $links['children'] = array(
660
+ 'href' => $rest_url,
661
+ );
662
+ }
663
+
664
  return $links;
665
  }
666
 
760
  $prepared_comment['comment_author_url'] = $request['author_url'];
761
  }
762
 
763
+ if ( isset( $request['author_ip'] ) ) {
764
+ $prepared_comment['comment_author_IP'] = $request['author_ip'];
765
+ }
766
+
767
  if ( isset( $request['type'] ) ) {
768
  $prepared_comment['comment_type'] = $request['type'];
769
  }
820
  'author_ip' => array(
821
  'description' => __( 'IP address for the object author.' ),
822
  'type' => 'string',
823
+ 'format' => 'ipv4',
824
  'context' => array( 'edit' ),
825
+ 'arg_options' => array(
826
+ 'default' => '127.0.0.1',
827
+ ),
828
  ),
829
  'author_name' => array(
830
  'description' => __( 'Display name for the object author.' ),
1027
  'type' => 'string',
1028
  'sanitize_callback' => 'sanitize_key',
1029
  'validate_callback' => 'rest_validate_request_arg',
1030
+ 'default' => 'desc',
1031
  'enum' => array(
1032
  'asc',
1033
  'desc',
1152
  * @return boolean Can we read it?
1153
  */
1154
  protected function check_read_permission( $comment ) {
1155
+ if ( ! empty( $comment->comment_post_ID ) ) {
1156
+ $post = get_post( $comment->comment_post_ID );
1157
+ if ( $post ) {
1158
+ if ( $this->check_read_post_permission( $post ) && 1 === (int) $comment->comment_approved ) {
1159
+ return true;
1160
+ }
1161
+ }
1162
  }
1163
 
1164
  if ( 0 === get_current_user_id() ) {
1169
  return false;
1170
  }
1171
 
 
 
 
 
 
 
 
1172
  if ( ! empty( $comment->user_id ) && get_current_user_id() === (int) $comment->user_id ) {
1173
  return true;
1174
  }
lib/endpoints/class-wp-rest-controller.php CHANGED
@@ -189,6 +189,7 @@ abstract class WP_REST_Controller {
189
 
190
  if ( ! in_array( $context, $schema['properties'][ $key ]['context'] ) ) {
191
  unset( $data[ $key ] );
 
192
  }
193
 
194
  if ( 'object' === $schema['properties'][ $key ]['type'] && ! empty( $schema['properties'][ $key ]['properties'] ) ) {
@@ -289,7 +290,7 @@ abstract class WP_REST_Controller {
289
  return array_merge( $param_details, $args );
290
  }
291
  $contexts = array();
292
- foreach ( $schema['properties'] as $key => $attributes ) {
293
  if ( ! empty( $attributes['context'] ) ) {
294
  $contexts = array_merge( $contexts, $attributes['context'] );
295
  }
@@ -329,13 +330,12 @@ abstract class WP_REST_Controller {
329
  *
330
  * @param array $object
331
  * @param WP_REST_Request $request
 
332
  */
333
  protected function update_additional_fields_for_object( $object, $request ) {
334
-
335
  $additional_fields = $this->get_additional_fields();
336
 
337
  foreach ( $additional_fields as $field_name => $field_options ) {
338
-
339
  if ( ! $field_options['update_callback'] ) {
340
  continue;
341
  }
@@ -345,8 +345,13 @@ abstract class WP_REST_Controller {
345
  continue;
346
  }
347
 
348
- call_user_func( $field_options['update_callback'], $request[ $field_name ], $object, $field_name, $request, $this->get_object_type() );
 
 
 
349
  }
 
 
350
  }
351
 
352
  /**
@@ -480,4 +485,50 @@ abstract class WP_REST_Controller {
480
  return $endpoint_args;
481
  }
482
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
483
  }
189
 
190
  if ( ! in_array( $context, $schema['properties'][ $key ]['context'] ) ) {
191
  unset( $data[ $key ] );
192
+ continue;
193
  }
194
 
195
  if ( 'object' === $schema['properties'][ $key ]['type'] && ! empty( $schema['properties'][ $key ]['properties'] ) ) {
290
  return array_merge( $param_details, $args );
291
  }
292
  $contexts = array();
293
+ foreach ( $schema['properties'] as $attributes ) {
294
  if ( ! empty( $attributes['context'] ) ) {
295
  $contexts = array_merge( $contexts, $attributes['context'] );
296
  }
330
  *
331
  * @param array $object
332
  * @param WP_REST_Request $request
333
+ * @return bool|WP_Error True on success, WP_Error object if a field cannot be updated.
334
  */
335
  protected function update_additional_fields_for_object( $object, $request ) {
 
336
  $additional_fields = $this->get_additional_fields();
337
 
338
  foreach ( $additional_fields as $field_name => $field_options ) {
 
339
  if ( ! $field_options['update_callback'] ) {
340
  continue;
341
  }
345
  continue;
346
  }
347
 
348
+ $result = call_user_func( $field_options['update_callback'], $request[ $field_name ], $object, $field_name, $request, $this->get_object_type() );
349
+ if ( is_wp_error( $result ) ) {
350
+ return $result;
351
+ }
352
  }
353
+
354
+ return true;
355
  }
356
 
357
  /**
485
  return $endpoint_args;
486
  }
487
 
488
+ /**
489
+ * Retrieves post data given a post ID or post object.
490
+ *
491
+ * This is a subset of the functionality of the `get_post()` function, with
492
+ * the additional functionality of having `the_post` action done on the
493
+ * resultant post object. This is done so that plugins may manipulate the
494
+ * post that is used in the REST API.
495
+ *
496
+ * @see get_post()
497
+ * @global WP_Query $wp_query
498
+ *
499
+ * @param int|WP_Post $post Post ID or post object. Defaults to global $post.
500
+ * @return WP_Post|null A `WP_Post` object when successful.
501
+ */
502
+ public function get_post( $post ) {
503
+ $post_obj = get_post( $post );
504
+
505
+ /**
506
+ * Filter the post.
507
+ *
508
+ * Allows plugins to filter the post object as returned by `\WP_REST_Controller::get_post()`.
509
+ *
510
+ * @param WP_Post|null $post_obj The post object as returned by `get_post()`.
511
+ * @param int|WP_Post $post The original value used to obtain the post object.
512
+ */
513
+ $post = apply_filters( 'rest_the_post', $post_obj, $post );
514
+
515
+ return $post;
516
+ }
517
+
518
+ /**
519
+ * Sanitize the slug value.
520
+ *
521
+ * @internal We can't use {@see sanitize_title} directly, as the second
522
+ * parameter is the fallback title, which would end up being set to the
523
+ * request object.
524
+ * @see https://github.com/WP-API/WP-API/issues/1585
525
+ *
526
+ * @todo Remove this in favour of https://core.trac.wordpress.org/ticket/34659
527
+ *
528
+ * @param string $slug Slug value passed in request.
529
+ * @return string Sanitized value for the slug.
530
+ */
531
+ public function sanitize_slug( $slug ) {
532
+ return sanitize_title( $slug );
533
+ }
534
  }
lib/endpoints/class-wp-rest-post-statuses-controller.php CHANGED
@@ -155,9 +155,9 @@ class WP_REST_Post_Statuses_Controller extends WP_REST_Controller {
155
  $response = rest_ensure_response( $data );
156
 
157
  if ( 'publish' === $status->name ) {
158
- $response->add_link( 'archives', rest_url( '/wp/v2/posts' ) );
159
  } else {
160
- $response->add_link( 'archives', add_query_arg( 'status', $status->name, rest_url( '/wp/v2/posts' ) ) );
161
  }
162
 
163
  /**
155
  $response = rest_ensure_response( $data );
156
 
157
  if ( 'publish' === $status->name ) {
158
+ $response->add_link( 'archives', rest_url( 'wp/v2/posts' ) );
159
  } else {
160
+ $response->add_link( 'archives', add_query_arg( 'status', $status->name, rest_url( 'wp/v2/posts' ) ) );
161
  }
162
 
163
  /**
lib/endpoints/class-wp-rest-posts-controller.php CHANGED
@@ -37,7 +37,10 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
37
  'callback' => array( $this, 'get_item' ),
38
  'permission_callback' => array( $this, 'get_item_permissions_check' ),
39
  'args' => array(
40
- 'context' => $this->get_context_param( array( 'default' => 'view' ) ),
 
 
 
41
  ),
42
  ),
43
  array(
@@ -85,6 +88,12 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
85
  * @return WP_Error|WP_REST_Response
86
  */
87
  public function get_items( $request ) {
 
 
 
 
 
 
88
  $args = array();
89
  $args['author__in'] = $request['author'];
90
  $args['author__not_in'] = $request['author_exclude'];
@@ -95,7 +104,6 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
95
  $args['paged'] = $request['page'];
96
  $args['post__in'] = $request['include'];
97
  $args['post__not_in'] = $request['exclude'];
98
- $args['posts_per_page'] = $request['per_page'];
99
  $args['name'] = $request['slug'];
100
  $args['post_parent__in'] = $request['parent'];
101
  $args['post_parent__not_in'] = $request['parent_exclude'];
@@ -118,6 +126,31 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
118
  unset( $args['filter'] );
119
  }
120
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
  // Force the post_type argument, since it's not a user input variable.
122
  $args['post_type'] = $this->post_type;
123
 
@@ -152,6 +185,11 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
152
  $posts_query = new WP_Query();
153
  $query_result = $posts_query->query( $query_args );
154
 
 
 
 
 
 
155
  $posts = array();
156
  foreach ( $query_result as $post ) {
157
  if ( ! $this->check_read_permission( $post ) ) {
@@ -162,6 +200,11 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
162
  $posts[] = $this->prepare_response_for_collection( $data );
163
  }
164
 
 
 
 
 
 
165
  $page = (int) $query_args['paged'];
166
  $total_posts = $posts_query->found_posts;
167
 
@@ -185,7 +228,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
185
  unset( $request_params['filter']['posts_per_page'] );
186
  unset( $request_params['filter']['paged'] );
187
  }
188
- $base = add_query_arg( $request_params, rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ) );
189
 
190
  if ( $page > 1 ) {
191
  $prev_page = $page - 1;
@@ -212,12 +255,24 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
212
  */
213
  public function get_item_permissions_check( $request ) {
214
 
215
- $post = get_post( (int) $request['id'] );
216
 
217
  if ( 'edit' === $request['context'] && $post && ! $this->check_update_permission( $post ) ) {
218
  return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to edit this post' ), array( 'status' => rest_authorization_required_code() ) );
219
  }
220
 
 
 
 
 
 
 
 
 
 
 
 
 
221
  if ( $post ) {
222
  return $this->check_read_permission( $post );
223
  }
@@ -225,6 +280,36 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
225
  return true;
226
  }
227
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
228
  /**
229
  * Get a single post.
230
  *
@@ -233,7 +318,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
233
  */
234
  public function get_item( $request ) {
235
  $id = (int) $request['id'];
236
- $post = get_post( $id );
237
 
238
  if ( empty( $id ) || empty( $post->ID ) || $this->post_type !== $post->post_type ) {
239
  return new WP_Error( 'rest_post_invalid_id', __( 'Invalid post id.' ), array( 'status' => 404 ) );
@@ -259,10 +344,6 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
259
 
260
  $post_type = get_post_type_object( $this->post_type );
261
 
262
- if ( ! empty( $request['password'] ) && ! current_user_can( $post_type->cap->publish_posts ) ) {
263
- return new WP_Error( 'rest_cannot_publish', __( 'Sorry, you are not allowed to create password protected posts in this post type' ), array( 'status' => rest_authorization_required_code() ) );
264
- }
265
-
266
  if ( ! empty( $request['author'] ) && get_current_user_id() !== $request['author'] && ! current_user_can( $post_type->cap->edit_others_posts ) ) {
267
  return new WP_Error( 'rest_cannot_edit_others', __( 'You are not allowed to create posts as this user.' ), array( 'status' => rest_authorization_required_code() ) );
268
  }
@@ -333,8 +414,11 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
333
  return $terms_update;
334
  }
335
 
336
- $post = get_post( $post_id );
337
- $this->update_additional_fields_for_object( $post, $request );
 
 
 
338
 
339
  /**
340
  * Fires after a single post is created or updated via the REST API.
@@ -349,7 +433,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
349
  $response = $this->prepare_item_for_response( $post, $request );
350
  $response = rest_ensure_response( $response );
351
  $response->set_status( 201 );
352
- $response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $post_id ) ) );
353
 
354
  return $response;
355
  }
@@ -362,17 +446,13 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
362
  */
363
  public function update_item_permissions_check( $request ) {
364
 
365
- $post = get_post( $request['id'] );
366
  $post_type = get_post_type_object( $this->post_type );
367
 
368
  if ( $post && ! $this->check_update_permission( $post ) ) {
369
  return new WP_Error( 'rest_cannot_edit', __( 'Sorry, you are not allowed to update this post.' ), array( 'status' => rest_authorization_required_code() ) );;
370
  }
371
 
372
- if ( ! empty( $request['password'] ) && ! current_user_can( $post_type->cap->publish_posts ) ) {
373
- return new WP_Error( 'rest_cannot_publish', __( 'Sorry, you are not allowed to create password protected posts in this post type' ), array( 'status' => rest_authorization_required_code() ) );
374
- }
375
-
376
  if ( ! empty( $request['author'] ) && get_current_user_id() !== $request['author'] && ! current_user_can( $post_type->cap->edit_others_posts ) ) {
377
  return new WP_Error( 'rest_cannot_edit_others', __( 'You are not allowed to update posts as this user.' ), array( 'status' => rest_authorization_required_code() ) );
378
  }
@@ -392,10 +472,10 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
392
  */
393
  public function update_item( $request ) {
394
  $id = (int) $request['id'];
395
- $post = get_post( $id );
396
 
397
  if ( empty( $id ) || empty( $post->ID ) || $this->post_type !== $post->post_type ) {
398
- return new WP_Error( 'rest_post_invalid_id', __( 'Post id is invalid.' ), array( 'status' => 400 ) );
399
  }
400
 
401
  $post = $this->prepare_item_for_database( $request );
@@ -440,8 +520,11 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
440
  return $terms_update;
441
  }
442
 
443
- $post = get_post( $post_id );
444
- $this->update_additional_fields_for_object( $post, $request );
 
 
 
445
 
446
  /* This action is documented in lib/endpoints/class-wp-rest-controller.php */
447
  do_action( "rest_insert_{$this->post_type}", $post, $request, false );
@@ -459,7 +542,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
459
  */
460
  public function delete_item_permissions_check( $request ) {
461
 
462
- $post = get_post( $request['id'] );
463
 
464
  if ( $post && ! $this->check_delete_permission( $post ) ) {
465
  return new WP_Error( 'rest_cannot_delete', __( 'Sorry, you are not allowed to delete posts.' ), array( 'status' => rest_authorization_required_code() ) );
@@ -478,7 +561,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
478
  $id = (int) $request['id'];
479
  $force = (bool) $request['force'];
480
 
481
- $post = get_post( $id );
482
 
483
  if ( empty( $id ) || empty( $post->ID ) || $this->post_type !== $post->post_type ) {
484
  return new WP_Error( 'rest_post_invalid_id', __( 'Invalid post id.' ), array( 'status' => 404 ) );
@@ -648,27 +731,6 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
648
  return $valid_vars;
649
  }
650
 
651
- /**
652
- * Check the post excerpt and prepare it for single post output.
653
- *
654
- * @param string $excerpt
655
- * @return string|null $excerpt
656
- */
657
- protected function prepare_excerpt_response( $excerpt ) {
658
- if ( post_password_required() ) {
659
- return __( 'There is no excerpt because this is a protected post.' );
660
- }
661
-
662
- /** This filter is documented in wp-includes/post-template.php */
663
- $excerpt = apply_filters( 'the_excerpt', apply_filters( 'get_the_excerpt', $excerpt ) );
664
-
665
- if ( empty( $excerpt ) ) {
666
- return '';
667
- }
668
-
669
- return $excerpt;
670
- }
671
-
672
  /**
673
  * Check the post_date_gmt or modified_gmt and prepare any post or
674
  * modified date for single post output.
@@ -692,21 +754,6 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
692
  return mysql_to_rfc3339( $date_gmt );
693
  }
694
 
695
- protected function prepare_password_response( $password ) {
696
- if ( ! empty( $password ) ) {
697
- /**
698
- * Fake the correct cookie to fool post_password_required().
699
- * Without this, get_the_content() will give a password form.
700
- */
701
- require_once ABSPATH . 'wp-includes/class-phpass.php';
702
- $hasher = new PasswordHash( 8, true );
703
- $value = $hasher->HashPassword( $password );
704
- $_COOKIE[ 'wp-postpass_' . COOKIEHASH ] = wp_slash( $value );
705
- }
706
-
707
- return $password;
708
- }
709
-
710
  /**
711
  * Prepare a single post for create or update.
712
  *
@@ -761,7 +808,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
761
  $post_type = get_post_type_object( $prepared_post->post_type );
762
 
763
  // Post status.
764
- if ( isset( $request['status'] ) ) {
765
  $status = $this->handle_status_param( $request['status'], $post_type );
766
  if ( is_wp_error( $status ) ) {
767
  return $status;
@@ -771,13 +818,13 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
771
  }
772
 
773
  // Post date.
774
- if ( ! empty( $request['date'] ) ) {
775
  $date_data = rest_get_date_with_gmt( $request['date'] );
776
 
777
  if ( ! empty( $date_data ) ) {
778
  list( $prepared_post->post_date, $prepared_post->post_date_gmt ) = $date_data;
779
  }
780
- } elseif ( ! empty( $request['date_gmt'] ) ) {
781
  $date_data = rest_get_date_with_gmt( $request['date_gmt'], true );
782
 
783
  if ( ! empty( $date_data ) ) {
@@ -785,7 +832,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
785
  }
786
  }
787
  // Post slug.
788
- if ( isset( $request['slug'] ) ) {
789
  $prepared_post->post_name = $request['slug'];
790
  }
791
 
@@ -802,7 +849,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
802
  }
803
 
804
  // Post password.
805
- if ( isset( $request['password'] ) && '' !== $request['password'] ) {
806
  $prepared_post->post_password = $request['password'];
807
 
808
  if ( ! empty( $schema['properties']['sticky'] ) && ! empty( $request['sticky'] ) ) {
@@ -814,7 +861,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
814
  }
815
  }
816
 
817
- if ( ! empty( $request['sticky'] ) ) {
818
  if ( ! empty( $prepared_post->ID ) && post_password_required( $prepared_post->ID ) ) {
819
  return new WP_Error( 'rest_invalid_field', __( 'A password protected post can not be set to sticky.' ), array( 'status' => 400 ) );
820
  }
@@ -822,7 +869,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
822
 
823
  // Parent.
824
  if ( ! empty( $schema['properties']['parent'] ) && ! empty( $request['parent'] ) ) {
825
- $parent = get_post( (int) $request['parent'] );
826
  if ( empty( $parent ) ) {
827
  return new WP_Error( 'rest_post_invalid_id', __( 'Invalid post parent id.' ), array( 'status' => 400 ) );
828
  }
@@ -897,6 +944,8 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
897
  *
898
  * @param int $featured_media
899
  * @param int $post_id
 
 
900
  */
901
  protected function handle_featured_media( $featured_media, $post_id ) {
902
 
@@ -921,7 +970,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
921
  * @param integer $post_id
922
  */
923
  public function handle_template( $template, $post_id ) {
924
- if ( in_array( $template, array_keys( wp_get_theme()->get_page_templates( get_post( $post_id ) ) ) ) ) {
925
  update_post_meta( $post_id, '_wp_page_template', $template );
926
  } else {
927
  update_post_meta( $post_id, '_wp_page_template', '' );
@@ -978,10 +1027,6 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
978
  * @return boolean Can we read it?
979
  */
980
  public function check_read_permission( $post ) {
981
- if ( ! empty( $post->post_password ) && ! $this->check_update_permission( $post ) ) {
982
- return false;
983
- }
984
-
985
  $post_type = get_post_type_object( $post->post_type );
986
  if ( ! $this->check_is_post_type_allowed( $post_type ) ) {
987
  return false;
@@ -999,7 +1044,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
999
 
1000
  // Can we read the parent if we're inheriting?
1001
  if ( 'inherit' === $post->post_status && $post->post_parent > 0 ) {
1002
- $parent = get_post( $post->post_parent );
1003
  return $this->check_read_permission( $parent );
1004
  }
1005
 
@@ -1071,59 +1116,99 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
1071
  $GLOBALS['post'] = $post;
1072
  setup_postdata( $post );
1073
 
 
 
1074
  // Base fields for every post.
1075
- $data = array(
1076
- 'id' => $post->ID,
1077
- 'date' => $this->prepare_date_response( $post->post_date_gmt, $post->post_date ),
1078
- 'date_gmt' => $this->prepare_date_response( $post->post_date_gmt ),
1079
- 'guid' => array(
 
 
 
 
 
 
 
 
 
 
 
1080
  /** This filter is documented in wp-includes/post-template.php */
1081
  'rendered' => apply_filters( 'get_the_guid', $post->guid ),
1082
  'raw' => $post->guid,
1083
- ),
1084
- 'modified' => $this->prepare_date_response( $post->post_modified_gmt, $post->post_modified ),
1085
- 'modified_gmt' => $this->prepare_date_response( $post->post_modified_gmt ),
1086
- 'password' => $post->post_password,
1087
- 'slug' => $post->post_name,
1088
- 'status' => $post->post_status,
1089
- 'type' => $post->post_type,
1090
- 'link' => get_permalink( $post->ID ),
1091
- );
1092
 
1093
- $schema = $this->get_item_schema();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1094
 
1095
  if ( ! empty( $schema['properties']['title'] ) ) {
 
1096
  $data['title'] = array(
1097
  'raw' => $post->post_title,
1098
  'rendered' => get_the_title( $post->ID ),
1099
  );
 
1100
  }
1101
 
1102
- if ( ! empty( $schema['properties']['content'] ) ) {
1103
-
1104
- if ( ! empty( $post->post_password ) ) {
1105
- $this->prepare_password_response( $post->post_password );
1106
- }
 
1107
 
 
1108
  $data['content'] = array(
1109
- 'raw' => $post->post_content,
1110
  /** This filter is documented in wp-includes/post-template.php */
1111
- 'rendered' => apply_filters( 'the_content', $post->post_content ),
 
1112
  );
1113
-
1114
- // Don't leave our cookie lying around: https://github.com/WP-API/WP-API/issues/1055.
1115
- if ( ! empty( $post->post_password ) ) {
1116
- $_COOKIE[ 'wp-postpass_' . COOKIEHASH ] = '';
1117
- }
1118
  }
1119
 
1120
  if ( ! empty( $schema['properties']['excerpt'] ) ) {
 
 
1121
  $data['excerpt'] = array(
1122
- 'raw' => $post->post_excerpt,
1123
- 'rendered' => $this->prepare_excerpt_response( $post->post_excerpt ),
 
1124
  );
1125
  }
1126
 
 
 
 
 
 
1127
  if ( ! empty( $schema['properties']['author'] ) ) {
1128
  $data['author'] = (int) $post->post_author;
1129
  }
@@ -1171,8 +1256,10 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
1171
  $taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) );
1172
  foreach ( $taxonomies as $taxonomy ) {
1173
  $base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name;
1174
- $terms = get_the_terms( $post, $taxonomy->name );
1175
- $data[ $base ] = $terms ? wp_list_pluck( $terms, 'term_id' ) : array();
 
 
1176
  }
1177
 
1178
  $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
@@ -1197,6 +1284,20 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
1197
  return apply_filters( "rest_prepare_{$this->post_type}", $response, $post, $request );
1198
  }
1199
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1200
  /**
1201
  * Prepare links for the request.
1202
  *
@@ -1204,7 +1305,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
1204
  * @return array Links for the given post.
1205
  */
1206
  protected function prepare_links( $post ) {
1207
- $base = sprintf( '/%s/%s', $this->namespace, $this->rest_base );
1208
 
1209
  // Entity meta
1210
  $links = array(
@@ -1215,20 +1316,20 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
1215
  'href' => rest_url( $base ),
1216
  ),
1217
  'about' => array(
1218
- 'href' => rest_url( '/wp/v2/types/' . $this->post_type ),
1219
  ),
1220
  );
1221
 
1222
  if ( ( in_array( $post->post_type, array( 'post', 'page' ) ) || post_type_supports( $post->post_type, 'author' ) )
1223
  && ! empty( $post->post_author ) ) {
1224
  $links['author'] = array(
1225
- 'href' => rest_url( '/wp/v2/users/' . $post->post_author ),
1226
  'embeddable' => true,
1227
  );
1228
  };
1229
 
1230
  if ( in_array( $post->post_type, array( 'post', 'page' ) ) || post_type_supports( $post->post_type, 'comments' ) ) {
1231
- $replies_url = rest_url( '/wp/v2/comments' );
1232
  $replies_url = add_query_arg( 'post', $post->ID, $replies_url );
1233
  $links['replies'] = array(
1234
  'href' => $replies_url,
@@ -1331,11 +1432,13 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
1331
  'description' => __( 'GUID for the object, as it exists in the database.' ),
1332
  'type' => 'string',
1333
  'context' => array( 'edit' ),
 
1334
  ),
1335
  'rendered' => array(
1336
  'description' => __( 'GUID for the object, transformed for display.' ),
1337
  'type' => 'string',
1338
  'context' => array( 'view', 'edit' ),
 
1339
  ),
1340
  ),
1341
  ),
@@ -1366,17 +1469,12 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
1366
  'context' => array( 'view', 'edit' ),
1367
  'readonly' => true,
1368
  ),
1369
- 'password' => array(
1370
- 'description' => __( 'A password to protect access to the post.' ),
1371
- 'type' => 'string',
1372
- 'context' => array( 'edit' ),
1373
- ),
1374
  'slug' => array(
1375
  'description' => __( 'An alphanumeric identifier for the object unique to its type.' ),
1376
  'type' => 'string',
1377
  'context' => array( 'view', 'edit', 'embed' ),
1378
  'arg_options' => array(
1379
- 'sanitize_callback' => 'sanitize_title',
1380
  ),
1381
  ),
1382
  'status' => array(
@@ -1466,6 +1564,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
1466
  'description' => __( 'HTML title for the object, transformed for display.' ),
1467
  'type' => 'string',
1468
  'context' => array( 'view', 'edit', 'embed' ),
 
1469
  ),
1470
  ),
1471
  );
@@ -1486,6 +1585,13 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
1486
  'description' => __( 'HTML content for the object, transformed for display.' ),
1487
  'type' => 'string',
1488
  'context' => array( 'view', 'edit' ),
 
 
 
 
 
 
 
1489
  ),
1490
  ),
1491
  );
@@ -1514,6 +1620,13 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
1514
  'description' => __( 'HTML excerpt for the object, transformed for display.' ),
1515
  'type' => 'string',
1516
  'context' => array( 'view', 'edit', 'embed' ),
 
 
 
 
 
 
 
1517
  ),
1518
  ),
1519
  );
@@ -1568,6 +1681,12 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
1568
  'type' => 'boolean',
1569
  'context' => array( 'view', 'edit' ),
1570
  );
 
 
 
 
 
 
1571
  }
1572
 
1573
  if ( 'page' === $this->post_type ) {
@@ -1669,6 +1788,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
1669
  'default' => 'date',
1670
  'enum' => array(
1671
  'date',
 
1672
  'id',
1673
  'include',
1674
  'title',
@@ -1703,7 +1823,8 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
1703
  );
1704
  $params['status'] = array(
1705
  'default' => 'publish',
1706
- 'description' => __( 'Limit result set to posts assigned a specific status.' ),
 
1707
  'sanitize_callback' => 'sanitize_key',
1708
  'type' => 'string',
1709
  'validate_callback' => array( $this, 'validate_user_can_query_private_statuses' ),
@@ -1723,6 +1844,15 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
1723
  'default' => array(),
1724
  );
1725
  }
 
 
 
 
 
 
 
 
 
1726
  return $params;
1727
  }
1728
 
@@ -1744,5 +1874,4 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
1744
  }
1745
  return new WP_Error( 'rest_forbidden_status', __( 'Status is forbidden' ), array( 'status' => rest_authorization_required_code() ) );
1746
  }
1747
-
1748
  }
37
  'callback' => array( $this, 'get_item' ),
38
  'permission_callback' => array( $this, 'get_item_permissions_check' ),
39
  'args' => array(
40
+ 'context' => $this->get_context_param( array( 'default' => 'view' ) ),
41
+ 'password' => array(
42
+ 'description' => __( 'The password for the post if it is password protected.' ),
43
+ ),
44
  ),
45
  ),
46
  array(
88
  * @return WP_Error|WP_REST_Response
89
  */
90
  public function get_items( $request ) {
91
+
92
+ //Make sure a search string is set in case the orderby is set to 'relevace'
93
+ if ( ! empty( $request['orderby'] ) && 'relevance' === $request['orderby'] && empty( $request['search'] ) && empty( $request['filter']['s'] ) ) {
94
+ return new WP_Error( 'rest_no_search_term_defined', __( 'You need to define a search term to order by relevance.' ), array( 'status' => 400 ) );
95
+ }
96
+
97
  $args = array();
98
  $args['author__in'] = $request['author'];
99
  $args['author__not_in'] = $request['author_exclude'];
104
  $args['paged'] = $request['page'];
105
  $args['post__in'] = $request['include'];
106
  $args['post__not_in'] = $request['exclude'];
 
107
  $args['name'] = $request['slug'];
108
  $args['post_parent__in'] = $request['parent'];
109
  $args['post_parent__not_in'] = $request['parent_exclude'];
126
  unset( $args['filter'] );
127
  }
128
 
129
+ // Ensure our per_page parameter overrides filter.
130
+ $args['posts_per_page'] = $request['per_page'];
131
+
132
+ if ( isset( $request['sticky'] ) ) {
133
+ $sticky_posts = get_option( 'sticky_posts', array() );
134
+ if ( $sticky_posts && $request['sticky'] ) {
135
+ // As post__in will be used to only get sticky posts,
136
+ // we have to support the case where post__in was already
137
+ // specified.
138
+ $args['post__in'] = $args['post__in'] ? array_intersect( $sticky_posts, $args['post__in'] ) : $sticky_posts;
139
+
140
+ // If we intersected, but there are no post ids in common,
141
+ // WP_Query won't return "no posts" for `post__in = array()`
142
+ // so we have to fake it a bit.
143
+ if ( ! $args['post__in'] ) {
144
+ $args['post__in'] = array( -1 );
145
+ }
146
+ } elseif ( $sticky_posts ) {
147
+ // As post___not_in will be used to only get posts that
148
+ // are not sticky, we have to support the case where post__not_in
149
+ // was already specified.
150
+ $args['post__not_in'] = array_merge( $args['post__not_in'], $sticky_posts );
151
+ }
152
+ }
153
+
154
  // Force the post_type argument, since it's not a user input variable.
155
  $args['post_type'] = $this->post_type;
156
 
185
  $posts_query = new WP_Query();
186
  $query_result = $posts_query->query( $query_args );
187
 
188
+ // Allow access to all password protected posts if the context is edit.
189
+ if ( 'edit' === $request['context'] ) {
190
+ add_filter( 'post_password_required', '__return_false' );
191
+ }
192
+
193
  $posts = array();
194
  foreach ( $query_result as $post ) {
195
  if ( ! $this->check_read_permission( $post ) ) {
200
  $posts[] = $this->prepare_response_for_collection( $data );
201
  }
202
 
203
+ // Reset filter.
204
+ if ( 'edit' === $request['context'] ) {
205
+ remove_filter( 'post_password_required', '__return_false' );
206
+ }
207
+
208
  $page = (int) $query_args['paged'];
209
  $total_posts = $posts_query->found_posts;
210
 
228
  unset( $request_params['filter']['posts_per_page'] );
229
  unset( $request_params['filter']['paged'] );
230
  }
231
+ $base = add_query_arg( $request_params, rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ) );
232
 
233
  if ( $page > 1 ) {
234
  $prev_page = $page - 1;
255
  */
256
  public function get_item_permissions_check( $request ) {
257
 
258
+ $post = $this->get_post( (int) $request['id'] );
259
 
260
  if ( 'edit' === $request['context'] && $post && ! $this->check_update_permission( $post ) ) {
261
  return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to edit this post' ), array( 'status' => rest_authorization_required_code() ) );
262
  }
263
 
264
+ if ( $post && ! empty( $request['password'] ) ) {
265
+ // Check post password, and return error if invalid.
266
+ if ( ! hash_equals( $post->post_password, $request['password'] ) ) {
267
+ return new WP_Error( 'rest_post_incorrect_password', __( 'Incorrect post password.' ), array( 'status' => 403 ) );
268
+ }
269
+ }
270
+
271
+ // Allow access to all password protected posts if the context is edit.
272
+ if ( 'edit' === $request['context'] ) {
273
+ add_filter( 'post_password_required', '__return_false' );
274
+ }
275
+
276
  if ( $post ) {
277
  return $this->check_read_permission( $post );
278
  }
280
  return true;
281
  }
282
 
283
+ /**
284
+ * Can the user access passworded content?
285
+ *
286
+ * This method determines whether we need to override the regular password
287
+ * check in core with a filter.
288
+ *
289
+ * @param WP_Post $post Post to check against.
290
+ * @param WP_REST_Request $request Request data to check.
291
+ * @return bool True if the user can access passworded content, false otherwise.
292
+ */
293
+ protected function can_access_password_content( $post, $request ) {
294
+ if ( empty( $post->post_password ) ) {
295
+ // No filter required.
296
+ return false;
297
+ }
298
+
299
+ // Edit context always gets access to passworded posts.
300
+ if ( 'edit' === $request['context'] ) {
301
+ return true;
302
+ }
303
+
304
+ // No password, no auth.
305
+ if ( empty( $request['password'] ) ) {
306
+ return false;
307
+ }
308
+
309
+ // Double-check the request password.
310
+ return hash_equals( $post->post_password, $request['password'] );
311
+ }
312
+
313
  /**
314
  * Get a single post.
315
  *
318
  */
319
  public function get_item( $request ) {
320
  $id = (int) $request['id'];
321
+ $post = $this->get_post( $id );
322
 
323
  if ( empty( $id ) || empty( $post->ID ) || $this->post_type !== $post->post_type ) {
324
  return new WP_Error( 'rest_post_invalid_id', __( 'Invalid post id.' ), array( 'status' => 404 ) );
344
 
345
  $post_type = get_post_type_object( $this->post_type );
346
 
 
 
 
 
347
  if ( ! empty( $request['author'] ) && get_current_user_id() !== $request['author'] && ! current_user_can( $post_type->cap->edit_others_posts ) ) {
348
  return new WP_Error( 'rest_cannot_edit_others', __( 'You are not allowed to create posts as this user.' ), array( 'status' => rest_authorization_required_code() ) );
349
  }
414
  return $terms_update;
415
  }
416
 
417
+ $post = $this->get_post( $post_id );
418
+ $fields_update = $this->update_additional_fields_for_object( $post, $request );
419
+ if ( is_wp_error( $fields_update ) ) {
420
+ return $fields_update;
421
+ }
422
 
423
  /**
424
  * Fires after a single post is created or updated via the REST API.
433
  $response = $this->prepare_item_for_response( $post, $request );
434
  $response = rest_ensure_response( $response );
435
  $response->set_status( 201 );
436
+ $response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $post_id ) ) );
437
 
438
  return $response;
439
  }
446
  */
447
  public function update_item_permissions_check( $request ) {
448
 
449
+ $post = $this->get_post( $request['id'] );
450
  $post_type = get_post_type_object( $this->post_type );
451
 
452
  if ( $post && ! $this->check_update_permission( $post ) ) {
453
  return new WP_Error( 'rest_cannot_edit', __( 'Sorry, you are not allowed to update this post.' ), array( 'status' => rest_authorization_required_code() ) );;
454
  }
455
 
 
 
 
 
456
  if ( ! empty( $request['author'] ) && get_current_user_id() !== $request['author'] && ! current_user_can( $post_type->cap->edit_others_posts ) ) {
457
  return new WP_Error( 'rest_cannot_edit_others', __( 'You are not allowed to update posts as this user.' ), array( 'status' => rest_authorization_required_code() ) );
458
  }
472
  */
473
  public function update_item( $request ) {
474
  $id = (int) $request['id'];
475
+ $post = $this->get_post( $id );
476
 
477
  if ( empty( $id ) || empty( $post->ID ) || $this->post_type !== $post->post_type ) {
478
+ return new WP_Error( 'rest_post_invalid_id', __( 'Post id is invalid.' ), array( 'status' => 404 ) );
479
  }
480
 
481
  $post = $this->prepare_item_for_database( $request );
520
  return $terms_update;
521
  }
522
 
523
+ $post = $this->get_post( $post_id );
524
+ $fields_update = $this->update_additional_fields_for_object( $post, $request );
525
+ if ( is_wp_error( $fields_update ) ) {
526
+ return $fields_update;
527
+ }
528
 
529
  /* This action is documented in lib/endpoints/class-wp-rest-controller.php */
530
  do_action( "rest_insert_{$this->post_type}", $post, $request, false );
542
  */
543
  public function delete_item_permissions_check( $request ) {
544
 
545
+ $post = $this->get_post( $request['id'] );
546
 
547
  if ( $post && ! $this->check_delete_permission( $post ) ) {
548
  return new WP_Error( 'rest_cannot_delete', __( 'Sorry, you are not allowed to delete posts.' ), array( 'status' => rest_authorization_required_code() ) );
561
  $id = (int) $request['id'];
562
  $force = (bool) $request['force'];
563
 
564
+ $post = $this->get_post( $id );
565
 
566
  if ( empty( $id ) || empty( $post->ID ) || $this->post_type !== $post->post_type ) {
567
  return new WP_Error( 'rest_post_invalid_id', __( 'Invalid post id.' ), array( 'status' => 404 ) );
731
  return $valid_vars;
732
  }
733
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
734
  /**
735
  * Check the post_date_gmt or modified_gmt and prepare any post or
736
  * modified date for single post output.
754
  return mysql_to_rfc3339( $date_gmt );
755
  }
756
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
757
  /**
758
  * Prepare a single post for create or update.
759
  *
808
  $post_type = get_post_type_object( $prepared_post->post_type );
809
 
810
  // Post status.
811
+ if ( ! empty( $schema['properties']['status'] ) && isset( $request['status'] ) ) {
812
  $status = $this->handle_status_param( $request['status'], $post_type );
813
  if ( is_wp_error( $status ) ) {
814
  return $status;
818
  }
819
 
820
  // Post date.
821
+ if ( ! empty( $schema['properties']['date'] ) && ! empty( $request['date'] ) ) {
822
  $date_data = rest_get_date_with_gmt( $request['date'] );
823
 
824
  if ( ! empty( $date_data ) ) {
825
  list( $prepared_post->post_date, $prepared_post->post_date_gmt ) = $date_data;
826
  }
827
+ } elseif ( ! empty( $schema['properties']['date_gmt'] ) && ! empty( $request['date_gmt'] ) ) {
828
  $date_data = rest_get_date_with_gmt( $request['date_gmt'], true );
829
 
830
  if ( ! empty( $date_data ) ) {
832
  }
833
  }
834
  // Post slug.
835
+ if ( ! empty( $schema['properties']['slug'] ) && isset( $request['slug'] ) ) {
836
  $prepared_post->post_name = $request['slug'];
837
  }
838
 
849
  }
850
 
851
  // Post password.
852
+ if ( ! empty( $schema['properties']['password'] ) && isset( $request['password'] ) && '' !== $request['password'] ) {
853
  $prepared_post->post_password = $request['password'];
854
 
855
  if ( ! empty( $schema['properties']['sticky'] ) && ! empty( $request['sticky'] ) ) {
861
  }
862
  }
863
 
864
+ if ( ! empty( $schema['properties']['sticky'] ) && ! empty( $request['sticky'] ) ) {
865
  if ( ! empty( $prepared_post->ID ) && post_password_required( $prepared_post->ID ) ) {
866
  return new WP_Error( 'rest_invalid_field', __( 'A password protected post can not be set to sticky.' ), array( 'status' => 400 ) );
867
  }
869
 
870
  // Parent.
871
  if ( ! empty( $schema['properties']['parent'] ) && ! empty( $request['parent'] ) ) {
872
+ $parent = $this->get_post( (int) $request['parent'] );
873
  if ( empty( $parent ) ) {
874
  return new WP_Error( 'rest_post_invalid_id', __( 'Invalid post parent id.' ), array( 'status' => 400 ) );
875
  }
944
  *
945
  * @param int $featured_media
946
  * @param int $post_id
947
+ *
948
+ * @return bool|WP_Error
949
  */
950
  protected function handle_featured_media( $featured_media, $post_id ) {
951
 
970
  * @param integer $post_id
971
  */
972
  public function handle_template( $template, $post_id ) {
973
+ if ( in_array( $template, array_keys( wp_get_theme()->get_page_templates( $this->get_post( $post_id ) ) ) ) ) {
974
  update_post_meta( $post_id, '_wp_page_template', $template );
975
  } else {
976
  update_post_meta( $post_id, '_wp_page_template', '' );
1027
  * @return boolean Can we read it?
1028
  */
1029
  public function check_read_permission( $post ) {
 
 
 
 
1030
  $post_type = get_post_type_object( $post->post_type );
1031
  if ( ! $this->check_is_post_type_allowed( $post_type ) ) {
1032
  return false;
1044
 
1045
  // Can we read the parent if we're inheriting?
1046
  if ( 'inherit' === $post->post_status && $post->post_parent > 0 ) {
1047
+ $parent = $this->get_post( $post->post_parent );
1048
  return $this->check_read_permission( $parent );
1049
  }
1050
 
1116
  $GLOBALS['post'] = $post;
1117
  setup_postdata( $post );
1118
 
1119
+ $schema = $this->get_item_schema();
1120
+
1121
  // Base fields for every post.
1122
+ $data = array();
1123
+
1124
+ if ( ! empty( $schema['properties']['id'] ) ) {
1125
+ $data['id'] = $post->ID;
1126
+ }
1127
+
1128
+ if ( ! empty( $schema['properties']['date'] ) ) {
1129
+ $data['date'] = $this->prepare_date_response( $post->post_date_gmt, $post->post_date );
1130
+ }
1131
+
1132
+ if ( ! empty( $schema['properties']['date_gmt'] ) ) {
1133
+ $data['date_gmt'] = $this->prepare_date_response( $post->post_date_gmt );
1134
+ }
1135
+
1136
+ if ( ! empty( $schema['properties']['guid'] ) ) {
1137
+ $data['guid'] = array(
1138
  /** This filter is documented in wp-includes/post-template.php */
1139
  'rendered' => apply_filters( 'get_the_guid', $post->guid ),
1140
  'raw' => $post->guid,
1141
+ );
1142
+ }
 
 
 
 
 
 
 
1143
 
1144
+ if ( ! empty( $schema['properties']['modified'] ) ) {
1145
+ $data['modified'] = $this->prepare_date_response( $post->post_modified_gmt, $post->post_modified );
1146
+ }
1147
+
1148
+ if ( ! empty( $schema['properties']['modified_gmt'] ) ) {
1149
+ $data['modified_gmt'] = $this->prepare_date_response( $post->post_modified_gmt );
1150
+ }
1151
+
1152
+ if ( ! empty( $schema['properties']['password'] ) ) {
1153
+ $data['password'] = $post->post_password;
1154
+ }
1155
+
1156
+ if ( ! empty( $schema['properties']['slug'] ) ) {
1157
+ $data['slug'] = $post->post_name;
1158
+ }
1159
+
1160
+ if ( ! empty( $schema['properties']['status'] ) ) {
1161
+ $data['status'] = $post->post_status;
1162
+ }
1163
+
1164
+ if ( ! empty( $schema['properties']['type'] ) ) {
1165
+ $data['type'] = $post->post_type;
1166
+ }
1167
+
1168
+ if ( ! empty( $schema['properties']['link'] ) ) {
1169
+ $data['link'] = get_permalink( $post->ID );
1170
+ }
1171
 
1172
  if ( ! empty( $schema['properties']['title'] ) ) {
1173
+ add_filter( 'protected_title_format', array( $this, 'protected_title_format' ) );
1174
  $data['title'] = array(
1175
  'raw' => $post->post_title,
1176
  'rendered' => get_the_title( $post->ID ),
1177
  );
1178
+ remove_filter( 'protected_title_format', array( $this, 'protected_title_format' ) );
1179
  }
1180
 
1181
+ $has_password_filter = false;
1182
+ if ( $this->can_access_password_content( $post, $request ) ) {
1183
+ // Allow access to the post, permissions already checked before.
1184
+ add_filter( 'post_password_required', '__return_false' );
1185
+ $has_password_filter = true;
1186
+ }
1187
 
1188
+ if ( ! empty( $schema['properties']['content'] ) ) {
1189
  $data['content'] = array(
1190
+ 'raw' => $post->post_content,
1191
  /** This filter is documented in wp-includes/post-template.php */
1192
+ 'rendered' => post_password_required( $post ) ? '' : apply_filters( 'the_content', $post->post_content ),
1193
+ 'protected' => (bool) $post->post_password,
1194
  );
 
 
 
 
 
1195
  }
1196
 
1197
  if ( ! empty( $schema['properties']['excerpt'] ) ) {
1198
+ /** This filter is documented in wp-includes/post-template.php */
1199
+ $excerpt = apply_filters( 'the_excerpt', apply_filters( 'get_the_excerpt', $post->post_excerpt, $post ) );
1200
  $data['excerpt'] = array(
1201
+ 'raw' => $post->post_excerpt,
1202
+ 'rendered' => post_password_required( $post ) ? '' : $excerpt,
1203
+ 'protected' => (bool) $post->post_password,
1204
  );
1205
  }
1206
 
1207
+ if ( $has_password_filter ) {
1208
+ // Reset filter.
1209
+ remove_filter( 'post_password_required', '__return_false' );
1210
+ }
1211
+
1212
  if ( ! empty( $schema['properties']['author'] ) ) {
1213
  $data['author'] = (int) $post->post_author;
1214
  }
1256
  $taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) );
1257
  foreach ( $taxonomies as $taxonomy ) {
1258
  $base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name;
1259
+ if ( ! empty( $schema['properties'][ $base ] ) ) {
1260
+ $terms = get_the_terms( $post, $taxonomy->name );
1261
+ $data[ $base ] = $terms ? array_values( wp_list_pluck( $terms, 'term_id' ) ) : array();
1262
+ }
1263
  }
1264
 
1265
  $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
1284
  return apply_filters( "rest_prepare_{$this->post_type}", $response, $post, $request );
1285
  }
1286
 
1287
+ /**
1288
+ * Overwrite the default protected title format.
1289
+ *
1290
+ * By default WordPress will show password protected posts with a title of
1291
+ * "Protected: %s", as the REST API communicates the protected status of a post
1292
+ * in a machine readable format, we remove the "Protected: " prefix.
1293
+ *
1294
+ * @param string $format
1295
+ * @return string
1296
+ */
1297
+ public function protected_title_format() {
1298
+ return '%s';
1299
+ }
1300
+
1301
  /**
1302
  * Prepare links for the request.
1303
  *
1305
  * @return array Links for the given post.
1306
  */
1307
  protected function prepare_links( $post ) {
1308
+ $base = sprintf( '%s/%s', $this->namespace, $this->rest_base );
1309
 
1310
  // Entity meta
1311
  $links = array(
1316
  'href' => rest_url( $base ),
1317
  ),
1318
  'about' => array(
1319
+ 'href' => rest_url( 'wp/v2/types/' . $this->post_type ),
1320
  ),
1321
  );
1322
 
1323
  if ( ( in_array( $post->post_type, array( 'post', 'page' ) ) || post_type_supports( $post->post_type, 'author' ) )
1324
  && ! empty( $post->post_author ) ) {
1325
  $links['author'] = array(
1326
+ 'href' => rest_url( 'wp/v2/users/' . $post->post_author ),
1327
  'embeddable' => true,
1328
  );
1329
  };
1330
 
1331
  if ( in_array( $post->post_type, array( 'post', 'page' ) ) || post_type_supports( $post->post_type, 'comments' ) ) {
1332
+ $replies_url = rest_url( 'wp/v2/comments' );
1333
  $replies_url = add_query_arg( 'post', $post->ID, $replies_url );
1334
  $links['replies'] = array(
1335
  'href' => $replies_url,
1432
  'description' => __( 'GUID for the object, as it exists in the database.' ),
1433
  'type' => 'string',
1434
  'context' => array( 'edit' ),
1435
+ 'readonly' => true,
1436
  ),
1437
  'rendered' => array(
1438
  'description' => __( 'GUID for the object, transformed for display.' ),
1439
  'type' => 'string',
1440
  'context' => array( 'view', 'edit' ),
1441
+ 'readonly' => true,
1442
  ),
1443
  ),
1444
  ),
1469
  'context' => array( 'view', 'edit' ),
1470
  'readonly' => true,
1471
  ),
 
 
 
 
 
1472
  'slug' => array(
1473
  'description' => __( 'An alphanumeric identifier for the object unique to its type.' ),
1474
  'type' => 'string',
1475
  'context' => array( 'view', 'edit', 'embed' ),
1476
  'arg_options' => array(
1477
+ 'sanitize_callback' => array( $this, 'sanitize_slug' ),
1478
  ),
1479
  ),
1480
  'status' => array(
1564
  'description' => __( 'HTML title for the object, transformed for display.' ),
1565
  'type' => 'string',
1566
  'context' => array( 'view', 'edit', 'embed' ),
1567
+ 'readonly' => true,
1568
  ),
1569
  ),
1570
  );
1585
  'description' => __( 'HTML content for the object, transformed for display.' ),
1586
  'type' => 'string',
1587
  'context' => array( 'view', 'edit' ),
1588
+ 'readonly' => true,
1589
+ ),
1590
+ 'protected' => array(
1591
+ 'description' => __( 'Whether the content is protected with a password.' ),
1592
+ 'type' => 'boolean',
1593
+ 'context' => array( 'view', 'edit', 'embed' ),
1594
+ 'readonly' => true,
1595
  ),
1596
  ),
1597
  );
1620
  'description' => __( 'HTML excerpt for the object, transformed for display.' ),
1621
  'type' => 'string',
1622
  'context' => array( 'view', 'edit', 'embed' ),
1623
+ 'readonly' => true,
1624
+ ),
1625
+ 'protected' => array(
1626
+ 'description' => __( 'Whether the excerpt is protected with a password.' ),
1627
+ 'type' => 'boolean',
1628
+ 'context' => array( 'view', 'edit', 'embed' ),
1629
+ 'readonly' => true,
1630
  ),
1631
  ),
1632
  );
1681
  'type' => 'boolean',
1682
  'context' => array( 'view', 'edit' ),
1683
  );
1684
+
1685
+ $schema['properties']['password'] = array(
1686
+ 'description' => __( 'A password to protect access to the content and excerpt.' ),
1687
+ 'type' => 'string',
1688
+ 'context' => array( 'edit' ),
1689
+ );
1690
  }
1691
 
1692
  if ( 'page' === $this->post_type ) {
1788
  'default' => 'date',
1789
  'enum' => array(
1790
  'date',
1791
+ 'relevance',
1792
  'id',
1793
  'include',
1794
  'title',
1823
  );
1824
  $params['status'] = array(
1825
  'default' => 'publish',
1826
+ 'description' => __( 'Limit result set to posts assigned a specific status; can be comma-delimited list of status types.' ),
1827
+ 'enum' => array_merge( array_keys( get_post_stati() ), array( 'any' ) ),
1828
  'sanitize_callback' => 'sanitize_key',
1829
  'type' => 'string',
1830
  'validate_callback' => array( $this, 'validate_user_can_query_private_statuses' ),
1844
  'default' => array(),
1845
  );
1846
  }
1847
+
1848
+ if ( 'post' === $this->post_type ) {
1849
+ $params['sticky'] = array(
1850
+ 'description' => __( 'Limit result set to items that are sticky.' ),
1851
+ 'type' => 'boolean',
1852
+ 'sanitize_callback' => 'rest_parse_request_arg',
1853
+ );
1854
+ }
1855
+
1856
  return $params;
1857
  }
1858
 
1874
  }
1875
  return new WP_Error( 'rest_forbidden_status', __( 'Status is forbidden' ), array( 'status' => rest_authorization_required_code() ) );
1876
  }
 
1877
  }
lib/endpoints/class-wp-rest-revisions-controller.php CHANGED
@@ -57,7 +57,7 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller {
57
  */
58
  public function get_items_permissions_check( $request ) {
59
 
60
- $parent = get_post( $request['parent'] );
61
  if ( ! $parent ) {
62
  return true;
63
  }
@@ -77,7 +77,7 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller {
77
  */
78
  public function get_items( $request ) {
79
 
80
- $parent = get_post( $request['parent'] );
81
  if ( ! $request['parent'] || ! $parent || $this->parent_post_type !== $parent->post_type ) {
82
  return new WP_Error( 'rest_post_invalid_parent', __( 'Invalid post parent id.' ), array( 'status' => 404 ) );
83
  }
@@ -110,12 +110,12 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller {
110
  */
111
  public function get_item( $request ) {
112
 
113
- $parent = get_post( $request['parent'] );
114
  if ( ! $request['parent'] || ! $parent || $this->parent_post_type !== $parent->post_type ) {
115
  return new WP_Error( 'rest_post_invalid_parent', __( 'Invalid post parent id.' ), array( 'status' => 404 ) );
116
  }
117
 
118
- $revision = get_post( $request['id'] );
119
  if ( ! $revision || 'revision' !== $revision->post_type ) {
120
  return new WP_Error( 'rest_post_invalid_id', __( 'Invalid revision id.' ), array( 'status' => 404 ) );
121
  }
@@ -137,7 +137,7 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller {
137
  return $response;
138
  }
139
 
140
- $post = get_post( $request['id'] );
141
  if ( ! $post ) {
142
  return new WP_Error( 'rest_post_invalid_id', __( 'Invalid revision id.' ), array( 'status' => 404 ) );
143
  }
@@ -180,31 +180,71 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller {
180
  */
181
  public function prepare_item_for_response( $post, $request ) {
182
 
183
- // Base fields for every post
184
- $data = array(
185
- 'author' => $post->post_author,
186
- 'date' => $this->prepare_date_response( $post->post_date_gmt, $post->post_date ),
187
- 'date_gmt' => $this->prepare_date_response( $post->post_date_gmt ),
188
- 'guid' => $post->guid,
189
- 'id' => $post->ID,
190
- 'modified' => $this->prepare_date_response( $post->post_modified_gmt, $post->post_modified ),
191
- 'modified_gmt' => $this->prepare_date_response( $post->post_modified_gmt ),
192
- 'parent' => (int) $post->post_parent,
193
- 'slug' => $post->post_name,
194
- );
195
-
196
  $schema = $this->get_item_schema();
197
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
198
  if ( ! empty( $schema['properties']['title'] ) ) {
199
- $data['title'] = $post->post_title;
 
 
 
200
  }
201
 
202
  if ( ! empty( $schema['properties']['content'] ) ) {
203
- $data['content'] = $post->post_content;
 
 
 
 
 
204
  }
205
 
206
  if ( ! empty( $schema['properties']['excerpt'] ) ) {
207
- $data['excerpt'] = $post->post_excerpt;
 
 
 
208
  }
209
 
210
  $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
@@ -213,7 +253,7 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller {
213
  $response = rest_ensure_response( $data );
214
 
215
  if ( ! empty( $data['parent'] ) ) {
216
- $response->add_link( 'parent', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->parent_base, $data['parent'] ) ) );
217
  }
218
 
219
  /**
@@ -316,38 +356,17 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller {
316
 
317
  $parent_schema = $this->parent_controller->get_item_schema();
318
 
319
- foreach ( array( 'title', 'content', 'excerpt' ) as $property ) {
320
- if ( empty( $parent_schema['properties'][ $property ] ) ) {
321
- continue;
322
- }
323
-
324
- switch ( $property ) {
325
-
326
- case 'title':
327
- $schema['properties']['title'] = array(
328
- 'description' => __( 'Title for the object, as it exists in the database.' ),
329
- 'type' => 'string',
330
- 'context' => array( 'view', 'edit', 'embed' ),
331
- );
332
- break;
333
-
334
- case 'content':
335
- $schema['properties']['content'] = array(
336
- 'description' => __( 'Content for the object, as it exists in the database.' ),
337
- 'type' => 'string',
338
- 'context' => array( 'view', 'edit' ),
339
- );
340
- break;
341
-
342
- case 'excerpt':
343
- $schema['properties']['excerpt'] = array(
344
- 'description' => __( 'Excerpt for the object, as it exists in the database.' ),
345
- 'type' => 'string',
346
- 'context' => array( 'view', 'edit', 'embed' ),
347
- );
348
- break;
349
-
350
- }
351
  }
352
 
353
  return $this->add_additional_fields_schema( $schema );
@@ -364,4 +383,22 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller {
364
  );
365
  }
366
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
367
  }
57
  */
58
  public function get_items_permissions_check( $request ) {
59
 
60
+ $parent = $this->get_post( $request['parent'] );
61
  if ( ! $parent ) {
62
  return true;
63
  }
77
  */
78
  public function get_items( $request ) {
79
 
80
+ $parent = $this->get_post( $request['parent'] );
81
  if ( ! $request['parent'] || ! $parent || $this->parent_post_type !== $parent->post_type ) {
82
  return new WP_Error( 'rest_post_invalid_parent', __( 'Invalid post parent id.' ), array( 'status' => 404 ) );
83
  }
110
  */
111
  public function get_item( $request ) {
112
 
113
+ $parent = $this->get_post( $request['parent'] );
114
  if ( ! $request['parent'] || ! $parent || $this->parent_post_type !== $parent->post_type ) {
115
  return new WP_Error( 'rest_post_invalid_parent', __( 'Invalid post parent id.' ), array( 'status' => 404 ) );
116
  }
117
 
118
+ $revision = $this->get_post( $request['id'] );
119
  if ( ! $revision || 'revision' !== $revision->post_type ) {
120
  return new WP_Error( 'rest_post_invalid_id', __( 'Invalid revision id.' ), array( 'status' => 404 ) );
121
  }
137
  return $response;
138
  }
139
 
140
+ $post = $this->get_post( $request['id'] );
141
  if ( ! $post ) {
142
  return new WP_Error( 'rest_post_invalid_id', __( 'Invalid revision id.' ), array( 'status' => 404 ) );
143
  }
180
  */
181
  public function prepare_item_for_response( $post, $request ) {
182
 
 
 
 
 
 
 
 
 
 
 
 
 
 
183
  $schema = $this->get_item_schema();
184
 
185
+ $data = array();
186
+
187
+ if ( ! empty( $schema['properties']['author'] ) ) {
188
+ $data['author'] = $post->post_author;
189
+ }
190
+
191
+ if ( ! empty( $schema['properties']['date'] ) ) {
192
+ $data['date'] = $this->prepare_date_response( $post->post_date_gmt, $post->post_date );
193
+ }
194
+
195
+ if ( ! empty( $schema['properties']['date_gmt'] ) ) {
196
+ $data['date_gmt'] = $this->prepare_date_response( $post->post_date_gmt );
197
+ }
198
+
199
+ if ( ! empty( $schema['properties']['id'] ) ) {
200
+ $data['id'] = $post->ID;
201
+ }
202
+
203
+ if ( ! empty( $schema['properties']['modified'] ) ) {
204
+ $data['modified'] = $this->prepare_date_response( $post->post_modified_gmt, $post->post_modified );
205
+ }
206
+
207
+ if ( ! empty( $schema['properties']['modified_gmt'] ) ) {
208
+ $data['modified_gmt'] = $this->prepare_date_response( $post->post_modified_gmt );
209
+ }
210
+
211
+ if ( ! empty( $schema['properties']['parent'] ) ) {
212
+ $data['parent'] = (int) $post->post_parent;
213
+ }
214
+
215
+ if ( ! empty( $schema['properties']['slug'] ) ) {
216
+ $data['slug'] = $post->post_name;
217
+ }
218
+
219
+ if ( ! empty( $schema['properties']['guid'] ) ) {
220
+ $data['guid'] = array(
221
+ /** This filter is documented in wp-includes/post-template.php */
222
+ 'rendered' => apply_filters( 'get_the_guid', $post->guid ),
223
+ 'raw' => $post->guid,
224
+ );
225
+ }
226
+
227
  if ( ! empty( $schema['properties']['title'] ) ) {
228
+ $data['title'] = array(
229
+ 'raw' => $post->post_title,
230
+ 'rendered' => get_the_title( $post->ID ),
231
+ );
232
  }
233
 
234
  if ( ! empty( $schema['properties']['content'] ) ) {
235
+
236
+ $data['content'] = array(
237
+ 'raw' => $post->post_content,
238
+ /** This filter is documented in wp-includes/post-template.php */
239
+ 'rendered' => apply_filters( 'the_content', $post->post_content ),
240
+ );
241
  }
242
 
243
  if ( ! empty( $schema['properties']['excerpt'] ) ) {
244
+ $data['excerpt'] = array(
245
+ 'raw' => $post->post_excerpt,
246
+ 'rendered' => $this->prepare_excerpt_response( $post->post_excerpt, $post ),
247
+ );
248
  }
249
 
250
  $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
253
  $response = rest_ensure_response( $data );
254
 
255
  if ( ! empty( $data['parent'] ) ) {
256
+ $response->add_link( 'parent', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->parent_base, $data['parent'] ) ) );
257
  }
258
 
259
  /**
356
 
357
  $parent_schema = $this->parent_controller->get_item_schema();
358
 
359
+ if ( ! empty( $parent_schema['properties']['title'] ) ) {
360
+ $schema['properties']['title'] = $parent_schema['properties']['title'];
361
+ }
362
+ if ( ! empty( $parent_schema['properties']['content'] ) ) {
363
+ $schema['properties']['content'] = $parent_schema['properties']['content'];
364
+ }
365
+ if ( ! empty( $parent_schema['properties']['excerpt'] ) ) {
366
+ $schema['properties']['excerpt'] = $parent_schema['properties']['excerpt'];
367
+ }
368
+ if ( ! empty( $parent_schema['properties']['guid'] ) ) {
369
+ $schema['properties']['guid'] = $parent_schema['properties']['guid'];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
370
  }
371
 
372
  return $this->add_additional_fields_schema( $schema );
383
  );
384
  }
385
 
386
+ /**
387
+ * Check the post excerpt and prepare it for single post output.
388
+ *
389
+ * @param string $excerpt
390
+ * @return string|null $excerpt
391
+ */
392
+ protected function prepare_excerpt_response( $excerpt, $post ) {
393
+
394
+ /** This filter is documented in wp-includes/post-template.php */
395
+ $excerpt = apply_filters( 'the_excerpt', apply_filters( 'get_the_excerpt', $excerpt, $post ) );
396
+
397
+ if ( empty( $excerpt ) ) {
398
+ return '';
399
+ }
400
+
401
+ return $excerpt;
402
+ }
403
+
404
  }
lib/endpoints/class-wp-rest-terms-controller.php CHANGED
@@ -182,7 +182,7 @@ class WP_REST_Terms_Controller extends WP_REST_Controller {
182
  $max_pages = ceil( $total_terms / $per_page );
183
  $response->header( 'X-WP-TotalPages', (int) $max_pages );
184
 
185
- $base = add_query_arg( $request->get_query_params(), rest_url( '/' . $this->namespace . '/' . $this->rest_base ) );
186
  if ( $page > 1 ) {
187
  $prev_page = $page - 1;
188
  if ( $prev_page > $max_pages ) {
@@ -371,12 +371,16 @@ class WP_REST_Terms_Controller extends WP_REST_Controller {
371
  */
372
  do_action( "rest_insert_{$this->taxonomy}", $term, $request, true );
373
 
374
- $this->update_additional_fields_for_object( $term, $request );
 
 
 
 
375
  $request->set_param( 'context', 'view' );
376
  $response = $this->prepare_item_for_response( $term, $request );
377
  $response = rest_ensure_response( $response );
378
  $response->set_status( 201 );
379
- $response->header( 'Location', rest_url( '/' . $this->namespace . '/' . $this->rest_base . '/' . $term->term_id ) );
380
  return $response;
381
  }
382
 
@@ -441,7 +445,11 @@ class WP_REST_Terms_Controller extends WP_REST_Controller {
441
  /* This action is documented in lib/endpoints/class-wp-rest-terms-controller.php */
442
  do_action( "rest_insert_{$this->taxonomy}", $term, $request, false );
443
 
444
- $this->update_additional_fields_for_object( $term, $request );
 
 
 
 
445
  $request->set_param( 'context', 'view' );
446
  $response = $this->prepare_item_for_response( $term, $request );
447
  return rest_ensure_response( $response );
@@ -513,23 +521,24 @@ class WP_REST_Terms_Controller extends WP_REST_Controller {
513
  public function prepare_item_for_database( $request ) {
514
  $prepared_term = new stdClass;
515
 
516
- if ( isset( $request['name'] ) ) {
 
517
  $prepared_term->name = $request['name'];
518
  }
519
 
520
- if ( isset( $request['slug'] ) ) {
521
  $prepared_term->slug = $request['slug'];
522
  }
523
 
524
- if ( isset( $request['taxonomy'] ) ) {
525
  $prepared_term->taxonomy = $request['taxonomy'];
526
  }
527
 
528
- if ( isset( $request['description'] ) ) {
529
  $prepared_term->description = $request['description'];
530
  }
531
 
532
- if ( isset( $request['parent'] ) ) {
533
  $parent_term_id = 0;
534
  $parent_term = get_term( (int) $request['parent'], $this->taxonomy );
535
 
@@ -558,16 +567,29 @@ class WP_REST_Terms_Controller extends WP_REST_Controller {
558
  */
559
  public function prepare_item_for_response( $item, $request ) {
560
 
561
- $data = array(
562
- 'id' => (int) $item->term_id,
563
- 'count' => (int) $item->count,
564
- 'description' => $item->description,
565
- 'link' => get_term_link( $item ),
566
- 'name' => $item->name,
567
- 'slug' => $item->slug,
568
- 'taxonomy' => $item->taxonomy,
569
- );
570
  $schema = $this->get_item_schema();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
571
  if ( ! empty( $schema['properties']['parent'] ) ) {
572
  $data['parent'] = (int) $item->parent;
573
  }
@@ -599,7 +621,7 @@ class WP_REST_Terms_Controller extends WP_REST_Controller {
599
  * @return array Links for the given term.
600
  */
601
  protected function prepare_links( $term ) {
602
- $base = '/' . $this->namespace . '/' . $this->rest_base;
603
  $links = array(
604
  'self' => array(
605
  'href' => rest_url( trailingslashit( $base ) . $term->term_id ),
@@ -697,7 +719,7 @@ class WP_REST_Terms_Controller extends WP_REST_Controller {
697
  'type' => 'string',
698
  'context' => array( 'view', 'embed', 'edit' ),
699
  'arg_options' => array(
700
- 'sanitize_callback' => 'sanitize_title',
701
  ),
702
  ),
703
  'taxonomy' => array(
182
  $max_pages = ceil( $total_terms / $per_page );
183
  $response->header( 'X-WP-TotalPages', (int) $max_pages );
184
 
185
+ $base = add_query_arg( $request->get_query_params(), rest_url( $this->namespace . '/' . $this->rest_base ) );
186
  if ( $page > 1 ) {
187
  $prev_page = $page - 1;
188
  if ( $prev_page > $max_pages ) {
371
  */
372
  do_action( "rest_insert_{$this->taxonomy}", $term, $request, true );
373
 
374
+ $fields_update = $this->update_additional_fields_for_object( $term, $request );
375
+ if ( is_wp_error( $fields_update ) ) {
376
+ return $fields_update;
377
+ }
378
+
379
  $request->set_param( 'context', 'view' );
380
  $response = $this->prepare_item_for_response( $term, $request );
381
  $response = rest_ensure_response( $response );
382
  $response->set_status( 201 );
383
+ $response->header( 'Location', rest_url( $this->namespace . '/' . $this->rest_base . '/' . $term->term_id ) );
384
  return $response;
385
  }
386
 
445
  /* This action is documented in lib/endpoints/class-wp-rest-terms-controller.php */
446
  do_action( "rest_insert_{$this->taxonomy}", $term, $request, false );
447
 
448
+ $fields_update = $this->update_additional_fields_for_object( $term, $request );
449
+ if ( is_wp_error( $fields_update ) ) {
450
+ return $fields_update;
451
+ }
452
+
453
  $request->set_param( 'context', 'view' );
454
  $response = $this->prepare_item_for_response( $term, $request );
455
  return rest_ensure_response( $response );
521
  public function prepare_item_for_database( $request ) {
522
  $prepared_term = new stdClass;
523
 
524
+ $schema = $this->get_item_schema();
525
+ if ( isset( $request['name'] ) && ! empty( $schema['properties']['name'] ) ) {
526
  $prepared_term->name = $request['name'];
527
  }
528
 
529
+ if ( isset( $request['slug'] ) && ! empty( $schema['properties']['slug'] ) ) {
530
  $prepared_term->slug = $request['slug'];
531
  }
532
 
533
+ if ( isset( $request['taxonomy'] ) && ! empty( $schema['properties']['taxonomy'] ) ) {
534
  $prepared_term->taxonomy = $request['taxonomy'];
535
  }
536
 
537
+ if ( isset( $request['description'] ) && ! empty( $schema['properties']['description'] ) ) {
538
  $prepared_term->description = $request['description'];
539
  }
540
 
541
+ if ( isset( $request['parent'] ) && ! empty( $schema['properties']['parent'] ) ) {
542
  $parent_term_id = 0;
543
  $parent_term = get_term( (int) $request['parent'], $this->taxonomy );
544
 
567
  */
568
  public function prepare_item_for_response( $item, $request ) {
569
 
 
 
 
 
 
 
 
 
 
570
  $schema = $this->get_item_schema();
571
+ $data = array();
572
+ if ( ! empty( $schema['properties']['id'] ) ) {
573
+ $data['id'] = (int) $item->term_id;
574
+ }
575
+ if ( ! empty( $schema['properties']['count'] ) ) {
576
+ $data['count'] = (int) $item->count;
577
+ }
578
+ if ( ! empty( $schema['properties']['description'] ) ) {
579
+ $data['description'] = $item->description;
580
+ }
581
+ if ( ! empty( $schema['properties']['link'] ) ) {
582
+ $data['link'] = get_term_link( $item );
583
+ }
584
+ if ( ! empty( $schema['properties']['name'] ) ) {
585
+ $data['name'] = $item->name;
586
+ }
587
+ if ( ! empty( $schema['properties']['slug'] ) ) {
588
+ $data['slug'] = $item->slug;
589
+ }
590
+ if ( ! empty( $schema['properties']['taxonomy'] ) ) {
591
+ $data['taxonomy'] = $item->taxonomy;
592
+ }
593
  if ( ! empty( $schema['properties']['parent'] ) ) {
594
  $data['parent'] = (int) $item->parent;
595
  }
621
  * @return array Links for the given term.
622
  */
623
  protected function prepare_links( $term ) {
624
+ $base = $this->namespace . '/' . $this->rest_base;
625
  $links = array(
626
  'self' => array(
627
  'href' => rest_url( trailingslashit( $base ) . $term->term_id ),
719
  'type' => 'string',
720
  'context' => array( 'view', 'embed', 'edit' ),
721
  'arg_options' => array(
722
+ 'sanitize_callback' => array( $this, 'sanitize_slug' ),
723
  ),
724
  ),
725
  'taxonomy' => array(
lib/endpoints/class-wp-rest-users-controller.php CHANGED
@@ -86,6 +86,10 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
86
  return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you cannot view this resource with edit context.' ), array( 'status' => rest_authorization_required_code() ) );
87
  }
88
 
 
 
 
 
89
  return true;
90
  }
91
 
@@ -112,6 +116,9 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
112
  'include' => 'include',
113
  'name' => 'display_name',
114
  'registered_date' => 'registered',
 
 
 
115
  );
116
  $prepared_args['orderby'] = $orderby_possibles[ $request['orderby'] ];
117
  $prepared_args['search'] = $request['search'];
@@ -121,7 +128,7 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
121
  $prepared_args['has_published_posts'] = true;
122
  }
123
 
124
- if ( '' !== $prepared_args['search'] ) {
125
  $prepared_args['search'] = '*' . $prepared_args['search'] . '*';
126
  }
127
 
@@ -168,7 +175,7 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
168
  $max_pages = ceil( $total_users / $per_page );
169
  $response->header( 'X-WP-TotalPages', (int) $max_pages );
170
 
171
- $base = add_query_arg( $request->get_query_params(), rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ) );
172
  if ( $page > 1 ) {
173
  $prev_page = $page - 1;
174
  if ( $prev_page > $max_pages ) {
@@ -196,7 +203,7 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
196
 
197
  $id = (int) $request['id'];
198
  $user = get_userdata( $id );
199
- $types = get_post_types( array( 'public' => true ), 'names' );
200
 
201
  if ( empty( $id ) || empty( $user->ID ) ) {
202
  return new WP_Error( 'rest_user_invalid_id', __( 'Invalid resource id.' ), array( 'status' => 404 ) );
@@ -250,7 +257,7 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
250
  $user = wp_get_current_user();
251
  $response = $this->prepare_item_for_response( $user, $request );
252
  $response = rest_ensure_response( $response );
253
- $response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $current_user_id ) ) );
254
  $response->set_status( 302 );
255
 
256
  return $response;
@@ -282,7 +289,9 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
282
  return new WP_Error( 'rest_user_exists', __( 'Cannot create existing resource.' ), array( 'status' => 400 ) );
283
  }
284
 
285
- if ( ! empty( $request['roles'] ) ) {
 
 
286
  $check_permission = $this->check_role_update( $request['id'], $request['roles'] );
287
  if ( is_wp_error( $check_permission ) ) {
288
  return $check_permission;
@@ -316,11 +325,14 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
316
  }
317
 
318
  $user = get_user_by( 'id', $user_id );
319
- if ( ! empty( $request['roles'] ) ) {
320
  array_map( array( $user, 'add_role' ), $request['roles'] );
321
  }
322
 
323
- $this->update_additional_fields_for_object( $user, $request );
 
 
 
324
 
325
  /**
326
  * Fires after a user is created or updated via the REST API.
@@ -335,7 +347,7 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
335
  $response = $this->prepare_item_for_response( $user, $request );
336
  $response = rest_ensure_response( $response );
337
  $response->set_status( 201 );
338
- $response->header( 'Location', rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $user_id ) ) );
339
 
340
  return $response;
341
  }
@@ -372,7 +384,7 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
372
 
373
  $user = get_userdata( $id );
374
  if ( ! $user ) {
375
- return new WP_Error( 'rest_user_invalid_id', __( 'Invalid resource id.' ), array( 'status' => 400 ) );
376
  }
377
 
378
  if ( email_exists( $request['email'] ) && $request['email'] !== $user->user_email ) {
@@ -409,7 +421,10 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
409
  array_map( array( $user, 'add_role' ), $request['roles'] );
410
  }
411
 
412
- $this->update_additional_fields_for_object( $user, $request );
 
 
 
413
 
414
  /* This action is documented in lib/endpoints/class-wp-rest-users-controller.php */
415
  do_action( 'rest_insert_user', $user, $request, false );
@@ -455,7 +470,7 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
455
 
456
  $user = get_userdata( $id );
457
  if ( ! $user ) {
458
- return new WP_Error( 'rest_user_invalid_id', __( 'Invalid resource id.' ), array( 'status' => 400 ) );
459
  }
460
 
461
  if ( ! empty( $reassign ) ) {
@@ -496,31 +511,76 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
496
  * @return WP_REST_Response $response Response data.
497
  */
498
  public function prepare_item_for_response( $user, $request ) {
499
- $data = array(
500
- 'id' => $user->ID,
501
- 'username' => $user->user_login,
502
- 'name' => $user->display_name,
503
- 'first_name' => $user->first_name,
504
- 'last_name' => $user->last_name,
505
- 'email' => $user->user_email,
506
- 'url' => $user->user_url,
507
- 'description' => $user->description,
508
- 'link' => get_author_posts_url( $user->ID ),
509
- 'nickname' => $user->nickname,
510
- 'slug' => $user->user_nicename,
511
- 'registered_date' => date( 'c', strtotime( $user->user_registered ) ),
512
- 'roles' => $user->roles,
513
- 'capabilities' => $user->allcaps,
514
- 'extra_capabilities' => $user->caps,
515
- );
516
 
 
517
  $schema = $this->get_item_schema();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
518
 
519
  if ( ! empty( $schema['properties']['avatar_urls'] ) ) {
520
  $data['avatar_urls'] = rest_get_avatar_urls( $user->user_email );
521
  }
522
 
523
  $context = ! empty( $request['context'] ) ? $request['context'] : 'embed';
 
524
  $data = $this->add_additional_fields_to_object( $data, $request );
525
  $data = $this->filter_response_by_context( $data, $context );
526
 
@@ -548,10 +608,10 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
548
  protected function prepare_links( $user ) {
549
  $links = array(
550
  'self' => array(
551
- 'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $user->ID ) ),
552
  ),
553
  'collection' => array(
554
- 'href' => rest_url( sprintf( '/%s/%s', $this->namespace, $this->rest_base ) ),
555
  ),
556
  );
557
 
@@ -567,14 +627,16 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
567
  protected function prepare_item_for_database( $request ) {
568
  $prepared_user = new stdClass;
569
 
 
 
570
  // required arguments.
571
- if ( isset( $request['email'] ) ) {
572
  $prepared_user->user_email = $request['email'];
573
  }
574
- if ( isset( $request['username'] ) ) {
575
  $prepared_user->user_login = $request['username'];
576
  }
577
- if ( isset( $request['password'] ) ) {
578
  $prepared_user->user_pass = $request['password'];
579
  }
580
 
@@ -582,26 +644,26 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
582
  if ( isset( $request['id'] ) ) {
583
  $prepared_user->ID = absint( $request['id'] );
584
  }
585
- if ( isset( $request['name'] ) ) {
586
  $prepared_user->display_name = $request['name'];
587
  }
588
- if ( isset( $request['first_name'] ) ) {
589
  $prepared_user->first_name = $request['first_name'];
590
  }
591
- if ( isset( $request['last_name'] ) ) {
592
  $prepared_user->last_name = $request['last_name'];
593
  }
594
- if ( isset( $request['nickname'] ) ) {
595
  $prepared_user->nickname = $request['nickname'];
596
  }
597
- if ( isset( $request['slug'] ) ) {
598
  $prepared_user->user_nicename = $request['slug'];
599
  }
600
- if ( isset( $request['description'] ) ) {
601
  $prepared_user->description = $request['description'];
602
  }
603
 
604
- if ( isset( $request['url'] ) ) {
605
  $prepared_user->user_url = $request['url'];
606
  }
607
 
@@ -748,12 +810,13 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
748
  'type' => 'string',
749
  'context' => array( 'embed', 'view', 'edit' ),
750
  'arg_options' => array(
751
- 'sanitize_callback' => 'sanitize_title',
752
  ),
753
  ),
754
  'registered_date' => array(
755
  'description' => __( 'Registration date for the resource.' ),
756
- 'type' => 'date-time',
 
757
  'context' => array( 'edit' ),
758
  'readonly' => true,
759
  ),
@@ -772,6 +835,7 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
772
  'description' => __( 'All capabilities assigned to the resource.' ),
773
  'type' => 'object',
774
  'context' => array( 'edit' ),
 
775
  ),
776
  'extra_capabilities' => array(
777
  'description' => __( 'Any extra capabilities assigned to the resource.' ),
@@ -852,6 +916,9 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
852
  'include',
853
  'name',
854
  'registered_date',
 
 
 
855
  ),
856
  'sanitize_callback' => 'sanitize_key',
857
  'type' => 'string',
86
  return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you cannot view this resource with edit context.' ), array( 'status' => rest_authorization_required_code() ) );
87
  }
88
 
89
+ if ( in_array( $request['orderby'], array( 'email', 'registered_date' ), true ) && ! current_user_can( 'list_users' ) ) {
90
+ return new WP_Error( 'rest_forbidden_orderby', __( 'Sorry, you cannot order by this parameter.' ), array( 'status' => rest_authorization_required_code() ) );
91
+ }
92
+
93
  return true;
94
  }
95
 
116
  'include' => 'include',
117
  'name' => 'display_name',
118
  'registered_date' => 'registered',
119
+ 'slug' => 'user_nicename',
120
+ 'email' => 'user_email',
121
+ 'url' => 'user_url',
122
  );
123
  $prepared_args['orderby'] = $orderby_possibles[ $request['orderby'] ];
124
  $prepared_args['search'] = $request['search'];
128
  $prepared_args['has_published_posts'] = true;
129
  }
130
 
131
+ if ( ! empty( $prepared_args['search'] ) ) {
132
  $prepared_args['search'] = '*' . $prepared_args['search'] . '*';
133
  }
134
 
175
  $max_pages = ceil( $total_users / $per_page );
176
  $response->header( 'X-WP-TotalPages', (int) $max_pages );
177
 
178
+ $base = add_query_arg( $request->get_query_params(), rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ) );
179
  if ( $page > 1 ) {
180
  $prev_page = $page - 1;
181
  if ( $prev_page > $max_pages ) {
203
 
204
  $id = (int) $request['id'];
205
  $user = get_userdata( $id );
206
+ $types = get_post_types( array( 'show_in_rest' => true ), 'names' );
207
 
208
  if ( empty( $id ) || empty( $user->ID ) ) {
209
  return new WP_Error( 'rest_user_invalid_id', __( 'Invalid resource id.' ), array( 'status' => 404 ) );
257
  $user = wp_get_current_user();
258
  $response = $this->prepare_item_for_response( $user, $request );
259
  $response = rest_ensure_response( $response );
260
+ $response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $current_user_id ) ) );
261
  $response->set_status( 302 );
262
 
263
  return $response;
289
  return new WP_Error( 'rest_user_exists', __( 'Cannot create existing resource.' ), array( 'status' => 400 ) );
290
  }
291
 
292
+ $schema = $this->get_item_schema();
293
+
294
+ if ( ! empty( $request['roles'] ) && ! empty( $schema['properties']['roles'] ) ) {
295
  $check_permission = $this->check_role_update( $request['id'], $request['roles'] );
296
  if ( is_wp_error( $check_permission ) ) {
297
  return $check_permission;
325
  }
326
 
327
  $user = get_user_by( 'id', $user_id );
328
+ if ( ! empty( $request['roles'] ) && ! empty( $schema['properties']['roles'] ) ) {
329
  array_map( array( $user, 'add_role' ), $request['roles'] );
330
  }
331
 
332
+ $fields_update = $this->update_additional_fields_for_object( $user, $request );
333
+ if ( is_wp_error( $fields_update ) ) {
334
+ return $fields_update;
335
+ }
336
 
337
  /**
338
  * Fires after a user is created or updated via the REST API.
347
  $response = $this->prepare_item_for_response( $user, $request );
348
  $response = rest_ensure_response( $response );
349
  $response->set_status( 201 );
350
+ $response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $user_id ) ) );
351
 
352
  return $response;
353
  }
384
 
385
  $user = get_userdata( $id );
386
  if ( ! $user ) {
387
+ return new WP_Error( 'rest_user_invalid_id', __( 'Invalid resource id.' ), array( 'status' => 404 ) );
388
  }
389
 
390
  if ( email_exists( $request['email'] ) && $request['email'] !== $user->user_email ) {
421
  array_map( array( $user, 'add_role' ), $request['roles'] );
422
  }
423
 
424
+ $fields_update = $this->update_additional_fields_for_object( $user, $request );
425
+ if ( is_wp_error( $fields_update ) ) {
426
+ return $fields_update;
427
+ }
428
 
429
  /* This action is documented in lib/endpoints/class-wp-rest-users-controller.php */
430
  do_action( 'rest_insert_user', $user, $request, false );
470
 
471
  $user = get_userdata( $id );
472
  if ( ! $user ) {
473
+ return new WP_Error( 'rest_user_invalid_id', __( 'Invalid resource id.' ), array( 'status' => 404 ) );
474
  }
475
 
476
  if ( ! empty( $reassign ) ) {
511
  * @return WP_REST_Response $response Response data.
512
  */
513
  public function prepare_item_for_response( $user, $request ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
514
 
515
+ $data = array();
516
  $schema = $this->get_item_schema();
517
+ if ( ! empty( $schema['properties']['id'] ) ) {
518
+ $data['id'] = $user->ID;
519
+ }
520
+
521
+ if ( ! empty( $schema['properties']['username'] ) ) {
522
+ $data['username'] = $user->user_login;
523
+ }
524
+
525
+ if ( ! empty( $schema['properties']['name'] ) ) {
526
+ $data['name'] = $user->display_name;
527
+ }
528
+
529
+ if ( ! empty( $schema['properties']['first_name'] ) ) {
530
+ $data['first_name'] = $user->first_name;
531
+ }
532
+
533
+ if ( ! empty( $schema['properties']['last_name'] ) ) {
534
+ $data['last_name'] = $user->last_name;
535
+ }
536
+
537
+ if ( ! empty( $schema['properties']['email'] ) ) {
538
+ $data['email'] = $user->user_email;
539
+ }
540
+
541
+ if ( ! empty( $schema['properties']['url'] ) ) {
542
+ $data['url'] = $user->user_url;
543
+ }
544
+
545
+ if ( ! empty( $schema['properties']['description'] ) ) {
546
+ $data['description'] = $user->description;
547
+ }
548
+
549
+ if ( ! empty( $schema['properties']['link'] ) ) {
550
+ $data['link'] = get_author_posts_url( $user->ID, $user->user_nicename );
551
+ }
552
+
553
+ if ( ! empty( $schema['properties']['nickname'] ) ) {
554
+ $data['nickname'] = $user->nickname;
555
+ }
556
+
557
+ if ( ! empty( $schema['properties']['slug'] ) ) {
558
+ $data['slug'] = $user->user_nicename;
559
+ }
560
+
561
+ if ( ! empty( $schema['properties']['roles'] ) ) {
562
+ // Defensively call array_values() to ensure an array is returned.
563
+ $data['roles'] = array_values( $user->roles );
564
+ }
565
+
566
+ if ( ! empty( $schema['properties']['registered_date'] ) ) {
567
+ $data['registered_date'] = date( 'c', strtotime( $user->user_registered ) );
568
+ }
569
+
570
+ if ( ! empty( $schema['properties']['capabilities'] ) ) {
571
+ $data['capabilities'] = (object) $user->allcaps;
572
+ }
573
+
574
+ if ( ! empty( $schema['properties']['extra_capabilities'] ) ) {
575
+ $data['extra_capabilities'] = (object) $user->caps;
576
+ }
577
 
578
  if ( ! empty( $schema['properties']['avatar_urls'] ) ) {
579
  $data['avatar_urls'] = rest_get_avatar_urls( $user->user_email );
580
  }
581
 
582
  $context = ! empty( $request['context'] ) ? $request['context'] : 'embed';
583
+
584
  $data = $this->add_additional_fields_to_object( $data, $request );
585
  $data = $this->filter_response_by_context( $data, $context );
586
 
608
  protected function prepare_links( $user ) {
609
  $links = array(
610
  'self' => array(
611
+ 'href' => rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $user->ID ) ),
612
  ),
613
  'collection' => array(
614
+ 'href' => rest_url( sprintf( '%s/%s', $this->namespace, $this->rest_base ) ),
615
  ),
616
  );
617
 
627
  protected function prepare_item_for_database( $request ) {
628
  $prepared_user = new stdClass;
629
 
630
+ $schema = $this->get_item_schema();
631
+
632
  // required arguments.
633
+ if ( isset( $request['email'] ) && ! empty( $schema['properties']['email'] ) ) {
634
  $prepared_user->user_email = $request['email'];
635
  }
636
+ if ( isset( $request['username'] ) && ! empty( $schema['properties']['username'] ) ) {
637
  $prepared_user->user_login = $request['username'];
638
  }
639
+ if ( isset( $request['password'] ) && ! empty( $schema['properties']['password'] ) ) {
640
  $prepared_user->user_pass = $request['password'];
641
  }
642
 
644
  if ( isset( $request['id'] ) ) {
645
  $prepared_user->ID = absint( $request['id'] );
646
  }
647
+ if ( isset( $request['name'] ) && ! empty( $schema['properties']['name'] ) ) {
648
  $prepared_user->display_name = $request['name'];
649
  }
650
+ if ( isset( $request['first_name'] ) && ! empty( $schema['properties']['first_name'] ) ) {
651
  $prepared_user->first_name = $request['first_name'];
652
  }
653
+ if ( isset( $request['last_name'] ) && ! empty( $schema['properties']['last_name'] ) ) {
654
  $prepared_user->last_name = $request['last_name'];
655
  }
656
+ if ( isset( $request['nickname'] ) && ! empty( $schema['properties']['nickname'] ) ) {
657
  $prepared_user->nickname = $request['nickname'];
658
  }
659
+ if ( isset( $request['slug'] ) && ! empty( $schema['properties']['slug'] ) ) {
660
  $prepared_user->user_nicename = $request['slug'];
661
  }
662
+ if ( isset( $request['description'] ) && ! empty( $schema['properties']['description'] ) ) {
663
  $prepared_user->description = $request['description'];
664
  }
665
 
666
+ if ( isset( $request['url'] ) && ! empty( $schema['properties']['url'] ) ) {
667
  $prepared_user->user_url = $request['url'];
668
  }
669
 
810
  'type' => 'string',
811
  'context' => array( 'embed', 'view', 'edit' ),
812
  'arg_options' => array(
813
+ 'sanitize_callback' => array( $this, 'sanitize_slug' ),
814
  ),
815
  ),
816
  'registered_date' => array(
817
  'description' => __( 'Registration date for the resource.' ),
818
+ 'type' => 'string',
819
+ 'format' => 'date-time',
820
  'context' => array( 'edit' ),
821
  'readonly' => true,
822
  ),
835
  'description' => __( 'All capabilities assigned to the resource.' ),
836
  'type' => 'object',
837
  'context' => array( 'edit' ),
838
+ 'readonly' => true,
839
  ),
840
  'extra_capabilities' => array(
841
  'description' => __( 'Any extra capabilities assigned to the resource.' ),
916
  'include',
917
  'name',
918
  'registered_date',
919
+ 'slug',
920
+ 'email',
921
+ 'url',
922
  ),
923
  'sanitize_callback' => 'sanitize_key',
924
  'type' => 'string',
plugin.php CHANGED
@@ -4,7 +4,7 @@
4
  * Description: JSON-based REST API for WordPress, originally developed as part of GSoC 2013.
5
  * Author: WP REST API Team
6
  * Author URI: http://v2.wp-api.org
7
- * Version: 2.0-beta13.1
8
  * Plugin URI: https://github.com/WP-API/WP-API
9
  * License: GPL2+
10
  */
@@ -299,6 +299,10 @@ if ( ! function_exists( 'rest_validate_request_arg' ) ) {
299
  return new WP_Error( 'rest_invalid_param', sprintf( __( '%s is not of type %s' ), $param, 'integer' ) );
300
  }
301
 
 
 
 
 
302
  if ( 'string' === $args['type'] && ! is_string( $value ) ) {
303
  return new WP_Error( 'rest_invalid_param', sprintf( __( '%s is not of type %s' ), $param, 'string' ) );
304
  }
@@ -316,6 +320,11 @@ if ( ! function_exists( 'rest_validate_request_arg' ) ) {
316
  return new WP_Error( 'rest_invalid_email', __( 'The email address you provided is invalid.' ) );
317
  }
318
  break;
 
 
 
 
 
319
  }
320
  }
321
 
@@ -378,6 +387,10 @@ if ( ! function_exists( 'rest_sanitize_request_arg' ) ) {
378
  return (int) $value;
379
  }
380
 
 
 
 
 
381
  if ( isset( $args['format'] ) ) {
382
  switch ( $args['format'] ) {
383
  case 'date-time' :
@@ -391,10 +404,113 @@ if ( ! function_exists( 'rest_sanitize_request_arg' ) ) {
391
 
392
  case 'uri' :
393
  return esc_url_raw( $value );
 
 
 
394
  }
395
  }
396
 
397
  return $value;
398
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
399
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
400
  }
4
  * Description: JSON-based REST API for WordPress, originally developed as part of GSoC 2013.
5
  * Author: WP REST API Team
6
  * Author URI: http://v2.wp-api.org
7
+ * Version: 2.0-beta14
8
  * Plugin URI: https://github.com/WP-API/WP-API
9
  * License: GPL2+
10
  */
299
  return new WP_Error( 'rest_invalid_param', sprintf( __( '%s is not of type %s' ), $param, 'integer' ) );
300
  }
301
 
302
+ if ( 'boolean' === $args['type'] && ! rest_is_boolean( $value ) ) {
303
+ return new WP_Error( 'rest_invalid_param', sprintf( __( '%s is not of type %s' ), $value, 'boolean' ) );
304
+ }
305
+
306
  if ( 'string' === $args['type'] && ! is_string( $value ) ) {
307
  return new WP_Error( 'rest_invalid_param', sprintf( __( '%s is not of type %s' ), $param, 'string' ) );
308
  }
320
  return new WP_Error( 'rest_invalid_email', __( 'The email address you provided is invalid.' ) );
321
  }
322
  break;
323
+ case 'ipv4' :
324
+ if ( ! rest_is_ip_address( $value ) ) {
325
+ return new WP_Error( 'rest_invalid_param', sprintf( __( '%s is not a valid IP address.' ), $value ) );
326
+ }
327
+ break;
328
  }
329
  }
330
 
387
  return (int) $value;
388
  }
389
 
390
+ if ( 'boolean' === $args['type'] ) {
391
+ return rest_sanitize_boolean( $value );
392
+ }
393
+
394
  if ( isset( $args['format'] ) ) {
395
  switch ( $args['format'] ) {
396
  case 'date-time' :
404
 
405
  case 'uri' :
406
  return esc_url_raw( $value );
407
+
408
+ case 'ipv4' :
409
+ return sanitize_text_field( $value );
410
  }
411
  }
412
 
413
  return $value;
414
  }
415
+ }
416
+
417
+
418
+ if ( ! function_exists( 'rest_parse_request_arg' ) ) {
419
+ /**
420
+ * Parse a request argument based on details registered to the route.
421
+ *
422
+ * Runs a validation check and sanitizes the value, primarily to be used via
423
+ * the `sanitize_callback` arguments in the endpoint args registration.
424
+ *
425
+ * @param mixed $value
426
+ * @param WP_REST_Request $request
427
+ * @param string $param
428
+ * @return mixed
429
+ */
430
+ function rest_parse_request_arg( $value, $request, $param ) {
431
+
432
+ $is_valid = rest_validate_request_arg( $value, $request, $param );
433
+
434
+ if ( is_wp_error( $is_valid ) ) {
435
+ return $is_valid;
436
+ }
437
+
438
+ $value = rest_sanitize_request_arg( $value, $request, $param );
439
+
440
+ return $value;
441
+ }
442
+ }
443
 
444
+ if ( ! function_exists( 'rest_is_ip_address' ) ) {
445
+ /**
446
+ * Determines if a IPv4 address is valid.
447
+ *
448
+ * Does not handle IPv6 addresses.
449
+ *
450
+ * @param string $ipv4 IP 32-bit address.
451
+ * @return string|false The valid IPv4 address, otherwise false.
452
+ */
453
+ function rest_is_ip_address( $ipv4 ) {
454
+ $pattern = '/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/';
455
+
456
+ if ( ! preg_match( $pattern, $ipv4 ) ) {
457
+ return false;
458
+ }
459
+
460
+ return $ipv4;
461
+ }
462
+ }
463
+
464
+ /**
465
+ * Changes a boolean-like value into the proper boolean value.
466
+ *
467
+ * @param bool|string|int $value The value being evaluated.
468
+ * @return boolean Returns the proper associated boolean value.
469
+ */
470
+ if ( ! function_exists( 'rest_sanitize_boolean' ) ) {
471
+ function rest_sanitize_boolean( $value ) {
472
+ // String values are translated to `true`; make sure 'false' is false.
473
+ if ( is_string( $value ) ) {
474
+ $value = strtolower( $value );
475
+ if ( in_array( $value, array( 'false', '0' ), true ) ) {
476
+ $value = false;
477
+ }
478
+ }
479
+
480
+ // Everything else will map nicely to boolean.
481
+ return (boolean) $value;
482
+ }
483
+ }
484
+
485
+ /**
486
+ * Determines if a given value is boolean-like.
487
+ *
488
+ * @param bool|string $maybe_bool The value being evaluated.
489
+ * @return boolean True if a boolean, otherwise false.
490
+ */
491
+ if ( ! function_exists( 'rest_is_boolean' ) ) {
492
+ function rest_is_boolean( $maybe_bool ) {
493
+ if ( is_bool( $maybe_bool ) ) {
494
+ return true;
495
+ }
496
+
497
+ if ( is_string( $maybe_bool ) ) {
498
+ $maybe_bool = strtolower( $maybe_bool );
499
+
500
+ $valid_boolean_values = array(
501
+ 'false',
502
+ 'true',
503
+ '0',
504
+ '1',
505
+ );
506
+
507
+ return in_array( $maybe_bool, $valid_boolean_values, true );
508
+ }
509
+
510
+ if ( is_int( $maybe_bool ) ) {
511
+ return in_array( $maybe_bool, array( 0, 1 ), true );
512
+ }
513
+
514
+ return false;
515
+ }
516
  }
readme.txt CHANGED
@@ -1,9 +1,9 @@
1
  === WordPress REST API (Version 2) ===
2
  Contributors: rmccue, rachelbaker, danielbachhuber, joehoyle
3
- Tags: json, rest, api, rest-api
4
  Requires at least: 4.4
5
- Tested up to: 4.5
6
- Stable tag: 2.0-beta13.1
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
@@ -16,9 +16,9 @@ This plugin provides an easy to use REST API, available via HTTP. Grab your site
16
 
17
  Want to get your site's posts? Simply send a `GET` request to `/wp-json/wp/v2/posts`. Update user with ID 4? Send a `PUT` request to `/wp-json/wp/v2/users/4`. Get all posts with the search term "awesome"? `GET /wp-json/wp/v2/posts?filter[s]=awesome`. It's that easy.
18
 
19
- WP API exposes a simple yet easy interface to WP Query, the posts API, post meta API, users API, revisions API and many more. Chances are, if you can do it with WordPress, WP API will let you do it.
20
 
21
- WP API also includes an easy-to-use Javascript API based on Backbone models, allowing plugin and theme developers to get up and running without needing to know anything about the details of getting connected.
22
 
23
  Check out [our documentation][docs] for information on what's available in the API and how to use it. We've also got documentation on extending the API with extra data for plugin and theme developers!
24
 
@@ -38,10 +38,6 @@ Once you've installed and activated the plugin, [check out the documentation](ht
38
 
39
  == Changelog ==
40
 
41
- = 2.0 Beta 13.1 (May 25, 2016) =
42
-
43
- * SECURITY: Return error when request can't context==edit for users.
44
-
45
  = 2.0 Beta 13.0 (March 29, 2016) =
46
 
47
  * BREAKING CHANGE: Fix Content-Disposition header parsing.
1
  === WordPress REST API (Version 2) ===
2
  Contributors: rmccue, rachelbaker, danielbachhuber, joehoyle
3
+ Tags: json, rest, api, rest-api, wp-rest-api
4
  Requires at least: 4.4
5
+ Tested up to: 4.6.1
6
+ Stable tag: 2.0-beta14
7
  License: GPLv2 or later
8
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
 
16
 
17
  Want to get your site's posts? Simply send a `GET` request to `/wp-json/wp/v2/posts`. Update user with ID 4? Send a `PUT` request to `/wp-json/wp/v2/users/4`. Get all posts with the search term "awesome"? `GET /wp-json/wp/v2/posts?filter[s]=awesome`. It's that easy.
18
 
19
+ The WordPress REST API exposes a simple yet easy interface to WP Query, the posts API, post meta API, users API, revisions API and many more. Chances are, if you can do it with WordPress, the API will let you do it.
20
 
21
+ The REST API also includes an easy-to-use JavaScript API based on Backbone models, allowing plugin and theme developers to get up and running without needing to know anything about the details of getting connected.
22
 
23
  Check out [our documentation][docs] for information on what's available in the API and how to use it. We've also got documentation on extending the API with extra data for plugin and theme developers!
24
 
38
 
39
  == Changelog ==
40
 
 
 
 
 
41
  = 2.0 Beta 13.0 (March 29, 2016) =
42
 
43
  * BREAKING CHANGE: Fix Content-Disposition header parsing.
wp-api.js CHANGED
@@ -2,6 +2,9 @@
2
 
3
  'use strict';
4
 
 
 
 
5
  function WP_API() {
6
  this.models = {};
7
  this.collections = {};
@@ -12,7 +15,7 @@
12
  wp.api = wp.api || new WP_API();
13
  wp.api.versionString = wp.api.versionString || 'wp/v2/';
14
 
15
- // Alias _includes to _.contains, ensuring it is available.
16
  if ( ! _.isFunction( _.includes ) && _.isFunction( _.contains ) ) {
17
  _.includes = _.contains;
18
  }
@@ -117,7 +120,7 @@
117
  };
118
 
119
  /**
120
- * Extract a route part based on negitive index.
121
  *
122
  * @param {string} route The endpoint route.
123
  * @param {int} part The number of parts from the end of the route to retrieve. Default 1.
@@ -250,8 +253,8 @@
250
  _.each( parseableDates, function( key ) {
251
  if ( key in attributes ) {
252
 
253
- // Don't convert null values
254
- if ( ! _.isNull( attributes[ key ] ) ) {
255
  attributes[ key ] = attributes[ key ].toISOString();
256
  }
257
  }
@@ -275,7 +278,7 @@
275
  return;
276
  }
277
 
278
- // Don't convert null values
279
  if ( ! _.isNull( response[ key ] ) ) {
280
  timestamp = wp.api.utils.parseISO8601( response[ key ] );
281
  response[ key ] = new Date( timestamp );
@@ -303,8 +306,8 @@
303
  deferred = jQuery.Deferred();
304
  embeddeds = parentModel.get( '_embedded' ) || {};
305
 
306
- // Verify that we have a valied author id.
307
- if ( ! _.isNumber( modelId ) ) {
308
  deferred.reject();
309
  return deferred;
310
  }
@@ -619,11 +622,11 @@
619
  },
620
 
621
  /**
622
- * Add a helper function to retrieve the featured image.
623
  */
624
- FeaturedImageMixin = {
625
- getFeaturedImage: function() {
626
- return buildModelGetter( this, this.get( 'featured_image' ), 'Media', 'https://api.w.org/featuredmedia', 'source_url' );
627
  }
628
  };
629
 
@@ -649,9 +652,9 @@
649
  model = model.extend( AuthorMixin );
650
  }
651
 
652
- // Add the FeaturedImageMixin for models that contain a featured_image.
653
- if ( ! _.isUndefined( model.prototype.args.featured_image ) ) {
654
- model = model.extend( FeaturedImageMixin );
655
  }
656
 
657
  // Add the CategoriesMixin for models that support categories collections.
@@ -837,7 +840,7 @@
837
  },
838
 
839
  /**
840
- * Overwrite Backbone.Collection.sync to pagination state based on response headers.
841
  *
842
  * Set nonce header before every Backbone sync.
843
  *
@@ -853,6 +856,7 @@
853
  options = options || {};
854
  beforeSend = options.beforeSend;
855
 
 
856
  if ( 'undefined' !== typeof wpApiSettings.nonce ) {
857
  options.beforeSend = function( xhr ) {
858
  xhr.setRequestHeader( 'X-WP-Nonce', wpApiSettings.nonce );
@@ -863,6 +867,7 @@
863
  };
864
  }
865
 
 
866
  if ( 'read' === method ) {
867
  if ( options.data ) {
868
  self.state.data = _.clone( options.data );
@@ -873,8 +878,8 @@
873
  }
874
 
875
  if ( 'undefined' === typeof options.data.page ) {
876
- self.state.currentPage = null;
877
- self.state.totalPages = null;
878
  self.state.totalObjects = null;
879
  } else {
880
  self.state.currentPage = options.data.page - 1;
@@ -883,7 +888,7 @@
883
  success = options.success;
884
  options.success = function( data, textStatus, request ) {
885
  if ( ! _.isUndefined( request ) ) {
886
- self.state.totalPages = parseInt( request.getResponseHeader( 'x-wp-totalpages' ), 10 );
887
  self.state.totalObjects = parseInt( request.getResponseHeader( 'x-wp-total' ), 10 );
888
  }
889
 
@@ -899,6 +904,7 @@
899
  };
900
  }
901
 
 
902
  return Backbone.sync( method, model, options );
903
  },
904
 
@@ -957,11 +963,12 @@
957
  window.wp = window.wp || {};
958
  wp.api = wp.api || {};
959
 
 
960
  if ( _.isEmpty( wpApiSettings ) ) {
961
  wpApiSettings.root = window.location.origin + '/wp-json/';
962
  }
963
 
964
- Endpoint = Backbone.Model.extend({
965
  defaults: {
966
  apiRoot: wpApiSettings.root,
967
  versionString: wp.api.versionString,
@@ -970,6 +977,9 @@
970
  collections: {}
971
  },
972
 
 
 
 
973
  initialize: function() {
974
  var model = this, deferred;
975
 
@@ -981,8 +991,9 @@
981
  model.schemaModel = new wp.api.models.Schema( null, {
982
  apiRoot: model.get( 'apiRoot' ),
983
  versionString: model.get( 'versionString' )
984
- });
985
 
 
986
  model.schemaModel.once( 'change', function() {
987
  model.constructFromSchema();
988
  deferred.resolve( model );
@@ -992,29 +1003,39 @@
992
 
993
  // Use schema supplied as model attribute.
994
  model.schemaModel.set( model.schemaModel.parse( model.get( 'schema' ) ) );
995
- } else if ( ! _.isUndefined( sessionStorage ) && sessionStorage.getItem( 'wp-api-schema-model' + model.get( 'apiRoot' ) + model.get( 'versionString' ) ) ) {
 
 
 
 
996
 
997
  // Used a cached copy of the schema model if available.
998
  model.schemaModel.set( model.schemaModel.parse( JSON.parse( sessionStorage.getItem( 'wp-api-schema-model' + model.get( 'apiRoot' ) + model.get( 'versionString' ) ) ) ) );
999
  } else {
1000
- model.schemaModel.fetch({
1001
  /**
1002
- * When the server return the schema model data, store the data in a sessionCache so we don't
1003
  * have to retrieve it again for this session. Then, construct the models and collections based
1004
  * on the schema model data.
1005
  */
1006
  success: function( newSchemaModel ) {
1007
 
1008
  // Store a copy of the schema model in the session cache if available.
1009
- if ( ! _.isUndefined( sessionStorage ) ) {
1010
- sessionStorage.setItem( 'wp-api-schema-model' + model.get( 'apiRoot' ) + model.get( 'versionString' ), JSON.stringify( newSchemaModel ) );
 
 
 
 
 
1011
  }
1012
  },
1013
 
1014
- // @todo Handle the error condition.
1015
- error: function() {
 
1016
  }
1017
- });
1018
  }
1019
  },
1020
 
@@ -1060,10 +1081,10 @@
1060
  * Iterate thru the routes, picking up models and collections to build. Builds two arrays,
1061
  * one for models and one for collections.
1062
  */
1063
- modelRoutes = [];
1064
- collectionRoutes = [];
1065
- schemaRoot = routeModel.get( 'apiRoot' ).replace( wp.api.utils.getRootUrl(), '' );
1066
- loadingObjects = {};
1067
 
1068
  /**
1069
  * Tracking objects for models and collections.
@@ -1080,7 +1101,7 @@
1080
  ) {
1081
 
1082
  // Single items end with a regex (or the special case 'me').
1083
- if ( /.*[+)|me]$/.test( index ) ) {
1084
  modelRoutes.push( { index: index, route: route } );
1085
  } else {
1086
 
@@ -1114,7 +1135,7 @@
1114
  modelClassName = mapping.models[ modelClassName ] || modelClassName;
1115
  loadingObjects.models[ modelClassName ] = wp.api.WPApiBaseModel.extend( {
1116
 
1117
- // Function that returns a constructed url based on the parent and id.
1118
  url: function() {
1119
  var url = routeModel.get( 'apiRoot' ) + routeModel.get( 'versionString' ) +
1120
  parentName + '/' +
@@ -1138,6 +1159,7 @@
1138
  methods: modelRoute.route.methods,
1139
 
1140
  initialize: function() {
 
1141
  /**
1142
  * Posts and pages support trashing, other types don't support a trash
1143
  * and require that you pass ?force=true to actually delete them.
@@ -1183,7 +1205,7 @@
1183
  } );
1184
  }
1185
 
1186
- // Add defaults to the new model, pulled form the endpoint
1187
  wp.api.utils.decorateFromRoute( modelRoute.route.endpoints, loadingObjects.models[ modelClassName ] );
1188
 
1189
  } );
@@ -1200,7 +1222,7 @@
1200
  routeName = collectionRoute.index.slice( collectionRoute.index.lastIndexOf( '/' ) + 1 ),
1201
  parentName = wp.api.utils.extractRoutePart( collectionRoute.index, 3 );
1202
 
1203
- // If the collection has a parent in its route, add that to its class name/
1204
  if ( '' !== parentName && parentName !== routeName ) {
1205
 
1206
  collectionClassName = wp.api.utils.capitalize( parentName ) + wp.api.utils.capitalize( routeName );
@@ -1252,7 +1274,7 @@
1252
  } );
1253
  }
1254
 
1255
- // Add defaults to the new model, pulled form the endpoint
1256
  wp.api.utils.decorateFromRoute( collectionRoute.route.endpoints, loadingObjects.collections[ collectionClassName ] );
1257
  } );
1258
 
@@ -1263,11 +1285,11 @@
1263
 
1264
  }
1265
 
1266
- });
1267
 
1268
- wp.api.endpoints = new Backbone.Collection({
1269
  model: Endpoint
1270
- });
1271
 
1272
  /**
1273
  * Initialize the wp-api, optionally passing the API root.
@@ -1280,10 +1302,10 @@
1280
  wp.api.init = function( args ) {
1281
  var endpoint, attributes = {}, deferred, promise;
1282
 
1283
- args = args || {};
1284
- attributes.apiRoot = args.apiRoot || wpApiSettings.root;
1285
  attributes.versionString = args.versionString || wpApiSettings.versionString;
1286
- attributes.schema = args.schema || null;
1287
  if ( ! attributes.schema && attributes.apiRoot === wpApiSettings.root && attributes.versionString === wpApiSettings.versionString ) {
1288
  attributes.schema = wpApiSettings.schema;
1289
  }
2
 
3
  'use strict';
4
 
5
+ /**
6
+ * Initialise the WP_API.
7
+ */
8
  function WP_API() {
9
  this.models = {};
10
  this.collections = {};
15
  wp.api = wp.api || new WP_API();
16
  wp.api.versionString = wp.api.versionString || 'wp/v2/';
17
 
18
+ // Alias _includes to _.contains, ensuring it is available if lodash is used.
19
  if ( ! _.isFunction( _.includes ) && _.isFunction( _.contains ) ) {
20
  _.includes = _.contains;
21
  }
120
  };
121
 
122
  /**
123
+ * Extract a route part based on negative index.
124
  *
125
  * @param {string} route The endpoint route.
126
  * @param {int} part The number of parts from the end of the route to retrieve. Default 1.
253
  _.each( parseableDates, function( key ) {
254
  if ( key in attributes ) {
255
 
256
+ // Only convert dates.
257
+ if ( _.isDate( attributes[ key ] ) ) {
258
  attributes[ key ] = attributes[ key ].toISOString();
259
  }
260
  }
278
  return;
279
  }
280
 
281
+ // Don't convert null values.
282
  if ( ! _.isNull( response[ key ] ) ) {
283
  timestamp = wp.api.utils.parseISO8601( response[ key ] );
284
  response[ key ] = new Date( timestamp );
306
  deferred = jQuery.Deferred();
307
  embeddeds = parentModel.get( '_embedded' ) || {};
308
 
309
+ // Verify that we have a valied object id.
310
+ if ( ! _.isNumber( modelId ) || 0 === modelId ) {
311
  deferred.reject();
312
  return deferred;
313
  }
622
  },
623
 
624
  /**
625
+ * Add a helper function to retrieve the featured media.
626
  */
627
+ FeaturedMediaMixin = {
628
+ getFeaturedMedia: function() {
629
+ return buildModelGetter( this, this.get( 'featured_media' ), 'Media', 'wp:featuredmedia', 'source_url' );
630
  }
631
  };
632
 
652
  model = model.extend( AuthorMixin );
653
  }
654
 
655
+ // Add the FeaturedMediaMixin for models that contain a featured_media.
656
+ if ( ! _.isUndefined( model.prototype.args.featured_media ) ) {
657
+ model = model.extend( FeaturedMediaMixin );
658
  }
659
 
660
  // Add the CategoriesMixin for models that support categories collections.
840
  },
841
 
842
  /**
843
+ * Extend Backbone.Collection.sync to add nince and pagination support.
844
  *
845
  * Set nonce header before every Backbone sync.
846
  *
856
  options = options || {};
857
  beforeSend = options.beforeSend;
858
 
859
+ // If we have a localized nonce, pass that along with each sync.
860
  if ( 'undefined' !== typeof wpApiSettings.nonce ) {
861
  options.beforeSend = function( xhr ) {
862
  xhr.setRequestHeader( 'X-WP-Nonce', wpApiSettings.nonce );
867
  };
868
  }
869
 
870
+ // When reading, add pagination data.
871
  if ( 'read' === method ) {
872
  if ( options.data ) {
873
  self.state.data = _.clone( options.data );
878
  }
879
 
880
  if ( 'undefined' === typeof options.data.page ) {
881
+ self.state.currentPage = null;
882
+ self.state.totalPages = null;
883
  self.state.totalObjects = null;
884
  } else {
885
  self.state.currentPage = options.data.page - 1;
888
  success = options.success;
889
  options.success = function( data, textStatus, request ) {
890
  if ( ! _.isUndefined( request ) ) {
891
+ self.state.totalPages = parseInt( request.getResponseHeader( 'x-wp-totalpages' ), 10 );
892
  self.state.totalObjects = parseInt( request.getResponseHeader( 'x-wp-total' ), 10 );
893
  }
894
 
904
  };
905
  }
906
 
907
+ // Continue by calling Bacckbone's sync.
908
  return Backbone.sync( method, model, options );
909
  },
910
 
963
  window.wp = window.wp || {};
964
  wp.api = wp.api || {};
965
 
966
+ // If wpApiSettings is unavailable, try the default.
967
  if ( _.isEmpty( wpApiSettings ) ) {
968
  wpApiSettings.root = window.location.origin + '/wp-json/';
969
  }
970
 
971
+ Endpoint = Backbone.Model.extend( {
972
  defaults: {
973
  apiRoot: wpApiSettings.root,
974
  versionString: wp.api.versionString,
977
  collections: {}
978
  },
979
 
980
+ /**
981
+ * Initialize the Endpoint model.
982
+ */
983
  initialize: function() {
984
  var model = this, deferred;
985
 
991
  model.schemaModel = new wp.api.models.Schema( null, {
992
  apiRoot: model.get( 'apiRoot' ),
993
  versionString: model.get( 'versionString' )
994
+ } );
995
 
996
+ // When the model loads, resolve the promise.
997
  model.schemaModel.once( 'change', function() {
998
  model.constructFromSchema();
999
  deferred.resolve( model );
1003
 
1004
  // Use schema supplied as model attribute.
1005
  model.schemaModel.set( model.schemaModel.parse( model.get( 'schema' ) ) );
1006
+ } else if (
1007
+ ! _.isUndefined( sessionStorage ) &&
1008
+ ( _.isUndefined( wpApiSettings.cacheSchema ) || wpApiSettings.cacheSchema ) &&
1009
+ sessionStorage.getItem( 'wp-api-schema-model' + model.get( 'apiRoot' ) + model.get( 'versionString' ) )
1010
+ ) {
1011
 
1012
  // Used a cached copy of the schema model if available.
1013
  model.schemaModel.set( model.schemaModel.parse( JSON.parse( sessionStorage.getItem( 'wp-api-schema-model' + model.get( 'apiRoot' ) + model.get( 'versionString' ) ) ) ) );
1014
  } else {
1015
+ model.schemaModel.fetch( {
1016
  /**
1017
+ * When the server returns the schema model data, store the data in a sessionCache so we don't
1018
  * have to retrieve it again for this session. Then, construct the models and collections based
1019
  * on the schema model data.
1020
  */
1021
  success: function( newSchemaModel ) {
1022
 
1023
  // Store a copy of the schema model in the session cache if available.
1024
+ if ( ! _.isUndefined( sessionStorage ) && wpApiSettings.cacheSchema ) {
1025
+ try {
1026
+ sessionStorage.setItem( 'wp-api-schema-model' + model.get( 'apiRoot' ) + model.get( 'versionString' ), JSON.stringify( newSchemaModel ) );
1027
+ } catch ( error ) {
1028
+
1029
+ // Fail silently, fixes errors in safari private mode.
1030
+ }
1031
  }
1032
  },
1033
 
1034
+ // Log the error condition.
1035
+ error: function( err ) {
1036
+ window.console.log( err );
1037
  }
1038
+ } );
1039
  }
1040
  },
1041
 
1081
  * Iterate thru the routes, picking up models and collections to build. Builds two arrays,
1082
  * one for models and one for collections.
1083
  */
1084
+ modelRoutes = [];
1085
+ collectionRoutes = [];
1086
+ schemaRoot = routeModel.get( 'apiRoot' ).replace( wp.api.utils.getRootUrl(), '' );
1087
+ loadingObjects = {};
1088
 
1089
  /**
1090
  * Tracking objects for models and collections.
1101
  ) {
1102
 
1103
  // Single items end with a regex (or the special case 'me').
1104
+ if ( /(?:.*[+)]|\/me)$/.test( index ) ) {
1105
  modelRoutes.push( { index: index, route: route } );
1106
  } else {
1107
 
1135
  modelClassName = mapping.models[ modelClassName ] || modelClassName;
1136
  loadingObjects.models[ modelClassName ] = wp.api.WPApiBaseModel.extend( {
1137
 
1138
+ // Return a constructed url based on the parent and id.
1139
  url: function() {
1140
  var url = routeModel.get( 'apiRoot' ) + routeModel.get( 'versionString' ) +
1141
  parentName + '/' +
1159
  methods: modelRoute.route.methods,
1160
 
1161
  initialize: function() {
1162
+
1163
  /**
1164
  * Posts and pages support trashing, other types don't support a trash
1165
  * and require that you pass ?force=true to actually delete them.
1205
  } );
1206
  }
1207
 
1208
+ // Add defaults to the new model, pulled form the endpoint.
1209
  wp.api.utils.decorateFromRoute( modelRoute.route.endpoints, loadingObjects.models[ modelClassName ] );
1210
 
1211
  } );
1222
  routeName = collectionRoute.index.slice( collectionRoute.index.lastIndexOf( '/' ) + 1 ),
1223
  parentName = wp.api.utils.extractRoutePart( collectionRoute.index, 3 );
1224
 
1225
+ // If the collection has a parent in its route, add that to its class name.
1226
  if ( '' !== parentName && parentName !== routeName ) {
1227
 
1228
  collectionClassName = wp.api.utils.capitalize( parentName ) + wp.api.utils.capitalize( routeName );
1274
  } );
1275
  }
1276
 
1277
+ // Add defaults to the new model, pulled form the endpoint.
1278
  wp.api.utils.decorateFromRoute( collectionRoute.route.endpoints, loadingObjects.collections[ collectionClassName ] );
1279
  } );
1280
 
1285
 
1286
  }
1287
 
1288
+ } );
1289
 
1290
+ wp.api.endpoints = new Backbone.Collection( {
1291
  model: Endpoint
1292
+ } );
1293
 
1294
  /**
1295
  * Initialize the wp-api, optionally passing the API root.
1302
  wp.api.init = function( args ) {
1303
  var endpoint, attributes = {}, deferred, promise;
1304
 
1305
+ args = args || {};
1306
+ attributes.apiRoot = args.apiRoot || wpApiSettings.root;
1307
  attributes.versionString = args.versionString || wpApiSettings.versionString;
1308
+ attributes.schema = args.schema || null;
1309
  if ( ! attributes.schema && attributes.apiRoot === wpApiSettings.root && attributes.versionString === wpApiSettings.versionString ) {
1310
  attributes.schema = wpApiSettings.schema;
1311
  }
wp-api.min.js CHANGED
@@ -1,2 +1,2 @@
1
- !function(a,b){"use strict";function c(){this.models={},this.collections={},this.views={}}a.wp=a.wp||{},wp.api=wp.api||new c,wp.api.versionString=wp.api.versionString||"wp/v2/",!_.isFunction(_.includes)&&_.isFunction(_.contains)&&(_.includes=_.contains)}(window),function(a,b){"use strict";var c,d;a.wp=a.wp||{},wp.api=wp.api||{},wp.api.utils=wp.api.utils||{},Date.prototype.toISOString||(c=function(a){return d=String(a),1===d.length&&(d="0"+d),d},Date.prototype.toISOString=function(){return this.getUTCFullYear()+"-"+c(this.getUTCMonth()+1)+"-"+c(this.getUTCDate())+"T"+c(this.getUTCHours())+":"+c(this.getUTCMinutes())+":"+c(this.getUTCSeconds())+"."+String((this.getUTCMilliseconds()/1e3).toFixed(3)).slice(2,5)+"Z"}),wp.api.utils.parseISO8601=function(a){var c,d,e,f,g=0,h=[1,4,5,6,7,10,11];if(d=/^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(a)){for(e=0;f=h[e];++e)d[f]=+d[f]||0;d[2]=(+d[2]||1)-1,d[3]=+d[3]||1,"Z"!==d[8]&&b!==d[9]&&(g=60*d[10]+d[11],"+"===d[9]&&(g=0-g)),c=Date.UTC(d[1],d[2],d[3],d[4],d[5]+g,d[6],d[7])}else c=Date.parse?Date.parse(a):NaN;return c},wp.api.utils.getRootUrl=function(){return a.location.origin?a.location.origin+"/":a.location.protocol+"/"+a.location.host+"/"},wp.api.utils.capitalize=function(a){return _.isUndefined(a)?a:a.charAt(0).toUpperCase()+a.slice(1)},wp.api.utils.extractRoutePart=function(a,b){var c;return b=b||1,a=a.replace(wp.api.versionString,""),c=a.split("/").reverse(),_.isUndefined(c[--b])?"":c[b]},wp.api.utils.extractParentName=function(a){var b,c=a.lastIndexOf("_id>[\\d]+)/");return 0>c?"":(b=a.substr(0,c-1),b=b.split("/"),b.pop(),b=b.pop())},wp.api.utils.decorateFromRoute=function(a,b){_.each(a,function(a){_.includes(a.methods,"POST")||_.includes(a.methods,"PUT")?_.isEmpty(a.args)||(_.isEmpty(b.prototype.args)?b.prototype.args=a.args:b.prototype.args=_.union(a.args,b.prototype.defaults)):_.includes(a.methods,"GET")&&(_.isEmpty(a.args)||(_.isEmpty(b.prototype.options)?b.prototype.options=a.args:b.prototype.options=_.union(a.args,b.prototype.options)))})},wp.api.utils.addMixinsAndHelpers=function(a,b,c){var d=!1,e=["date","modified","date_gmt","modified_gmt"],f={toJSON:function(){var a=_.clone(this.attributes);return _.each(e,function(b){b in a&&(_.isNull(a[b])||(a[b]=a[b].toISOString()))}),a},parse:function(a){var b;return _.each(e,function(c){c in a&&(_.isNull(a[c])||(b=wp.api.utils.parseISO8601(a[c]),a[c]=new Date(b)))}),a}},g=function(a,b,c,d,e){var f,g,h,i;return i=jQuery.Deferred(),g=a.get("_embedded")||{},_.isNumber(b)?(g[d]&&(h=_.findWhere(g[d],{id:b})),h||(h={id:b}),f=new wp.api.models[c](h),f.get(e)?i.resolve(f):f.fetch({success:function(a){i.resolve(a)}}),i.promise()):(i.reject(),i)},h=function(a,b,c,d){var e,f,g,h="",j="",k=jQuery.Deferred();return e=a.get("id"),f=a.get("_embedded")||{},_.isNumber(e)&&0!==e?(_.isUndefined(c)||_.isUndefined(f[c])?h={parent:e}:j=_.isUndefined(d)?f[c]:f[c][d],g=new wp.api.collections[b](j,h),_.isUndefined(g.models[0])?g.fetch({success:function(a){i(a,e),k.resolve(a)}}):(i(g,e),k.resolve(g)),k.promise()):(k.reject(),k)},i=function(a,b){_.each(a.models,function(a){a.set("parent_post",b)})},j={getMeta:function(){return h(this,"PostMeta","https://api.w.org/meta")}},k={getRevisions:function(){return h(this,"PostRevisions")}},l={getTags:function(){var a=this.get("tags"),b=new wp.api.collections.Tags;return _.isEmpty(a)?jQuery.Deferred().resolve([]):b.fetch({data:{include:a}})},setTags:function(a){var b,c,d=this,e=[];return _.isString(a)?!1:void(_.isArray(a)?(b=new wp.api.collections.Tags,b.fetch({data:{per_page:100},success:function(b){_.each(a,function(a){c=new wp.api.models.Tag(b.findWhere({slug:a})),c.set("parent_post",d.get("id")),e.push(c)}),a=new wp.api.collections.Tags(e),d.setTagsWithCollection(a)}})):this.setTagsWithCollection(a))},setTagsWithCollection:function(a){return this.set("tags",a.pluck("id")),this.save()}},m={getCategories:function(){var a=this.get("categories"),b=new wp.api.collections.Categories;return _.isEmpty(a)?jQuery.Deferred().resolve([]):b.fetch({data:{include:a}})},setCategories:function(a){var b,c,d=this,e=[];return _.isString(a)?!1:void(_.isArray(a)?(b=new wp.api.collections.Categories,b.fetch({data:{per_page:100},success:function(b){_.each(a,function(a){c=new wp.api.models.Category(b.findWhere({slug:a})),c.set("parent_post",d.get("id")),e.push(c)}),a=new wp.api.collections.Categories(e),d.setCategoriesWithCollection(a)}})):this.setCategoriesWithCollection(a))},setCategoriesWithCollection:function(a){return this.set("categories",a.pluck("id")),this.save()}},n={getAuthorUser:function(){return g(this,this.get("author"),"User","author","name")}},o={getFeaturedImage:function(){return g(this,this.get("featured_image"),"Media","https://api.w.org/featuredmedia","source_url")}};return _.isUndefined(a.prototype.args)?a:(_.each(e,function(b){_.isUndefined(a.prototype.args[b])||(d=!0)}),d&&(a=a.extend(f)),_.isUndefined(a.prototype.args.author)||(a=a.extend(n)),_.isUndefined(a.prototype.args.featured_image)||(a=a.extend(o)),_.isUndefined(a.prototype.args.categories)||(a=a.extend(m)),_.isUndefined(c.collections[b+"Meta"])||(a=a.extend(j)),_.isUndefined(a.prototype.args.tags)||(a=a.extend(l)),_.isUndefined(c.collections[b+"Revisions"])||(a=a.extend(k)),a)}}(window),function(){"use strict";var a=window.wpApiSettings||{};wp.api.WPApiBaseModel=Backbone.Model.extend({sync:function(b,c,d){var e;return d=d||{},_.isNull(c.get("date_gmt"))&&c.unset("date_gmt"),_.isEmpty(c.get("slug"))&&c.unset("slug"),_.isUndefined(a.nonce)||_.isNull(a.nonce)||(e=d.beforeSend,d.beforeSend=function(b){return b.setRequestHeader("X-WP-Nonce",a.nonce),e?e.apply(this,arguments):void 0}),this.requireForceForDelete&&"delete"===b&&(c.url=c.url()+"?force=true"),Backbone.sync(b,c,d)},save:function(a,b){return _.includes(this.methods,"PUT")||_.includes(this.methods,"POST")?Backbone.Model.prototype.save.call(this,a,b):!1},destroy:function(a){return _.includes(this.methods,"DELETE")?Backbone.Model.prototype.destroy.call(this,a):!1}}),wp.api.models.Schema=wp.api.WPApiBaseModel.extend({defaults:{_links:{},namespace:null,routes:{}},initialize:function(b,c){var d=this;c=c||{},wp.api.WPApiBaseModel.prototype.initialize.call(d,b,c),d.apiRoot=c.apiRoot||a.root,d.versionString=c.versionString||a.versionString},url:function(){return this.apiRoot+this.versionString}})}(),function(){"use strict";var a=window.wpApiSettings||{};wp.api.WPApiBaseCollection=Backbone.Collection.extend({initialize:function(a,b){this.state={data:{},currentPage:null,totalPages:null,totalObjects:null},_.isUndefined(b)?this.parent="":this.parent=b.parent},sync:function(b,c,d){var e,f,g=this;return d=d||{},e=d.beforeSend,"undefined"!=typeof a.nonce&&(d.beforeSend=function(b){return b.setRequestHeader("X-WP-Nonce",a.nonce),e?e.apply(g,arguments):void 0}),"read"===b&&(d.data?(g.state.data=_.clone(d.data),delete g.state.data.page):g.state.data=d.data={},"undefined"==typeof d.data.page?(g.state.currentPage=null,g.state.totalPages=null,g.state.totalObjects=null):g.state.currentPage=d.data.page-1,f=d.success,d.success=function(a,b,c){return _.isUndefined(c)||(g.state.totalPages=parseInt(c.getResponseHeader("x-wp-totalpages"),10),g.state.totalObjects=parseInt(c.getResponseHeader("x-wp-total"),10)),null===g.state.currentPage?g.state.currentPage=1:g.state.currentPage++,f?f.apply(this,arguments):void 0}),Backbone.sync(b,c,d)},more:function(a){if(a=a||{},a.data=a.data||{},_.extend(a.data,this.state.data),"undefined"==typeof a.data.page){if(!this.hasMore())return!1;null===this.state.currentPage||this.state.currentPage<=1?a.data.page=2:a.data.page=this.state.currentPage+1}return this.fetch(a)},hasMore:function(){return null===this.state.totalPages||null===this.state.totalObjects||null===this.state.currentPage?null:this.state.currentPage<this.state.totalPages}})}(),function(){"use strict";var a,b={},c=window.wpApiSettings||{};window.wp=window.wp||{},wp.api=wp.api||{},_.isEmpty(c)&&(c.root=window.location.origin+"/wp-json/"),a=Backbone.Model.extend({defaults:{apiRoot:c.root,versionString:wp.api.versionString,schema:null,models:{},collections:{}},initialize:function(){var a,b=this;Backbone.Model.prototype.initialize.apply(b,arguments),a=jQuery.Deferred(),b.schemaConstructed=a.promise(),b.schemaModel=new wp.api.models.Schema(null,{apiRoot:b.get("apiRoot"),versionString:b.get("versionString")}),b.schemaModel.once("change",function(){b.constructFromSchema(),a.resolve(b)}),b.get("schema")?b.schemaModel.set(b.schemaModel.parse(b.get("schema"))):!_.isUndefined(sessionStorage)&&sessionStorage.getItem("wp-api-schema-model"+b.get("apiRoot")+b.get("versionString"))?b.schemaModel.set(b.schemaModel.parse(JSON.parse(sessionStorage.getItem("wp-api-schema-model"+b.get("apiRoot")+b.get("versionString"))))):b.schemaModel.fetch({success:function(a){_.isUndefined(sessionStorage)||sessionStorage.setItem("wp-api-schema-model"+b.get("apiRoot")+b.get("versionString"),JSON.stringify(a))},error:function(){}})},constructFromSchema:function(){var a,b,d,e,f=this,g=c.mapping||{models:{Categories:"Category",Comments:"Comment",Pages:"Page",PagesMeta:"PageMeta",PagesRevisions:"PageRevision",Posts:"Post",PostsCategories:"PostCategory",PostsRevisions:"PostRevision",PostsTags:"PostTag",Schema:"Schema",Statuses:"Status",Tags:"Tag",Taxonomies:"Taxonomy",Types:"Type",Users:"User"},collections:{PagesMeta:"PageMeta",PagesRevisions:"PageRevisions",PostsCategories:"PostCategories",PostsMeta:"PostMeta",PostsRevisions:"PostRevisions",PostsTags:"PostTags"}};a=[],b=[],d=f.get("apiRoot").replace(wp.api.utils.getRootUrl(),""),e={},e.models=f.get("models"),e.collections=f.get("collections"),_.each(f.schemaModel.get("routes"),function(c,e){e!==f.get(" versionString")&&e!==d&&e!=="/"+f.get("versionString").slice(0,-1)&&(/.*[+)|me]$/.test(e)?a.push({index:e,route:c}):b.push({index:e,route:c}))}),_.each(a,function(a){var b,c=wp.api.utils.extractRoutePart(a.index,2),d=wp.api.utils.extractRoutePart(a.index,4),h=wp.api.utils.extractRoutePart(a.index,1);"me"===h&&(c="me"),""!==d&&d!==c?(b=wp.api.utils.capitalize(d)+wp.api.utils.capitalize(c),b=g.models[b]||b,e.models[b]=wp.api.WPApiBaseModel.extend({url:function(){var a=f.get("apiRoot")+f.get("versionString")+d+"/"+(_.isUndefined(this.get("parent"))||0===this.get("parent")?this.get("parent_post"):this.get("parent"))+"/"+c;return _.isUndefined(this.get("id"))||(a+="/"+this.get("id")),a},route:a,name:b,methods:a.route.methods,initialize:function(){"Posts"!==this.name&&"Pages"!==this.name&&_.includes(this.methods,"DELETE")&&(this.requireForceForDelete=!0)}})):(b=wp.api.utils.capitalize(c),b=g.models[b]||b,e.models[b]=wp.api.WPApiBaseModel.extend({url:function(){var a=f.get("apiRoot")+f.get("versionString")+("me"===c?"users/me":c);return _.isUndefined(this.get("id"))||(a+="/"+this.get("id")),a},route:a,name:b,methods:a.route.methods})),wp.api.utils.decorateFromRoute(a.route.endpoints,e.models[b])}),_.each(b,function(a){var b,c,d=a.index.slice(a.index.lastIndexOf("/")+1),h=wp.api.utils.extractRoutePart(a.index,3);""!==h&&h!==d?(b=wp.api.utils.capitalize(h)+wp.api.utils.capitalize(d),c=g.models[b]||b,b=g.collections[b]||b,e.collections[b]=wp.api.WPApiBaseCollection.extend({url:function(){return f.get("apiRoot")+f.get("versionString")+h+"/"+this.parent+"/"+d},model:e.models[c],name:b,route:a,methods:a.route.methods})):(b=wp.api.utils.capitalize(d),c=g.models[b]||b,b=g.collections[b]||b,e.collections[b]=wp.api.WPApiBaseCollection.extend({url:f.get("apiRoot")+f.get("versionString")+d,model:e.models[c],name:b,route:a,methods:a.route.methods})),wp.api.utils.decorateFromRoute(a.route.endpoints,e.collections[b])}),_.each(e.models,function(a,b){e.models[b]=wp.api.utils.addMixinsAndHelpers(a,b,e)})}}),wp.api.endpoints=new Backbone.Collection({model:a}),wp.api.init=function(d){var e,f,g,h={};return d=d||{},h.apiRoot=d.apiRoot||c.root,h.versionString=d.versionString||c.versionString,h.schema=d.schema||null,h.schema||h.apiRoot!==c.root||h.versionString!==c.versionString||(h.schema=c.schema),b[h.apiRoot+h.versionString]||(e=wp.api.endpoints.findWhere({apiRoot:h.apiRoot,versionString:h.versionString}),e||(e=new a(h),wp.api.endpoints.add(e)),f=jQuery.Deferred(),g=f.promise(),e.schemaConstructed.done(function(a){wp.api.models=_.extend(a.get("models"),wp.api.models),wp.api.collections=_.extend(a.get("collections"),wp.api.collections),f.resolveWith(wp.api,[a])}),b[h.apiRoot+h.versionString]=g),b[h.apiRoot+h.versionString]},wp.api.loadPromise=wp.api.init()}();
2
  //# sourceMappingURL=wp-api.min.map
1
+ !function(a,b){"use strict";function c(){this.models={},this.collections={},this.views={}}a.wp=a.wp||{},wp.api=wp.api||new c,wp.api.versionString=wp.api.versionString||"wp/v2/",!_.isFunction(_.includes)&&_.isFunction(_.contains)&&(_.includes=_.contains)}(window),function(a,b){"use strict";var c,d;a.wp=a.wp||{},wp.api=wp.api||{},wp.api.utils=wp.api.utils||{},Date.prototype.toISOString||(c=function(a){return d=String(a),1===d.length&&(d="0"+d),d},Date.prototype.toISOString=function(){return this.getUTCFullYear()+"-"+c(this.getUTCMonth()+1)+"-"+c(this.getUTCDate())+"T"+c(this.getUTCHours())+":"+c(this.getUTCMinutes())+":"+c(this.getUTCSeconds())+"."+String((this.getUTCMilliseconds()/1e3).toFixed(3)).slice(2,5)+"Z"}),wp.api.utils.parseISO8601=function(a){var c,d,e,f,g=0,h=[1,4,5,6,7,10,11];if(d=/^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(a)){for(e=0;f=h[e];++e)d[f]=+d[f]||0;d[2]=(+d[2]||1)-1,d[3]=+d[3]||1,"Z"!==d[8]&&b!==d[9]&&(g=60*d[10]+d[11],"+"===d[9]&&(g=0-g)),c=Date.UTC(d[1],d[2],d[3],d[4],d[5]+g,d[6],d[7])}else c=Date.parse?Date.parse(a):NaN;return c},wp.api.utils.getRootUrl=function(){return a.location.origin?a.location.origin+"/":a.location.protocol+"/"+a.location.host+"/"},wp.api.utils.capitalize=function(a){return _.isUndefined(a)?a:a.charAt(0).toUpperCase()+a.slice(1)},wp.api.utils.extractRoutePart=function(a,b){var c;return b=b||1,a=a.replace(wp.api.versionString,""),c=a.split("/").reverse(),_.isUndefined(c[--b])?"":c[b]},wp.api.utils.extractParentName=function(a){var b,c=a.lastIndexOf("_id>[\\d]+)/");return c<0?"":(b=a.substr(0,c-1),b=b.split("/"),b.pop(),b=b.pop())},wp.api.utils.decorateFromRoute=function(a,b){_.each(a,function(a){_.includes(a.methods,"POST")||_.includes(a.methods,"PUT")?_.isEmpty(a.args)||(_.isEmpty(b.prototype.args)?b.prototype.args=a.args:b.prototype.args=_.union(a.args,b.prototype.defaults)):_.includes(a.methods,"GET")&&(_.isEmpty(a.args)||(_.isEmpty(b.prototype.options)?b.prototype.options=a.args:b.prototype.options=_.union(a.args,b.prototype.options)))})},wp.api.utils.addMixinsAndHelpers=function(a,b,c){var d=!1,e=["date","modified","date_gmt","modified_gmt"],f={toJSON:function(){var a=_.clone(this.attributes);return _.each(e,function(b){b in a&&_.isDate(a[b])&&(a[b]=a[b].toISOString())}),a},parse:function(a){var b;return _.each(e,function(c){c in a&&(_.isNull(a[c])||(b=wp.api.utils.parseISO8601(a[c]),a[c]=new Date(b)))}),a}},g=function(a,b,c,d,e){var f,g,h,i;return i=jQuery.Deferred(),g=a.get("_embedded")||{},_.isNumber(b)&&0!==b?(g[d]&&(h=_.findWhere(g[d],{id:b})),h||(h={id:b}),f=new wp.api.models[c](h),f.get(e)?i.resolve(f):f.fetch({success:function(a){i.resolve(a)}}),i.promise()):(i.reject(),i)},h=function(a,b,c,d){var e,f,g,h="",j="",k=jQuery.Deferred();return e=a.get("id"),f=a.get("_embedded")||{},_.isNumber(e)&&0!==e?(_.isUndefined(c)||_.isUndefined(f[c])?h={parent:e}:j=_.isUndefined(d)?f[c]:f[c][d],g=new wp.api.collections[b](j,h),_.isUndefined(g.models[0])?g.fetch({success:function(a){i(a,e),k.resolve(a)}}):(i(g,e),k.resolve(g)),k.promise()):(k.reject(),k)},i=function(a,b){_.each(a.models,function(a){a.set("parent_post",b)})},j={getMeta:function(){return h(this,"PostMeta","https://api.w.org/meta")}},k={getRevisions:function(){return h(this,"PostRevisions")}},l={getTags:function(){var a=this.get("tags"),b=new wp.api.collections.Tags;return _.isEmpty(a)?jQuery.Deferred().resolve([]):b.fetch({data:{include:a}})},setTags:function(a){var b,c,d=this,e=[];return!_.isString(a)&&void(_.isArray(a)?(b=new wp.api.collections.Tags,b.fetch({data:{per_page:100},success:function(b){_.each(a,function(a){c=new wp.api.models.Tag(b.findWhere({slug:a})),c.set("parent_post",d.get("id")),e.push(c)}),a=new wp.api.collections.Tags(e),d.setTagsWithCollection(a)}})):this.setTagsWithCollection(a))},setTagsWithCollection:function(a){return this.set("tags",a.pluck("id")),this.save()}},m={getCategories:function(){var a=this.get("categories"),b=new wp.api.collections.Categories;return _.isEmpty(a)?jQuery.Deferred().resolve([]):b.fetch({data:{include:a}})},setCategories:function(a){var b,c,d=this,e=[];return!_.isString(a)&&void(_.isArray(a)?(b=new wp.api.collections.Categories,b.fetch({data:{per_page:100},success:function(b){_.each(a,function(a){c=new wp.api.models.Category(b.findWhere({slug:a})),c.set("parent_post",d.get("id")),e.push(c)}),a=new wp.api.collections.Categories(e),d.setCategoriesWithCollection(a)}})):this.setCategoriesWithCollection(a))},setCategoriesWithCollection:function(a){return this.set("categories",a.pluck("id")),this.save()}},n={getAuthorUser:function(){return g(this,this.get("author"),"User","author","name")}},o={getFeaturedMedia:function(){return g(this,this.get("featured_media"),"Media","wp:featuredmedia","source_url")}};return _.isUndefined(a.prototype.args)?a:(_.each(e,function(b){_.isUndefined(a.prototype.args[b])||(d=!0)}),d&&(a=a.extend(f)),_.isUndefined(a.prototype.args.author)||(a=a.extend(n)),_.isUndefined(a.prototype.args.featured_media)||(a=a.extend(o)),_.isUndefined(a.prototype.args.categories)||(a=a.extend(m)),_.isUndefined(c.collections[b+"Meta"])||(a=a.extend(j)),_.isUndefined(a.prototype.args.tags)||(a=a.extend(l)),_.isUndefined(c.collections[b+"Revisions"])||(a=a.extend(k)),a)}}(window),function(){"use strict";var a=window.wpApiSettings||{};wp.api.WPApiBaseModel=Backbone.Model.extend({sync:function(b,c,d){var e;return d=d||{},_.isNull(c.get("date_gmt"))&&c.unset("date_gmt"),_.isEmpty(c.get("slug"))&&c.unset("slug"),_.isUndefined(a.nonce)||_.isNull(a.nonce)||(e=d.beforeSend,d.beforeSend=function(b){if(b.setRequestHeader("X-WP-Nonce",a.nonce),e)return e.apply(this,arguments)}),this.requireForceForDelete&&"delete"===b&&(c.url=c.url()+"?force=true"),Backbone.sync(b,c,d)},save:function(a,b){return!(!_.includes(this.methods,"PUT")&&!_.includes(this.methods,"POST"))&&Backbone.Model.prototype.save.call(this,a,b)},destroy:function(a){return!!_.includes(this.methods,"DELETE")&&Backbone.Model.prototype.destroy.call(this,a)}}),wp.api.models.Schema=wp.api.WPApiBaseModel.extend({defaults:{_links:{},namespace:null,routes:{}},initialize:function(b,c){var d=this;c=c||{},wp.api.WPApiBaseModel.prototype.initialize.call(d,b,c),d.apiRoot=c.apiRoot||a.root,d.versionString=c.versionString||a.versionString},url:function(){return this.apiRoot+this.versionString}})}(),function(){"use strict";var a=window.wpApiSettings||{};wp.api.WPApiBaseCollection=Backbone.Collection.extend({initialize:function(a,b){this.state={data:{},currentPage:null,totalPages:null,totalObjects:null},_.isUndefined(b)?this.parent="":this.parent=b.parent},sync:function(b,c,d){var e,f,g=this;return d=d||{},e=d.beforeSend,"undefined"!=typeof a.nonce&&(d.beforeSend=function(b){if(b.setRequestHeader("X-WP-Nonce",a.nonce),e)return e.apply(g,arguments)}),"read"===b&&(d.data?(g.state.data=_.clone(d.data),delete g.state.data.page):g.state.data=d.data={},"undefined"==typeof d.data.page?(g.state.currentPage=null,g.state.totalPages=null,g.state.totalObjects=null):g.state.currentPage=d.data.page-1,f=d.success,d.success=function(a,b,c){if(_.isUndefined(c)||(g.state.totalPages=parseInt(c.getResponseHeader("x-wp-totalpages"),10),g.state.totalObjects=parseInt(c.getResponseHeader("x-wp-total"),10)),null===g.state.currentPage?g.state.currentPage=1:g.state.currentPage++,f)return f.apply(this,arguments)}),Backbone.sync(b,c,d)},more:function(a){if(a=a||{},a.data=a.data||{},_.extend(a.data,this.state.data),"undefined"==typeof a.data.page){if(!this.hasMore())return!1;null===this.state.currentPage||this.state.currentPage<=1?a.data.page=2:a.data.page=this.state.currentPage+1}return this.fetch(a)},hasMore:function(){return null===this.state.totalPages||null===this.state.totalObjects||null===this.state.currentPage?null:this.state.currentPage<this.state.totalPages}})}(),function(){"use strict";var a,b={},c=window.wpApiSettings||{};window.wp=window.wp||{},wp.api=wp.api||{},_.isEmpty(c)&&(c.root=window.location.origin+"/wp-json/"),a=Backbone.Model.extend({defaults:{apiRoot:c.root,versionString:wp.api.versionString,schema:null,models:{},collections:{}},initialize:function(){var a,b=this;Backbone.Model.prototype.initialize.apply(b,arguments),a=jQuery.Deferred(),b.schemaConstructed=a.promise(),b.schemaModel=new wp.api.models.Schema(null,{apiRoot:b.get("apiRoot"),versionString:b.get("versionString")}),b.schemaModel.once("change",function(){b.constructFromSchema(),a.resolve(b)}),b.get("schema")?b.schemaModel.set(b.schemaModel.parse(b.get("schema"))):!_.isUndefined(sessionStorage)&&(_.isUndefined(c.cacheSchema)||c.cacheSchema)&&sessionStorage.getItem("wp-api-schema-model"+b.get("apiRoot")+b.get("versionString"))?b.schemaModel.set(b.schemaModel.parse(JSON.parse(sessionStorage.getItem("wp-api-schema-model"+b.get("apiRoot")+b.get("versionString"))))):b.schemaModel.fetch({success:function(a){if(!_.isUndefined(sessionStorage)&&c.cacheSchema)try{sessionStorage.setItem("wp-api-schema-model"+b.get("apiRoot")+b.get("versionString"),JSON.stringify(a))}catch(a){}},error:function(a){window.console.log(a)}})},constructFromSchema:function(){var a,b,d,e,f=this,g=c.mapping||{models:{Categories:"Category",Comments:"Comment",Pages:"Page",PagesMeta:"PageMeta",PagesRevisions:"PageRevision",Posts:"Post",PostsCategories:"PostCategory",PostsRevisions:"PostRevision",PostsTags:"PostTag",Schema:"Schema",Statuses:"Status",Tags:"Tag",Taxonomies:"Taxonomy",Types:"Type",Users:"User"},collections:{PagesMeta:"PageMeta",PagesRevisions:"PageRevisions",PostsCategories:"PostCategories",PostsMeta:"PostMeta",PostsRevisions:"PostRevisions",PostsTags:"PostTags"}};a=[],b=[],d=f.get("apiRoot").replace(wp.api.utils.getRootUrl(),""),e={},e.models=f.get("models"),e.collections=f.get("collections"),_.each(f.schemaModel.get("routes"),function(c,e){e!==f.get(" versionString")&&e!==d&&e!=="/"+f.get("versionString").slice(0,-1)&&(/(?:.*[+)]|\/me)$/.test(e)?a.push({index:e,route:c}):b.push({index:e,route:c}))}),_.each(a,function(a){var b,c=wp.api.utils.extractRoutePart(a.index,2),d=wp.api.utils.extractRoutePart(a.index,4),h=wp.api.utils.extractRoutePart(a.index,1);"me"===h&&(c="me"),""!==d&&d!==c?(b=wp.api.utils.capitalize(d)+wp.api.utils.capitalize(c),b=g.models[b]||b,e.models[b]=wp.api.WPApiBaseModel.extend({url:function(){var a=f.get("apiRoot")+f.get("versionString")+d+"/"+(_.isUndefined(this.get("parent"))||0===this.get("parent")?this.get("parent_post"):this.get("parent"))+"/"+c;return _.isUndefined(this.get("id"))||(a+="/"+this.get("id")),a},route:a,name:b,methods:a.route.methods,initialize:function(){"Posts"!==this.name&&"Pages"!==this.name&&_.includes(this.methods,"DELETE")&&(this.requireForceForDelete=!0)}})):(b=wp.api.utils.capitalize(c),b=g.models[b]||b,e.models[b]=wp.api.WPApiBaseModel.extend({url:function(){var a=f.get("apiRoot")+f.get("versionString")+("me"===c?"users/me":c);return _.isUndefined(this.get("id"))||(a+="/"+this.get("id")),a},route:a,name:b,methods:a.route.methods})),wp.api.utils.decorateFromRoute(a.route.endpoints,e.models[b])}),_.each(b,function(a){var b,c,d=a.index.slice(a.index.lastIndexOf("/")+1),h=wp.api.utils.extractRoutePart(a.index,3);""!==h&&h!==d?(b=wp.api.utils.capitalize(h)+wp.api.utils.capitalize(d),c=g.models[b]||b,b=g.collections[b]||b,e.collections[b]=wp.api.WPApiBaseCollection.extend({url:function(){return f.get("apiRoot")+f.get("versionString")+h+"/"+this.parent+"/"+d},model:e.models[c],name:b,route:a,methods:a.route.methods})):(b=wp.api.utils.capitalize(d),c=g.models[b]||b,b=g.collections[b]||b,e.collections[b]=wp.api.WPApiBaseCollection.extend({url:f.get("apiRoot")+f.get("versionString")+d,model:e.models[c],name:b,route:a,methods:a.route.methods})),wp.api.utils.decorateFromRoute(a.route.endpoints,e.collections[b])}),_.each(e.models,function(a,b){e.models[b]=wp.api.utils.addMixinsAndHelpers(a,b,e)})}}),wp.api.endpoints=new Backbone.Collection({model:a}),wp.api.init=function(d){var e,f,g,h={};return d=d||{},h.apiRoot=d.apiRoot||c.root,h.versionString=d.versionString||c.versionString,h.schema=d.schema||null,h.schema||h.apiRoot!==c.root||h.versionString!==c.versionString||(h.schema=c.schema),b[h.apiRoot+h.versionString]||(e=wp.api.endpoints.findWhere({apiRoot:h.apiRoot,versionString:h.versionString}),e||(e=new a(h),wp.api.endpoints.add(e)),f=jQuery.Deferred(),g=f.promise(),e.schemaConstructed.done(function(a){wp.api.models=_.extend(a.get("models"),wp.api.models),wp.api.collections=_.extend(a.get("collections"),wp.api.collections),f.resolveWith(wp.api,[a])}),b[h.apiRoot+h.versionString]=g),b[h.apiRoot+h.versionString]},wp.api.loadPromise=wp.api.init()}();
2
  //# sourceMappingURL=wp-api.min.map
wp-api.min.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../../js/app.js","../../js/utils.js","../../js/models.js","../../js/collections.js","../../js/load.js"],"names":["window","undefined","WP_API","this","models","collections","views","wp","api","versionString","_","isFunction","includes","contains","pad","r","utils","Date","prototype","toISOString","number","String","length","getUTCFullYear","getUTCMonth","getUTCDate","getUTCHours","getUTCMinutes","getUTCSeconds","getUTCMilliseconds","toFixed","slice","parseISO8601","date","timestamp","struct","i","k","minutesOffset","numericKeys","exec","UTC","parse","NaN","getRootUrl","location","origin","protocol","host","capitalize","str","isUndefined","charAt","toUpperCase","extractRoutePart","route","part","routeParts","replace","split","reverse","extractParentName","name","lastSlash","lastIndexOf","substr","pop","decorateFromRoute","routeEndpoints","modelInstance","each","routeEndpoint","methods","isEmpty","args","union","defaults","options","addMixinsAndHelpers","model","modelClassName","loadingObjects","hasDate","parseableDates","TimeStampedMixin","toJSON","attributes","clone","key","isNull","response","buildModelGetter","parentModel","modelId","modelName","embedSourcePoint","embedCheckField","getModel","embeddeds","deferred","jQuery","Deferred","get","isNumber","findWhere","id","resolve","fetch","success","promise","reject","buildCollectionGetter","collectionName","embedIndex","postId","getObjects","classProperties","properties","parent","setHelperParentPost","collection","set","MetaMixin","getMeta","RevisionsMixin","getRevisions","TagsMixin","getTags","tagIds","tags","Tags","data","include","setTags","allTags","newTag","self","newTags","isString","isArray","per_page","alltags","tag","Tag","slug","push","setTagsWithCollection","pluck","save","CategoriesMixin","getCategories","categoryIds","categories","Categories","setCategories","allCategories","newCategory","newCategories","allcats","category","Category","setCategoriesWithCollection","AuthorMixin","getAuthorUser","FeaturedImageMixin","getFeaturedImage","theDateKey","extend","author","featured_image","wpApiSettings","WPApiBaseModel","Backbone","Model","sync","method","beforeSend","unset","nonce","xhr","setRequestHeader","apply","arguments","requireForceForDelete","url","attrs","call","destroy","Schema","_links","namespace","routes","initialize","apiRoot","root","WPApiBaseCollection","Collection","state","currentPage","totalPages","totalObjects","page","textStatus","request","parseInt","getResponseHeader","more","hasMore","Endpoint","initializedDeferreds","schema","schemaConstructed","schemaModel","once","constructFromSchema","sessionStorage","getItem","JSON","newSchemaModel","setItem","stringify","error","modelRoutes","collectionRoutes","schemaRoot","routeModel","mapping","Comments","Pages","PagesMeta","PagesRevisions","Posts","PostsCategories","PostsRevisions","PostsTags","Statuses","Taxonomies","Types","Users","PostsMeta","index","test","modelRoute","routeName","parentName","routeEnd","endpoints","collectionRoute","collectionClassName","init","endpoint","add","done","resolveWith","loadPromise"],"mappings":"CAAA,SAAWA,EAAQC,GAElB,YAEA,SAASC,KACRC,KAAKC,UACLD,KAAKE,eACLF,KAAKG,SAGNN,EAAOO,GAAgBP,EAAOO,OAC9BA,GAAGC,IAAoBD,GAAGC,KAAO,GAAIN,GACrCK,GAAGC,IAAIC,cAAgBF,GAAGC,IAAIC,eAAiB,UAGxCC,EAAEC,WAAYD,EAAEE,WAAcF,EAAEC,WAAYD,EAAEG,YACnDH,EAAEE,SAAWF,EAAEG,WAGdb,QCnBJ,SAAWA,EAAQC,GAElB,YAEA,IAAIa,GAAKC,CAETf,GAAOO,GAAKP,EAAOO,OACnBA,GAAGC,IAAMD,GAAGC,QACZD,GAAGC,IAAIQ,MAAQT,GAAGC,IAAIQ,UAMfC,KAAKC,UAAUC,cACrBL,EAAM,SAAUM,GAMf,MALAL,GAAIM,OAAQD,GACP,IAAML,EAAEO,SACZP,EAAI,IAAMA,GAGJA,GAGRE,KAAKC,UAAUC,YAAc,WAC5B,MAAOhB,MAAKoB,iBACX,IAAMT,EAAKX,KAAKqB,cAAgB,GAChC,IAAMV,EAAKX,KAAKsB,cAChB,IAAMX,EAAKX,KAAKuB,eAChB,IAAMZ,EAAKX,KAAKwB,iBAChB,IAAMb,EAAKX,KAAKyB,iBAChB,IAAMP,QAAUlB,KAAK0B,qBAAuB,KAAOC,QAAS,IAAMC,MAAO,EAAG,GAC5E,MASHxB,GAAGC,IAAIQ,MAAMgB,aAAe,SAAUC,GACrC,GAAIC,GAAWC,EAAQC,EAAGC,EACzBC,EAAgB,EAChBC,GAAgB,EAAG,EAAG,EAAG,EAAG,EAAG,GAAI,GAMpC,IAAOJ,EAAS,qIAAqIK,KAAMP,GAAW,CAGrK,IAAMG,EAAI,EAAKC,EAAIE,EAAYH,KAAQA,EACtCD,EAAOE,IAAMF,EAAOE,IAAM,CAI3BF,GAAO,KAAQA,EAAO,IAAM,GAAM,EAClCA,EAAO,IAAMA,EAAO,IAAM,EAErB,MAAQA,EAAO,IAAOlC,IAAckC,EAAO,KAC/CG,EAA6B,GAAbH,EAAO,IAAWA,EAAO,IAEpC,MAAQA,EAAO,KACnBG,EAAgB,EAAIA,IAItBJ,EAAYjB,KAAKwB,IAAKN,EAAO,GAAIA,EAAO,GAAIA,EAAO,GAAIA,EAAO,GAAIA,EAAO,GAAKG,EAAeH,EAAO,GAAIA,EAAO,QAE/GD,GAAYjB,KAAKyB,MAAQzB,KAAKyB,MAAOT,GAASU,GAG/C,OAAOT,IAOR3B,GAAGC,IAAIQ,MAAM4B,WAAa,WACzB,MAAO5C,GAAO6C,SAASC,OACtB9C,EAAO6C,SAASC,OAAS,IACzB9C,EAAO6C,SAASE,SAAW,IAAM/C,EAAO6C,SAASG,KAAO,KAM1DzC,GAAGC,IAAIQ,MAAMiC,WAAa,SAAUC,GACnC,MAAKxC,GAAEyC,YAAaD,GACZA,EAEDA,EAAIE,OAAQ,GAAIC,cAAgBH,EAAInB,MAAO,IAUnDxB,GAAGC,IAAIQ,MAAMsC,iBAAmB,SAAUC,EAAOC,GAChD,GAAIC,EAOJ,OALAD,GAAQA,GAAQ,EAGhBD,EAAQA,EAAMG,QAASnD,GAAGC,IAAIC,cAAe,IAC7CgD,EAAaF,EAAMI,MAAO,KAAMC,UAC3BlD,EAAEyC,YAAaM,IAAcD,IAC1B,GAEDC,EAAYD,IAQpBjD,GAAGC,IAAIQ,MAAM6C,kBAAoB,SAAUN,GAC1C,GAAIO,GACHC,EAAYR,EAAMS,YAAa,eAEhC,OAAiB,GAAZD,EACG,IAERD,EAAOP,EAAMU,OAAQ,EAAGF,EAAY,GACpCD,EAAOA,EAAKH,MAAO,KACnBG,EAAKI,MACLJ,EAAOA,EAAKI,QAWb3D,GAAGC,IAAIQ,MAAMmD,kBAAoB,SAAUC,EAAgBC,GAK1D3D,EAAE4D,KAAMF,EAAgB,SAAUG,GAG5B7D,EAAEE,SAAU2D,EAAcC,QAAS,SAAY9D,EAAEE,SAAU2D,EAAcC,QAAS,OAG/E9D,EAAE+D,QAASF,EAAcG,QAG1BhE,EAAE+D,QAASJ,EAAcnD,UAAUwD,MACvCL,EAAcnD,UAAUwD,KAAOH,EAAcG,KAI7CL,EAAcnD,UAAUwD,KAAOhE,EAAEiE,MAAOJ,EAAcG,KAAML,EAAcnD,UAAU0D,WAMjFlE,EAAEE,SAAU2D,EAAcC,QAAS,SAGhC9D,EAAE+D,QAASF,EAAcG,QAG1BhE,EAAE+D,QAASJ,EAAcnD,UAAU2D,SACvCR,EAAcnD,UAAU2D,QAAUN,EAAcG,KAIhDL,EAAcnD,UAAU2D,QAAUnE,EAAEiE,MAAOJ,EAAcG,KAAML,EAAcnD,UAAU2D,cAkB7FtE,GAAGC,IAAIQ,MAAM8D,oBAAsB,SAAUC,EAAOC,EAAgBC,GAEnE,GAAIC,IAAU,EAObC,GAAmB,OAAQ,WAAY,WAAY,gBAWnDC,GAMCC,OAAQ,WACP,GAAIC,GAAa5E,EAAE6E,MAAOpF,KAAKmF,WAa/B,OAVA5E,GAAE4D,KAAMa,EAAgB,SAAUK,GAC5BA,IAAOF,KAGJ5E,EAAE+E,OAAQH,EAAYE,MAC5BF,EAAYE,GAAQF,EAAYE,GAAMrE,kBAKlCmE,GASR5C,MAAO,SAAUgD,GAChB,GAAIxD,EAeJ,OAZAxB,GAAE4D,KAAMa,EAAgB,SAAUK,GACxBA,IAAOE,KAKThF,EAAE+E,OAAQC,EAAUF,MAC1BtD,EAAY3B,GAAGC,IAAIQ,MAAMgB,aAAc0D,EAAUF,IACjDE,EAAUF,GAAQ,GAAIvE,MAAMiB,OAIvBwD,IAeTC,EAAmB,SAAUC,EAAaC,EAASC,EAAWC,EAAkBC,GAC/E,GAAIC,GAAUC,EAAWZ,EAAYa,CAMrC,OAJAA,GAAYC,OAAOC,WACnBH,EAAYN,EAAYU,IAAK,iBAGtB5F,EAAE6F,SAAUV,IAMdK,EAAWH,KACfT,EAAa5E,EAAE8F,UAAWN,EAAWH,IAAsBU,GAAIZ,KAIzDP,IACNA,GAAemB,GAAIZ,IAIpBI,EAAW,GAAI1F,IAAGC,IAAIJ,OAAQ0F,GAAaR,GAGpCW,EAASK,IAAKN,GAKpBG,EAASO,QAAST,GAJlBA,EAASU,OAASC,QAAS,SAAUX,GACpCE,EAASO,QAAST,MAObE,EAASU,YA3BfV,EAASW,SACFX,IAuCTY,EAAwB,SAAUnB,EAAaoB,EAAgBjB,EAAkBkB,GAUhF,GAAIC,GAAQhB,EAAWiB,EACtBC,EAAkB,GAClBC,EAAkB,GAClBlB,EAAkBC,OAAOC,UAM1B,OAJAa,GAAYtB,EAAYU,IAAK,MAC7BJ,EAAYN,EAAYU,IAAK,iBAGtB5F,EAAE6F,SAAUW,IAAY,IAAMA,GAM9BxG,EAAEyC,YAAa4C,IAAwBrF,EAAEyC,YAAa+C,EAAWH,IAevEqB,GAAoBE,OAAQJ,GAT3BG,EAHI3G,EAAEyC,YAAa8D,GAGNf,EAAWH,GAIXG,EAAWH,GAAoBkB,GAS9CE,EAAa,GAAI5G,IAAGC,IAAIH,YAAa2G,GAAkBK,EAAYD,GAG9D1G,EAAEyC,YAAagE,EAAW/G,OAAO,IACrC+G,EAAWR,OAASC,QAAS,SAAUO,GAGtCI,EAAqBJ,EAAYD,GACjCf,EAASO,QAASS,OAKnBI,EAAqBJ,EAAYD,GACjCf,EAASO,QAASS,IAIZhB,EAASU,YA1CfV,EAASW,SACFX,IAgDToB,EAAsB,SAAUC,EAAYN,GAG3CxG,EAAE4D,KAAMkD,EAAWpH,OAAQ,SAAU2E,GACpCA,EAAM0C,IAAK,cAAeP,MAO5BQ,GACCC,QAAS,WACR,MAAOZ,GAAuB5G,KAAM,WAAY,4BAOlDyH,GACCC,aAAc,WACb,MAAOd,GAAuB5G,KAAM,mBAOtC2H,GAOCC,QAAS,WACR,GAAIC,GAAS7H,KAAKmG,IAAK,QACtB2B,EAAQ,GAAI1H,IAAGC,IAAIH,YAAY6H,IAGhC,OAAKxH,GAAE+D,QAASuD,GACR5B,OAAOC,WAAWK,YAGnBuB,EAAKtB,OAASwB,MAAQC,QAASJ,MAWvCK,QAAS,SAAUJ,GAClB,GAAIK,GAASC,EACZC,EAAOrI,KACPsI,IAED,OAAK/H,GAAEgI,SAAUT,IACT,OAIHvH,EAAEiI,QAASV,IAGfK,EAAU,GAAI/H,IAAGC,IAAIH,YAAY6H,KACjCI,EAAQ3B,OACPwB,MAAWS,SAAU,KACrBhC,QAAS,SAAUiC,GAGlBnI,EAAE4D,KAAM2D,EAAM,SAAUa,GACvBP,EAAS,GAAIhI,IAAGC,IAAIJ,OAAO2I,IAAKF,EAAQrC,WAAawC,KAAMF,KAG3DP,EAAOd,IAAK,cAAee,EAAKlC,IAAK,OAGrCmC,EAAQQ,KAAMV,KAEfN,EAAO,GAAI1H,IAAGC,IAAIH,YAAY6H,KAAMO,GACpCD,EAAKU,sBAAuBjB,OAK9B9H,KAAK+I,sBAAuBjB,KAY9BiB,sBAAuB,SAAUjB,GAIhC,MADA9H,MAAKsH,IAAK,OAAQQ,EAAKkB,MAAO,OACvBhJ,KAAKiJ,SAOdC,GAOCC,cAAe,WACd,GAAIC,GAAcpJ,KAAKmG,IAAK,cAC3BkD,EAAc,GAAIjJ,IAAGC,IAAIH,YAAYoJ,UAGtC,OAAK/I,GAAE+D,QAAS8E,GACRnD,OAAOC,WAAWK,YAGnB8C,EAAW7C,OAASwB,MAAQC,QAASmB,MAW7CG,cAAe,SAAUF,GACxB,GAAIG,GAAeC,EAClBpB,EAAOrI,KACP0J,IAED,OAAKnJ,GAAEgI,SAAUc,IACT,OAIH9I,EAAEiI,QAASa,IAGfG,EAAgB,GAAIpJ,IAAGC,IAAIH,YAAYoJ,WACvCE,EAAchD,OACbwB,MAAWS,SAAU,KACrBhC,QAAS,SAAUkD,GAGlBpJ,EAAE4D,KAAMkF,EAAY,SAAUO,GAC7BH,EAAc,GAAIrJ,IAAGC,IAAIJ,OAAO4J,SAAUF,EAAQtD,WAAawC,KAAMe,KAGrEH,EAAYnC,IAAK,cAAee,EAAKlC,IAAK,OAG1CuD,EAAcZ,KAAMW,KAErBJ,EAAa,GAAIjJ,IAAGC,IAAIH,YAAYoJ,WAAYI,GAChDrB,EAAKyB,4BAA6BT,OAKpCrJ,KAAK8J,4BAA6BT,KAapCS,4BAA6B,SAAUT,GAItC,MADArJ,MAAKsH,IAAK,aAAc+B,EAAWL,MAAO,OACnChJ,KAAKiJ,SAOdc,GACCC,cAAe,WACd,MAAOxE,GAAkBxF,KAAMA,KAAKmG,IAAK,UAAY,OAAQ,SAAU,UAOzE8D,GACCC,iBAAkB,WACjB,MAAO1E,GAAkBxF,KAAMA,KAAKmG,IAAK,kBAAoB,QAAS,kCAAmC,eAK5G,OAAK5F,GAAEyC,YAAa4B,EAAM7D,UAAUwD,MAC5BK,GAIRrE,EAAE4D,KAAMa,EAAgB,SAAUmF,GAC1B5J,EAAEyC,YAAa4B,EAAM7D,UAAUwD,KAAM4F,MAC3CpF,GAAU,KAKPA,IACJH,EAAQA,EAAMwF,OAAQnF,IAIhB1E,EAAEyC,YAAa4B,EAAM7D,UAAUwD,KAAK8F,UAC1CzF,EAAQA,EAAMwF,OAAQL,IAIhBxJ,EAAEyC,YAAa4B,EAAM7D,UAAUwD,KAAK+F,kBAC1C1F,EAAQA,EAAMwF,OAAQH,IAIhB1J,EAAEyC,YAAa4B,EAAM7D,UAAUwD,KAAK8E,cAC1CzE,EAAQA,EAAMwF,OAAQlB,IAIhB3I,EAAEyC,YAAa8B,EAAe5E,YAAa2E,EAAiB,WAClED,EAAQA,EAAMwF,OAAQ7C,IAIhBhH,EAAEyC,YAAa4B,EAAM7D,UAAUwD,KAAKuD,QAC1ClD,EAAQA,EAAMwF,OAAQzC,IAIhBpH,EAAEyC,YAAa8B,EAAe5E,YAAa2E,EAAiB,gBAClED,EAAQA,EAAMwF,OAAQ3C,IAGhB7C,KAGL/E,QC9oBJ,WAEC,YAEA,IAAI0K,GAAgB1K,OAAO0K,iBAK3BnK,IAAGC,IAAImK,eAAiBC,SAASC,MAAMN,QAWrCO,KAAM,SAAUC,EAAQhG,EAAOF,GAC9B,GAAImG,EAiCJ,OA/BAnG,GAAUA,MAGLnE,EAAE+E,OAAQV,EAAMuB,IAAK,cACzBvB,EAAMkG,MAAO,YAITvK,EAAE+D,QAASM,EAAMuB,IAAK,UAC1BvB,EAAMkG,MAAO,QAGPvK,EAAEyC,YAAauH,EAAcQ,QAAaxK,EAAE+E,OAAQiF,EAAcQ,SACxEF,EAAanG,EAAQmG,WAKrBnG,EAAQmG,WAAa,SAAUG,GAG9B,MAFAA,GAAIC,iBAAkB,aAAcV,EAAcQ,OAE7CF,EACGA,EAAWK,MAAOlL,KAAMmL,WADhC,SAOGnL,KAAKoL,uBAAyB,WAAaR,IAC/ChG,EAAMyG,IAAMzG,EAAMyG,MAAQ,eAEpBZ,SAASE,KAAMC,EAAQhG,EAAOF,IAMtCuE,KAAM,SAAUqC,EAAO5G,GAGtB,MAAKnE,GAAEE,SAAUT,KAAKqE,QAAS,QAAW9D,EAAEE,SAAUT,KAAKqE,QAAS,QAG5DoG,SAASC,MAAM3J,UAAUkI,KAAKsC,KAAMvL,KAAMsL,EAAO5G,IAIjD,GAOT8G,QAAS,SAAU9G,GAGlB,MAAKnE,GAAEE,SAAUT,KAAKqE,QAAS,UAGvBoG,SAASC,MAAM3J,UAAUyK,QAAQD,KAAMvL,KAAM0E,IAI7C,KAUXtE,GAAGC,IAAIJ,OAAOwL,OAASrL,GAAGC,IAAImK,eAAeJ,QAG3C3F,UACCiH,UACAC,UAAW,KACXC,WAGDC,WAAY,SAAU1G,EAAYT,GACjC,GAAIE,GAAQ5E,IACZ0E,GAAUA,MAEVtE,GAAGC,IAAImK,eAAezJ,UAAU8K,WAAWN,KAAM3G,EAAOO,EAAYT,GAEpEE,EAAMkH,QAAUpH,EAAQoH,SAAWvB,EAAcwB,KACjDnH,EAAMtE,cAAgBoE,EAAQpE,eAAiBiK,EAAcjK,eAG9D+K,IAAK,WACJ,MAAOrL,MAAK8L,QAAU9L,KAAKM,oBCzH/B,WAEC,YAEA,IAAIiK,GAAgB1K,OAAO0K,iBAK3BnK,IAAGC,IAAI2L,oBAAsBvB,SAASwB,WAAW7B,QAO/CyB,WAAY,SAAU5L,EAAQyE,GAC7B1E,KAAKkM,OACJlE,QACAmE,YAAa,KACbC,WAAY,KACZC,aAAc,MAEV9L,EAAEyC,YAAa0B,GACnB1E,KAAKmH,OAAS,GAEdnH,KAAKmH,OAASzC,EAAQyC,QAcxBwD,KAAM,SAAUC,EAAQhG,EAAOF,GAC9B,GAAImG,GAAYpE,EACf4B,EAAOrI,IAmDR,OAjDA0E,GAAaA,MACbmG,EAAanG,EAAQmG,WAEhB,mBAAuBN,GAAcQ,QACzCrG,EAAQmG,WAAa,SAAUG,GAG9B,MAFAA,GAAIC,iBAAkB,aAAcV,EAAcQ,OAE7CF,EACGA,EAAWK,MAAO7C,EAAM8C,WADhC,SAMG,SAAWP,IACVlG,EAAQsD,MACZK,EAAK6D,MAAMlE,KAAOzH,EAAE6E,MAAOV,EAAQsD,YAE5BK,GAAK6D,MAAMlE,KAAKsE,MAEvBjE,EAAK6D,MAAMlE,KAAOtD,EAAQsD,QAGtB,mBAAuBtD,GAAQsD,KAAKsE,MACxCjE,EAAK6D,MAAMC,YAAc,KACzB9D,EAAK6D,MAAME,WAAa,KACxB/D,EAAK6D,MAAMG,aAAe,MAE1BhE,EAAK6D,MAAMC,YAAczH,EAAQsD,KAAKsE,KAAO,EAG9C7F,EAAU/B,EAAQ+B,QAClB/B,EAAQ+B,QAAU,SAAUuB,EAAMuE,EAAYC,GAY7C,MAXOjM,GAAEyC,YAAawJ,KACrBnE,EAAK6D,MAAME,WAAaK,SAAUD,EAAQE,kBAAmB,mBAAqB,IAClFrE,EAAK6D,MAAMG,aAAeI,SAAUD,EAAQE,kBAAmB,cAAgB,KAG3E,OAASrE,EAAK6D,MAAMC,YACxB9D,EAAK6D,MAAMC,YAAc,EAEzB9D,EAAK6D,MAAMC,cAGP1F,EACGA,EAAQyE,MAAOlL,KAAMmL,WAD7B,SAMKV,SAASE,KAAMC,EAAQhG,EAAOF,IAStCiI,KAAM,SAAUjI,GAMf,GALAA,EAAUA,MACVA,EAAQsD,KAAOtD,EAAQsD,SAEvBzH,EAAE6J,OAAQ1F,EAAQsD,KAAMhI,KAAKkM,MAAMlE,MAE9B,mBAAuBtD,GAAQsD,KAAKsE,KAAO,CAC/C,IAAOtM,KAAK4M,UACX,OAAO,CAGH,QAAS5M,KAAKkM,MAAMC,aAAenM,KAAKkM,MAAMC,aAAe,EACjEzH,EAAQsD,KAAKsE,KAAO,EAEpB5H,EAAQsD,KAAKsE,KAAOtM,KAAKkM,MAAMC,YAAc,EAI/C,MAAOnM,MAAKwG,MAAO9B,IAQpBkI,QAAS,WACR,MAAK,QAAS5M,KAAKkM,MAAME,YACvB,OAASpM,KAAKkM,MAAMG,cACpB,OAASrM,KAAKkM,MAAMC,YACd,KAEEnM,KAAKkM,MAAMC,YAAcnM,KAAKkM,MAAME,iBCtIlD,WAEC,YAEA,IAAIS,GAAUC,KACbvC,EAAgB1K,OAAO0K,iBACxB1K,QAAOO,GAAKP,OAAOO,OACnBA,GAAGC,IAASD,GAAGC,QAEVE,EAAE+D,QAASiG,KACfA,EAAcwB,KAAOlM,OAAO6C,SAASC,OAAS,aAG/CkK,EAAWpC,SAASC,MAAMN,QACzB3F,UACCqH,QAASvB,EAAcwB,KACvBzL,cAAeF,GAAGC,IAAIC,cACtByM,OAAQ,KACR9M,UACAC,gBAGD2L,WAAY,WACX,GAAkB7F,GAAdpB,EAAQ5E,IAEZyK,UAASC,MAAM3J,UAAU8K,WAAWX,MAAOtG,EAAOuG,WAElDnF,EAAWC,OAAOC,WAClBtB,EAAMoI,kBAAoBhH,EAASU,UAEnC9B,EAAMqI,YAAc,GAAI7M,IAAGC,IAAIJ,OAAOwL,OAAQ,MAC7CK,QAASlH,EAAMuB,IAAK,WACpB7F,cAAesE,EAAMuB,IAAK,mBAG3BvB,EAAMqI,YAAYC,KAAM,SAAU,WACjCtI,EAAMuI,sBACNnH,EAASO,QAAS3B,KAGdA,EAAMuB,IAAK,UAGfvB,EAAMqI,YAAY3F,IAAK1C,EAAMqI,YAAY1K,MAAOqC,EAAMuB,IAAK,aAC9C5F,EAAEyC,YAAaoK,iBAAoBA,eAAeC,QAAS,sBAAwBzI,EAAMuB,IAAK,WAAcvB,EAAMuB,IAAK,kBAGpIvB,EAAMqI,YAAY3F,IAAK1C,EAAMqI,YAAY1K,MAAO+K,KAAK/K,MAAO6K,eAAeC,QAAS,sBAAwBzI,EAAMuB,IAAK,WAAcvB,EAAMuB,IAAK,qBAEhJvB,EAAMqI,YAAYzG,OAMjBC,QAAS,SAAU8G,GAGXhN,EAAEyC,YAAaoK,iBACrBA,eAAeI,QAAS,sBAAwB5I,EAAMuB,IAAK,WAAcvB,EAAMuB,IAAK,iBAAmBmH,KAAKG,UAAWF,KAKzHG,MAAO,gBAMVP,oBAAqB,WACpB,GAAuBQ,GAAaC,EAAkBC,EAAY/I,EAA9DgJ,EAAa9N,KASjB+N,EAAUxD,EAAcwD,UACvB9N,QACCqJ,WAAmB,WACnB0E,SAAmB,UACnBC,MAAmB,OACnBC,UAAmB,WACnBC,eAAmB,eACnBC,MAAmB,OACnBC,gBAAmB,eACnBC,eAAmB,eACnBC,UAAmB,UACnB9C,OAAmB,SACnB+C,SAAmB,SACnBzG,KAAmB,MACnB0G,WAAmB,WACnBC,MAAmB,OACnBC,MAAmB,QAEpBzO,aACCgO,UAAmB,WACnBC,eAAmB,gBACnBE,gBAAmB,iBACnBO,UAAmB,WACnBN,eAAmB,gBACnBC,UAAmB,YAQrBZ,MACAC,KACAC,EAA6BC,EAAW3H,IAAK,WAAY5C,QAASnD,GAAGC,IAAIQ,MAAM4B,aAAc,IAC7FqC,KAKAA,EAAe7E,OAAc6N,EAAW3H,IAAK,UAC7CrB,EAAe5E,YAAc4N,EAAW3H,IAAK,eAE7C5F,EAAE4D,KAAM2J,EAAWb,YAAY9G,IAAK,UAAY,SAAU/C,EAAOyL,GAG3DA,IAAUf,EAAW3H,IAAK,mBAC7B0I,IAAUhB,GACVgB,IAAY,IAAMf,EAAW3H,IAAK,iBAAkBvE,MAAO,EAAG,MAI1D,aAAakN,KAAMD,GACvBlB,EAAY7E,MAAQ+F,MAAOA,EAAOzL,MAAOA,IAIzCwK,EAAiB9E,MAAQ+F,MAAOA,EAAOzL,MAAOA,OAUjD7C,EAAE4D,KAAMwJ,EAAa,SAAUoB,GAG9B,GAAIlK,GACFmK,EAAa5O,GAAGC,IAAIQ,MAAMsC,iBAAkB4L,EAAWF,MAAO,GAC9DI,EAAa7O,GAAGC,IAAIQ,MAAMsC,iBAAkB4L,EAAWF,MAAO,GAC9DK,EAAa9O,GAAGC,IAAIQ,MAAMsC,iBAAkB4L,EAAWF,MAAO,EAG3D,QAASK,IACbF,EAAY,MAIR,KAAOC,GAAcA,IAAeD,GACxCnK,EAAiBzE,GAAGC,IAAIQ,MAAMiC,WAAYmM,GAAe7O,GAAGC,IAAIQ,MAAMiC,WAAYkM,GAClFnK,EAAiBkJ,EAAQ9N,OAAQ4E,IAAoBA,EACrDC,EAAe7E,OAAQ4E,GAAmBzE,GAAGC,IAAImK,eAAeJ,QAG/DiB,IAAK,WACJ,GAAIA,GAAMyC,EAAW3H,IAAK,WAAc2H,EAAW3H,IAAK,iBACtD8I,EAAc,KACV1O,EAAEyC,YAAahD,KAAKmG,IAAK,YAAgB,IAAMnG,KAAKmG,IAAK,UAC5DnG,KAAKmG,IAAK,eACVnG,KAAKmG,IAAK,WAAe,IAC1B6I,CAIF,OAHOzO,GAAEyC,YAAahD,KAAKmG,IAAK,SAC/BkF,GAAQ,IAAMrL,KAAKmG,IAAK,OAElBkF,GAIRjI,MAAO2L,EAGPpL,KAAMkB,EAGNR,QAAS0K,EAAW3L,MAAMiB,QAE1BwH,WAAY,WAQV,UAAY7L,KAAK2D,MACjB,UAAY3D,KAAK2D,MACjBpD,EAAEE,SAAUT,KAAKqE,QAAS,YAE1BrE,KAAKoL,uBAAwB,QAOhCvG,EAAiBzE,GAAGC,IAAIQ,MAAMiC,WAAYkM,GAC1CnK,EAAiBkJ,EAAQ9N,OAAQ4E,IAAoBA,EACrDC,EAAe7E,OAAQ4E,GAAmBzE,GAAGC,IAAImK,eAAeJ,QAG/DiB,IAAK,WACJ,GAAIA,GAAMyC,EAAW3H,IAAK,WACzB2H,EAAW3H,IAAK,kBACZ,OAAS6I,EAAc,WAAaA,EAKzC,OAHOzO,GAAEyC,YAAahD,KAAKmG,IAAK,SAC/BkF,GAAQ,IAAMrL,KAAKmG,IAAK,OAElBkF,GAIRjI,MAAO2L,EAGPpL,KAAMkB,EAGNR,QAAS0K,EAAW3L,MAAMiB,WAK5BjE,GAAGC,IAAIQ,MAAMmD,kBAAmB+K,EAAW3L,MAAM+L,UAAWrK,EAAe7E,OAAQ4E,MASpFtE,EAAE4D,KAAMyJ,EAAkB,SAAUwB,GAGnC,GAAIC,GAAqBxK,EACvBmK,EAAaI,EAAgBP,MAAMjN,MAAOwN,EAAgBP,MAAMhL,YAAa,KAAQ,GACrFoL,EAAa7O,GAAGC,IAAIQ,MAAMsC,iBAAkBiM,EAAgBP,MAAO,EAGhE,MAAOI,GAAcA,IAAeD,GAExCK,EAAsBjP,GAAGC,IAAIQ,MAAMiC,WAAYmM,GAAe7O,GAAGC,IAAIQ,MAAMiC,WAAYkM,GACvFnK,EAAsBkJ,EAAQ9N,OAAQoP,IAAyBA,EAC/DA,EAAsBtB,EAAQ7N,YAAamP,IAAyBA,EACpEvK,EAAe5E,YAAamP,GAAwBjP,GAAGC,IAAI2L,oBAAoB5B,QAG9EiB,IAAK,WACJ,MAAOyC,GAAW3H,IAAK,WAAc2H,EAAW3H,IAAK,iBACnD8I,EAAa,IAAMjP,KAAKmH,OAAS,IACjC6H,GAIHpK,MAAOE,EAAe7E,OAAQ4E,GAG9BlB,KAAM0L,EAGNjM,MAAOgM,EAGP/K,QAAS+K,EAAgBhM,MAAMiB,YAKhCgL,EAAsBjP,GAAGC,IAAIQ,MAAMiC,WAAYkM,GAC/CnK,EAAsBkJ,EAAQ9N,OAAQoP,IAAyBA,EAC/DA,EAAsBtB,EAAQ7N,YAAamP,IAAyBA,EACpEvK,EAAe5E,YAAamP,GAAwBjP,GAAGC,IAAI2L,oBAAoB5B,QAG9EiB,IAAKyC,EAAW3H,IAAK,WAAc2H,EAAW3H,IAAK,iBAAoB6I,EAGvEpK,MAAOE,EAAe7E,OAAQ4E,GAG9BlB,KAAM0L,EAGNjM,MAAOgM,EAGP/K,QAAS+K,EAAgBhM,MAAMiB,WAKjCjE,GAAGC,IAAIQ,MAAMmD,kBAAmBoL,EAAgBhM,MAAM+L,UAAWrK,EAAe5E,YAAamP,MAI9F9O,EAAE4D,KAAMW,EAAe7E,OAAQ,SAAU2E,EAAOiK,GAC/C/J,EAAe7E,OAAQ4O,GAAUzO,GAAGC,IAAIQ,MAAM8D,oBAAqBC,EAAOiK,EAAO/J,QAOpF1E,GAAGC,IAAI8O,UAAY,GAAI1E,UAASwB,YAC/BrH,MAAOiI,IAWRzM,GAAGC,IAAIiP,KAAO,SAAU/K,GACvB,GAAIgL,GAA2BvJ,EAAUU,EAA3BvB,IA4Bd,OA1BAZ,GAAOA,MACPY,EAAW2G,QAAUvH,EAAKuH,SAAWvB,EAAcwB,KACnD5G,EAAW7E,cAAgBiE,EAAKjE,eAAiBiK,EAAcjK,cAC/D6E,EAAW4H,OAASxI,EAAKwI,QAAU,KAC5B5H,EAAW4H,QAAU5H,EAAW2G,UAAYvB,EAAcwB,MAAQ5G,EAAW7E,gBAAkBiK,EAAcjK,gBACnH6E,EAAW4H,OAASxC,EAAcwC,QAG5BD,EAAsB3H,EAAW2G,QAAU3G,EAAW7E,iBAC5DiP,EAAWnP,GAAGC,IAAI8O,UAAU9I,WAAayF,QAAS3G,EAAW2G,QAASxL,cAAe6E,EAAW7E,gBACzFiP,IACNA,EAAW,GAAI1C,GAAU1H,GACzB/E,GAAGC,IAAI8O,UAAUK,IAAKD,IAEvBvJ,EAAWC,OAAOC,WAClBQ,EAAUV,EAASU,UAEnB6I,EAASvC,kBAAkByC,KAAM,SAAUF,GAG1CnP,GAAGC,IAAIJ,OAAcM,EAAE6J,OAAQmF,EAASpJ,IAAK,UAAY/F,GAAGC,IAAIJ,QAChEG,GAAGC,IAAIH,YAAcK,EAAE6J,OAAQmF,EAASpJ,IAAK,eAAiB/F,GAAGC,IAAIH,aACrE8F,EAAS0J,YAAatP,GAAGC,KAAOkP,MAEjCzC,EAAsB3H,EAAW2G,QAAU3G,EAAW7E,eAAkBoG,GAElEoG,EAAsB3H,EAAW2G,QAAU3G,EAAW7E,gBAQ9DF,GAAGC,IAAIsP,YAAcvP,GAAGC,IAAIiP","file":"wp-api.min.js"}
1
+ {"version":3,"sources":["../../js/app.js","../../js/utils.js","../../js/models.js","../../js/collections.js","../../js/load.js"],"names":["window","undefined","WP_API","this","models","collections","views","wp","api","versionString","_","isFunction","includes","contains","pad","r","utils","Date","prototype","toISOString","number","String","length","getUTCFullYear","getUTCMonth","getUTCDate","getUTCHours","getUTCMinutes","getUTCSeconds","getUTCMilliseconds","toFixed","slice","parseISO8601","date","timestamp","struct","i","k","minutesOffset","numericKeys","exec","UTC","parse","NaN","getRootUrl","location","origin","protocol","host","capitalize","str","isUndefined","charAt","toUpperCase","extractRoutePart","route","part","routeParts","replace","split","reverse","extractParentName","name","lastSlash","lastIndexOf","substr","pop","decorateFromRoute","routeEndpoints","modelInstance","each","routeEndpoint","methods","isEmpty","args","union","defaults","options","addMixinsAndHelpers","model","modelClassName","loadingObjects","hasDate","parseableDates","TimeStampedMixin","toJSON","attributes","clone","key","isDate","response","isNull","buildModelGetter","parentModel","modelId","modelName","embedSourcePoint","embedCheckField","getModel","embeddeds","deferred","jQuery","Deferred","get","isNumber","findWhere","id","resolve","fetch","success","promise","reject","buildCollectionGetter","collectionName","embedIndex","postId","getObjects","classProperties","properties","parent","setHelperParentPost","collection","set","MetaMixin","getMeta","RevisionsMixin","getRevisions","TagsMixin","getTags","tagIds","tags","Tags","data","include","setTags","allTags","newTag","self","newTags","isString","isArray","per_page","alltags","tag","Tag","slug","push","setTagsWithCollection","pluck","save","CategoriesMixin","getCategories","categoryIds","categories","Categories","setCategories","allCategories","newCategory","newCategories","allcats","category","Category","setCategoriesWithCollection","AuthorMixin","getAuthorUser","FeaturedMediaMixin","getFeaturedMedia","theDateKey","extend","author","featured_media","wpApiSettings","WPApiBaseModel","Backbone","Model","sync","method","beforeSend","unset","nonce","xhr","setRequestHeader","apply","arguments","requireForceForDelete","url","attrs","call","destroy","Schema","_links","namespace","routes","initialize","apiRoot","root","WPApiBaseCollection","Collection","state","currentPage","totalPages","totalObjects","page","textStatus","request","parseInt","getResponseHeader","more","hasMore","Endpoint","initializedDeferreds","schema","schemaConstructed","schemaModel","once","constructFromSchema","sessionStorage","cacheSchema","getItem","JSON","newSchemaModel","setItem","stringify","error","err","console","log","modelRoutes","collectionRoutes","schemaRoot","routeModel","mapping","Comments","Pages","PagesMeta","PagesRevisions","Posts","PostsCategories","PostsRevisions","PostsTags","Statuses","Taxonomies","Types","Users","PostsMeta","index","test","modelRoute","routeName","parentName","routeEnd","endpoints","collectionRoute","collectionClassName","init","endpoint","add","done","resolveWith","loadPromise"],"mappings":"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","file":"wp-api.min.js"}