Version Description
Download this release
Release Info
Developer | danielbachhuber |
Plugin | WordPress REST API (Version 2) |
Version | 2.0-beta3.1 |
Comparing to | |
See all releases |
Code changes from version 2.0-beta4.1 to 2.0-beta3.1
- CHANGELOG.md +1 -234
- README.md +0 -4
- extras.php +1 -2
- lib/endpoints/class-wp-rest-attachments-controller.php +8 -26
- lib/endpoints/class-wp-rest-comments-controller.php +101 -43
- lib/endpoints/class-wp-rest-meta-controller.php +18 -15
- lib/endpoints/class-wp-rest-post-statuses-controller.php +9 -10
- lib/endpoints/class-wp-rest-post-types-controller.php +12 -13
- lib/endpoints/class-wp-rest-posts-controller.php +32 -44
- lib/endpoints/class-wp-rest-posts-terms-controller.php +9 -8
- lib/endpoints/class-wp-rest-revisions-controller.php +11 -12
- lib/endpoints/class-wp-rest-taxonomies-controller.php +12 -15
- lib/endpoints/class-wp-rest-terms-controller.php +34 -30
- lib/endpoints/class-wp-rest-users-controller.php +36 -52
- lib/infrastructure/class-wp-rest-request.php +1 -1
- lib/infrastructure/class-wp-rest-server.php +58 -189
- plugin.php +30 -82
- readme.txt +3 -521
- wp-api.js +296 -222
CHANGELOG.md
CHANGED
@@ -1,244 +1,11 @@
|
|
1 |
# Changelog
|
2 |
|
3 |
-
## 2.0 Beta
|
4 |
|
5 |
- Ensure media of private posts are private too.
|
6 |
|
7 |
Reported by @danielbachhuber on 2016-01-08.
|
8 |
|
9 |
-
## 2.0 Beta 4.0
|
10 |
-
|
11 |
-
- Show public user information through the user controller.
|
12 |
-
|
13 |
-
In WordPress as of [r32683](https://core.trac.wordpress.org/changeset/32683) (scheduled for 4.3), `WP_User_Query` now has support for getting users with published posts.
|
14 |
-
|
15 |
-
To match current behaviour in WordPress themes and feeds, we now expose this public user information. This includes the avatar, description, user ID, custom URL, display name, and URL, for users who have published at least one post on the site. This information is available to all clients; other fields and data for all users are still only available when authenticated.
|
16 |
-
|
17 |
-
(props @joehoyle, @rmccue, @Shelob9, [#1397][gh-1397], [#839][gh-839], [#1435][gh-1435])
|
18 |
-
|
19 |
-
- Send schema in OPTIONS requests and index.
|
20 |
-
|
21 |
-
Rather than using separate `/schema` endpoints, the schema for items is now available through an OPTIONS request to the route. This means that full documentation is now available for endpoints through an OPTIONS request; this includes available methods, what data you can pass to the endpoint, and the data you'll get back.
|
22 |
-
|
23 |
-
This data is now also available in the main index and namespace indexes. Simply request the index with `context=help` to get full schema data. Warning: this response will be huge. The schema for single endpoints is also available in the collection's OPTIONS response.
|
24 |
-
|
25 |
-
**⚠️ This breaks backwards compatibility** for clients relying on schemas being at their own routes. These clients should instead send `OPTIONS` requests.
|
26 |
-
|
27 |
-
Custom endpoints can register their own schema via the `schema` option on the route. This option should live side-by-side with the endpoints (similar to `relation` in WP's meta queries), so your registration call will look something like:
|
28 |
-
|
29 |
-
```php
|
30 |
-
register_rest_route( 'test-ns', '/test', array(
|
31 |
-
array(
|
32 |
-
'methods' => 'GET',
|
33 |
-
'callback' => 'my_test_callback',
|
34 |
-
),
|
35 |
-
|
36 |
-
'schema' => 'my_schema_callback',
|
37 |
-
) );
|
38 |
-
```
|
39 |
-
|
40 |
-
(props @rmccue, [#1415][gh-1415], [#1222][gh-1222], [#1305][gh-1305])
|
41 |
-
|
42 |
-
- Update JavaScript API for version 2.
|
43 |
-
|
44 |
-
Our fantastic JavaScript API from version 1 is now available for version 2, refreshed with the latest and greatest changes.
|
45 |
-
|
46 |
-
As a refresher: if you want to use it, simply make your script depend on `wp-api` when you enqueue it. If you want to enqueue the script manually, add `wp_enqueue_script( 'wp-api' )` to a callback on `wp_enqueue_scripts`.
|
47 |
-
|
48 |
-
(props @tlovett1, @kadamwhite, @nathanrice, [#1374][gh-1374], [#1320][gh-1320])
|
49 |
-
|
50 |
-
- Embed links inside items in a collection.
|
51 |
-
|
52 |
-
Previously when fetching a collection of items, you only received the items themselves. To fetch the links as well via embedding, you needed to make a request to the single item with `_embed` set.
|
53 |
-
|
54 |
-
No longer! You can now request a collection with embeds enabled (try `/wp/v2/posts?_embed`). This will embed links inside each item, allowing you to build interface items much easier (for example, post archive pages can get featured image data at the same time).
|
55 |
-
|
56 |
-
This also applies to custom endpoints. Any endpoint that returns a list of objects will automatically have the embedding applied to objects inside the list.
|
57 |
-
|
58 |
-
(props @rmccue, [#1459][gh-1459], [#865][gh-865])
|
59 |
-
|
60 |
-
- Fix potential XSS vulnerability.
|
61 |
-
|
62 |
-
Requests from other origins could potentially run code on the API domain, allowing cross-origin access to authentication cookies or similar.
|
63 |
-
|
64 |
-
Reported by @xknown on 2015-07-23.
|
65 |
-
|
66 |
-
- Move `/posts` `WP_Query` vars back to `filter` param.
|
67 |
-
|
68 |
-
In version 1, we had internal `WP_Query` vars available via `filter` (e.g. `filter[s]=search+term`). For our first betas of version 2, we tried something different and exposed these directly on the endpoint. The experiment has now concluded; we didn't like this that much, so `filter` is back.
|
69 |
-
|
70 |
-
We plan on adding nicer looking arguments to collections in future releases, with a view towards being consistent across different collections. We also plan on opening up the underlying query vars via `filter` for users, comments, and terms as well.
|
71 |
-
|
72 |
-
**⚠️ This breaks backwards compatibility** for users using WP Query vars. Simply change your `x=y` parameter to `filter[x]=y`.
|
73 |
-
|
74 |
-
(props @WP-API, [#1420][gh-1420])
|
75 |
-
|
76 |
-
- Respect `rest_base` for taxonomies.
|
77 |
-
|
78 |
-
**⚠️ This breaks backwards compatibility** by changing the `/wp/v2/posts/{id}/terms/post_tag` endpoint to `/wp/v2/posts/{id}/tag`.
|
79 |
-
|
80 |
-
(props @joehoyle, [#1466][gh-1466])
|
81 |
-
|
82 |
-
- Add permission check for retrieving the posts collection in edit context.
|
83 |
-
|
84 |
-
By extension of the fact that getting any individual post yields a forbidden context error when the `context=edit` and the user is not authorized, the user should also not be permitted to list any post items when unauthorized.
|
85 |
-
|
86 |
-
(props @danielpunkass, [#1412][gh-1412])
|
87 |
-
|
88 |
-
- Ensure the REST API URL always has a trailing slash.
|
89 |
-
|
90 |
-
Previously, when pretty permalinks were enabled, the API URL during autodiscovery looked like `/wp-json`, whereas the non-pretty permalink URL looked like `?rest_route=/`. These are now consistent, and always end with a slash character to simplify client URL building.
|
91 |
-
|
92 |
-
(props @danielpunkass, @rmccue, [#1426][gh-1426], [#1442][gh-1442], [#1455][gh-1455], [#1467][gh-1467])
|
93 |
-
|
94 |
-
- Use `wp_json_encode` instead of `json_encode`
|
95 |
-
|
96 |
-
Since WordPress 4.1, `wp_json_encode` has been available to ensure encoded values are sane, and that non-UTF8 encodings are supported. We now use this function rather than doing the encode ourselves.
|
97 |
-
|
98 |
-
(props @rmccue, @pento, [#1417][gh-1417])
|
99 |
-
|
100 |
-
- Add `role` to schema for users.
|
101 |
-
|
102 |
-
The available roles you can assign to a user are now available in the schema as an `enum`.
|
103 |
-
|
104 |
-
(props @joehoyle, [#1400][gh-1400])
|
105 |
-
|
106 |
-
- Use the schema for validation inside the comments controller.
|
107 |
-
|
108 |
-
Previously, the schema was merely a decorative element for documentation inside the comments controller. To bring it inline with our other controllers, the schema is now used internally for validation.
|
109 |
-
|
110 |
-
(props @joehoyle, [#1422][gh-1422])
|
111 |
-
|
112 |
-
- Don't set the Location header in update responses.
|
113 |
-
|
114 |
-
Previously, the Location header was sent when updating resources due to some inadvertent copypasta. This header should only be sent when creating to direct clients to the new resource, and isn't required when you're already on the correct resource.
|
115 |
-
|
116 |
-
(props @rachelbaker, [#1441][gh-1441])
|
117 |
-
|
118 |
-
- Re-enable the `rest_insert_post` action hook for `WP_REST_Posts_Controller`
|
119 |
-
|
120 |
-
This was disabled during 2.0 development to avoid breaking lots of plugins on the `json_insert_post` action. Now that we've changed namespaces and are Mostly Stable (tm), we can re-enable the action.
|
121 |
-
|
122 |
-
(props @jaredcobb, [#1427][gh-1427], [#1424][gh-1424])
|
123 |
-
|
124 |
-
- Fix post taxonomy terms link URLs.
|
125 |
-
|
126 |
-
When moving the routes in a previous beta, we forgot to correct the links on post objects to the new correct route. Sorry!
|
127 |
-
|
128 |
-
(props @rachelbaker, @joehoyle, [#1447][gh-1447], [#1383][gh-1383])
|
129 |
-
|
130 |
-
- Use `wp_get_attachment_image_src()` on the image sizes in attachments.
|
131 |
-
|
132 |
-
Since the first versions of the API, we've been building attachment URLs via `str_replace`. Who knows why we were doing this, but it caused problems with custom attachment URLs (such as CDN-hosted images). This now correctly uses the internal functions and filters.
|
133 |
-
|
134 |
-
(props @joehoyle, [#1462][gh-1462])
|
135 |
-
|
136 |
-
- Make the embed context a default, not forced.
|
137 |
-
|
138 |
-
If you want embeds to bring in full data rather than with `context=edit`, you can now change the link to specify `context=view` explicitly.
|
139 |
-
|
140 |
-
(props @rmccue, [#1464][gh-1464])
|
141 |
-
|
142 |
-
- Ensure we always use the `term_taxonomy_id` and never expose `term_id` publicly.
|
143 |
-
|
144 |
-
Previously, `term_id` was inadvertently exposed in some error responses.
|
145 |
-
|
146 |
-
(props @jdolan, [#1430][gh-1430])
|
147 |
-
|
148 |
-
- Fix adding alt text to attachments on creation.
|
149 |
-
|
150 |
-
Previously, this could only be set when updating an attachment, not when creating one.
|
151 |
-
|
152 |
-
(props @joehoyle, [#1398][gh-1398])
|
153 |
-
|
154 |
-
- Throw an error when registering routes without a namespace.
|
155 |
-
|
156 |
-
Namespaces should **always** be provided when registering routes. We now throw a `doing_it_wrong` error when attempting to register one. (Previously, this caused a warning, or an invalid internal route.)
|
157 |
-
|
158 |
-
If you *really* need to register namespaceless routes (e.g. to replicate an existing API), call `WP_REST_Server::register_route` directly rather than using the convenience function.
|
159 |
-
|
160 |
-
(props @joehoyle, @rmccue, [#1355][gh-1355])
|
161 |
-
|
162 |
-
- Show links on embeds.
|
163 |
-
|
164 |
-
Previously, links were accidentally stripped from embedded response data.
|
165 |
-
|
166 |
-
(props @rmccue, [#1472][gh-1472])
|
167 |
-
|
168 |
-
- Clarify insufficient permisssion error when editing posts.
|
169 |
-
|
170 |
-
(props @danielpunkass, [#1411][gh-1411])
|
171 |
-
|
172 |
-
- Improve @return inline docs for rest_ensure_response()
|
173 |
-
|
174 |
-
(props @Shelob9, [#1328][gh-1328])
|
175 |
-
|
176 |
-
- Check taxonomies exist before trying to set properties.
|
177 |
-
|
178 |
-
(props @joehoyle, @rachelbaker, [#1354][gh-1354])
|
179 |
-
|
180 |
-
- Update controllers to ensure we use `sanitize_callback` wherever possible.
|
181 |
-
|
182 |
-
(props @joehoyle, [#1399][gh-1399])
|
183 |
-
|
184 |
-
- Add more phpDoc documentation, and correct existing documentation.
|
185 |
-
|
186 |
-
(props @Shelob9, @rmccue, [#1432][gh-1432], [#1433][gh-1433], [#1465][gh-1465])
|
187 |
-
|
188 |
-
- Update testing infrastructure.
|
189 |
-
|
190 |
-
Travis now runs our coding standards tests in parallel, and now uses the new, faster container-based testing infrastructure.
|
191 |
-
|
192 |
-
(props @ntwb, @frozzare, [#1449][gh-1449], [#1457][gh-1457])
|
193 |
-
|
194 |
-
[View all changes](https://github.com/WP-API/WP-API/compare/2.0-beta3...2.0-beta4)
|
195 |
-
|
196 |
-
[gh-839]: https://github.com/WP-API/WP-API/issues/839
|
197 |
-
[gh-865]: https://github.com/WP-API/WP-API/issues/865
|
198 |
-
[gh-1222]: https://github.com/WP-API/WP-API/issues/1222
|
199 |
-
[gh-1305]: https://github.com/WP-API/WP-API/issues/1305
|
200 |
-
[gh-1310]: https://github.com/WP-API/WP-API/issues/1310
|
201 |
-
[gh-1320]: https://github.com/WP-API/WP-API/issues/1320
|
202 |
-
[gh-1328]: https://github.com/WP-API/WP-API/issues/1328
|
203 |
-
[gh-1354]: https://github.com/WP-API/WP-API/issues/1354
|
204 |
-
[gh-1355]: https://github.com/WP-API/WP-API/issues/1355
|
205 |
-
[gh-1372]: https://github.com/WP-API/WP-API/issues/1372
|
206 |
-
[gh-1374]: https://github.com/WP-API/WP-API/issues/1374
|
207 |
-
[gh-1383]: https://github.com/WP-API/WP-API/issues/1383
|
208 |
-
[gh-1397]: https://github.com/WP-API/WP-API/issues/1397
|
209 |
-
[gh-1398]: https://github.com/WP-API/WP-API/issues/1398
|
210 |
-
[gh-1399]: https://github.com/WP-API/WP-API/issues/1399
|
211 |
-
[gh-1400]: https://github.com/WP-API/WP-API/issues/1400
|
212 |
-
[gh-1402]: https://github.com/WP-API/WP-API/issues/1402
|
213 |
-
[gh-1411]: https://github.com/WP-API/WP-API/issues/1411
|
214 |
-
[gh-1412]: https://github.com/WP-API/WP-API/issues/1412
|
215 |
-
[gh-1413]: https://github.com/WP-API/WP-API/issues/1413
|
216 |
-
[gh-1415]: https://github.com/WP-API/WP-API/issues/1415
|
217 |
-
[gh-1417]: https://github.com/WP-API/WP-API/issues/1417
|
218 |
-
[gh-1420]: https://github.com/WP-API/WP-API/issues/1420
|
219 |
-
[gh-1422]: https://github.com/WP-API/WP-API/issues/1422
|
220 |
-
[gh-1424]: https://github.com/WP-API/WP-API/issues/1424
|
221 |
-
[gh-1426]: https://github.com/WP-API/WP-API/issues/1426
|
222 |
-
[gh-1427]: https://github.com/WP-API/WP-API/issues/1427
|
223 |
-
[gh-1430]: https://github.com/WP-API/WP-API/issues/1430
|
224 |
-
[gh-1432]: https://github.com/WP-API/WP-API/issues/1432
|
225 |
-
[gh-1433]: https://github.com/WP-API/WP-API/issues/1433
|
226 |
-
[gh-1435]: https://github.com/WP-API/WP-API/issues/1435
|
227 |
-
[gh-1441]: https://github.com/WP-API/WP-API/issues/1441
|
228 |
-
[gh-1442]: https://github.com/WP-API/WP-API/issues/1442
|
229 |
-
[gh-1447]: https://github.com/WP-API/WP-API/issues/1447
|
230 |
-
[gh-1449]: https://github.com/WP-API/WP-API/issues/1449
|
231 |
-
[gh-1455]: https://github.com/WP-API/WP-API/issues/1455
|
232 |
-
[gh-1455]: https://github.com/WP-API/WP-API/issues/1455
|
233 |
-
[gh-1457]: https://github.com/WP-API/WP-API/issues/1457
|
234 |
-
[gh-1459]: https://github.com/WP-API/WP-API/issues/1459
|
235 |
-
[gh-1462]: https://github.com/WP-API/WP-API/issues/1462
|
236 |
-
[gh-1464]: https://github.com/WP-API/WP-API/issues/1464
|
237 |
-
[gh-1465]: https://github.com/WP-API/WP-API/issues/1465
|
238 |
-
[gh-1466]: https://github.com/WP-API/WP-API/issues/1466
|
239 |
-
[gh-1467]: https://github.com/WP-API/WP-API/issues/1467
|
240 |
-
[gh-1472]: https://github.com/WP-API/WP-API/issues/1472
|
241 |
-
|
242 |
## 2.0 Beta 3.0
|
243 |
|
244 |
- Add ability to declare sanitization and default options for schema fields.
|
1 |
# Changelog
|
2 |
|
3 |
+
## 2.0 Beta 3.1
|
4 |
|
5 |
- Ensure media of private posts are private too.
|
6 |
|
7 |
Reported by @danielbachhuber on 2016-01-08.
|
8 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
## 2.0 Beta 3.0
|
10 |
|
11 |
- Add ability to declare sanitization and default options for schema fields.
|
README.md
CHANGED
@@ -4,7 +4,6 @@ Access your WordPress site's data through an easy-to-use HTTP REST API.
|
|
4 |
|
5 |
[![Build Status](https://travis-ci.org/WP-API/WP-API.svg?branch=develop)](https://travis-ci.org/WP-API/WP-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 |
|
@@ -50,9 +49,6 @@ There's no fixed timeline for integration into core at this time, but getting cl
|
|
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 `trunk` branch of WordPress Core as there are potentially
|
54 |
-
recent commits to Core that the REST API relies on.
|
55 |
-
|
56 |
## Issue Tracking
|
57 |
|
58 |
All tickets for the project are being tracked on [GitHub][]. You can also take a
|
4 |
|
5 |
[![Build Status](https://travis-ci.org/WP-API/WP-API.svg?branch=develop)](https://travis-ci.org/WP-API/WP-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 |
|
8 |
## WARNING
|
9 |
|
49 |
Drop this directory in and activate it. You need to be using pretty permalinks
|
50 |
to use the plugin, as it uses custom rewrite rules to power the API.
|
51 |
|
|
|
|
|
|
|
52 |
## Issue Tracking
|
53 |
|
54 |
All tickets for the project are being tracked on [GitHub][]. You can also take a
|
extras.php
CHANGED
@@ -74,7 +74,7 @@ function rest_output_link_header() {
|
|
74 |
|
75 |
$api_root = get_rest_url();
|
76 |
|
77 |
-
if ( empty(
|
78 |
return;
|
79 |
}
|
80 |
|
@@ -234,7 +234,6 @@ function rest_get_date_with_gmt( $date, $force_utc = false ) {
|
|
234 |
* information. Including any information on the offset could be misleading.
|
235 |
*
|
236 |
* @param string $date
|
237 |
-
* @return string Date formatted for ISO8601/RFC3339.
|
238 |
*/
|
239 |
function rest_mysql_to_rfc3339( $date_string ) {
|
240 |
$formatted = mysql2date( 'c', $date_string, false );
|
74 |
|
75 |
$api_root = get_rest_url();
|
76 |
|
77 |
+
if ( empty($api_root) ) {
|
78 |
return;
|
79 |
}
|
80 |
|
234 |
* information. Including any information on the offset could be misleading.
|
235 |
*
|
236 |
* @param string $date
|
|
|
237 |
*/
|
238 |
function rest_mysql_to_rfc3339( $date_string ) {
|
239 |
$formatted = mysql2date( 'c', $date_string, false );
|
lib/endpoints/class-wp-rest-attachments-controller.php
CHANGED
@@ -73,10 +73,6 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller {
|
|
73 |
|
74 |
wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $file ) );
|
75 |
|
76 |
-
if ( isset( $request['alt_text'] ) ) {
|
77 |
-
update_post_meta( $id, '_wp_attachment_image_alt', sanitize_text_field( $request['alt_text'] ) );
|
78 |
-
}
|
79 |
-
|
80 |
$this->update_additional_fields_for_object( $attachment, $request );
|
81 |
|
82 |
$response = $this->get_item( array(
|
@@ -107,15 +103,16 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller {
|
|
107 |
$data = $response->get_data();
|
108 |
|
109 |
if ( isset( $request['alt_text'] ) ) {
|
110 |
-
update_post_meta( $data['id'], '_wp_attachment_image_alt', $request['alt_text'] );
|
111 |
}
|
112 |
|
113 |
$response = $this->get_item( array(
|
114 |
'id' => $data['id'],
|
115 |
'context' => 'edit',
|
116 |
));
|
117 |
-
|
118 |
-
|
|
|
119 |
}
|
120 |
|
121 |
/**
|
@@ -128,15 +125,15 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller {
|
|
128 |
$prepared_attachment = parent::prepare_item_for_database( $request );
|
129 |
|
130 |
if ( isset( $request['caption'] ) ) {
|
131 |
-
$prepared_attachment->post_excerpt = $request['caption'];
|
132 |
}
|
133 |
|
134 |
if ( isset( $request['description'] ) ) {
|
135 |
-
$prepared_attachment->post_content = $request['description'];
|
136 |
}
|
137 |
|
138 |
if ( isset( $request['post'] ) ) {
|
139 |
-
$prepared_attachment->post_parent = (int) $request['
|
140 |
}
|
141 |
|
142 |
return $prepared_attachment;
|
@@ -169,13 +166,7 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller {
|
|
169 |
|
170 |
foreach ( $data['media_details']['sizes'] as $size => &$size_data ) {
|
171 |
// Use the same method image_downsize() does
|
172 |
-
$
|
173 |
-
|
174 |
-
if ( ! $image_src ) {
|
175 |
-
continue;
|
176 |
-
}
|
177 |
-
|
178 |
-
$size_data['source_url'] = $image_src[0];
|
179 |
}
|
180 |
} else {
|
181 |
$data['media_details']['sizes'] = new stdClass;
|
@@ -206,25 +197,16 @@ class WP_REST_Attachments_Controller extends WP_REST_Posts_Controller {
|
|
206 |
'description' => 'Alternative text to display when attachment is not displayed.',
|
207 |
'type' => 'string',
|
208 |
'context' => array( 'view', 'edit', 'embed' ),
|
209 |
-
'arg_options' => array(
|
210 |
-
'sanitize_callback' => 'sanitize_text_field',
|
211 |
-
),
|
212 |
);
|
213 |
$schema['properties']['caption'] = array(
|
214 |
'description' => 'The caption for the attachment.',
|
215 |
'type' => 'string',
|
216 |
'context' => array( 'view', 'edit' ),
|
217 |
-
'arg_options' => array(
|
218 |
-
'sanitize_callback' => 'wp_filter_post_kses',
|
219 |
-
),
|
220 |
);
|
221 |
$schema['properties']['description'] = array(
|
222 |
'description' => 'The description for the attachment.',
|
223 |
'type' => 'string',
|
224 |
'context' => array( 'view', 'edit' ),
|
225 |
-
'arg_options' => array(
|
226 |
-
'sanitize_callback' => 'wp_filter_post_kses',
|
227 |
-
),
|
228 |
);
|
229 |
$schema['properties']['media_type'] = array(
|
230 |
'description' => 'Type of attachment.',
|
73 |
|
74 |
wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $file ) );
|
75 |
|
|
|
|
|
|
|
|
|
76 |
$this->update_additional_fields_for_object( $attachment, $request );
|
77 |
|
78 |
$response = $this->get_item( array(
|
103 |
$data = $response->get_data();
|
104 |
|
105 |
if ( isset( $request['alt_text'] ) ) {
|
106 |
+
update_post_meta( $data['id'], '_wp_attachment_image_alt', sanitize_text_field( $request['alt_text'] ) );
|
107 |
}
|
108 |
|
109 |
$response = $this->get_item( array(
|
110 |
'id' => $data['id'],
|
111 |
'context' => 'edit',
|
112 |
));
|
113 |
+
$response = rest_ensure_response( $response );
|
114 |
+
$response->header( 'Location', rest_url( '/wp/v2/' . $this->get_post_type_base( $this->post_type ) . '/' . $data['id'] ) );
|
115 |
+
return $response;
|
116 |
}
|
117 |
|
118 |
/**
|
125 |
$prepared_attachment = parent::prepare_item_for_database( $request );
|
126 |
|
127 |
if ( isset( $request['caption'] ) ) {
|
128 |
+
$prepared_attachment->post_excerpt = wp_filter_post_kses( $request['caption'] );
|
129 |
}
|
130 |
|
131 |
if ( isset( $request['description'] ) ) {
|
132 |
+
$prepared_attachment->post_content = wp_filter_post_kses( $request['description'] );
|
133 |
}
|
134 |
|
135 |
if ( isset( $request['post'] ) ) {
|
136 |
+
$prepared_attachment->post_parent = (int) $request['post_parent'];
|
137 |
}
|
138 |
|
139 |
return $prepared_attachment;
|
166 |
|
167 |
foreach ( $data['media_details']['sizes'] as $size => &$size_data ) {
|
168 |
// Use the same method image_downsize() does
|
169 |
+
$size_data['source_url'] = str_replace( $img_url_basename, $size_data['file'], $data['source_url'] );
|
|
|
|
|
|
|
|
|
|
|
|
|
170 |
}
|
171 |
} else {
|
172 |
$data['media_details']['sizes'] = new stdClass;
|
197 |
'description' => 'Alternative text to display when attachment is not displayed.',
|
198 |
'type' => 'string',
|
199 |
'context' => array( 'view', 'edit', 'embed' ),
|
|
|
|
|
|
|
200 |
);
|
201 |
$schema['properties']['caption'] = array(
|
202 |
'description' => 'The caption for the attachment.',
|
203 |
'type' => 'string',
|
204 |
'context' => array( 'view', 'edit' ),
|
|
|
|
|
|
|
205 |
);
|
206 |
$schema['properties']['description'] = array(
|
207 |
'description' => 'The description for the attachment.',
|
208 |
'type' => 'string',
|
209 |
'context' => array( 'view', 'edit' ),
|
|
|
|
|
|
|
210 |
);
|
211 |
$schema['properties']['media_type'] = array(
|
212 |
'description' => 'Type of attachment.',
|
lib/endpoints/class-wp-rest-comments-controller.php
CHANGED
@@ -22,10 +22,54 @@ class WP_REST_Comments_Controller extends WP_REST_Controller {
|
|
22 |
'methods' => WP_REST_Server::CREATABLE,
|
23 |
'callback' => array( $this, 'create_item' ),
|
24 |
'permission_callback' => array( $this, 'create_item_permissions_check' ),
|
25 |
-
'args' =>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
),
|
27 |
-
|
28 |
-
'schema' => array( $this, 'get_public_item_schema' ),
|
29 |
) );
|
30 |
|
31 |
register_rest_route( 'wp/v2', '/comments/(?P<id>[\d]+)', array(
|
@@ -43,7 +87,40 @@ class WP_REST_Comments_Controller extends WP_REST_Controller {
|
|
43 |
'methods' => WP_REST_Server::EDITABLE,
|
44 |
'callback' => array( $this, 'update_item' ),
|
45 |
'permission_callback' => array( $this, 'update_item_permissions_check' ),
|
46 |
-
'args' =>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
47 |
),
|
48 |
array(
|
49 |
'methods' => WP_REST_Server::DELETABLE,
|
@@ -53,8 +130,11 @@ class WP_REST_Comments_Controller extends WP_REST_Controller {
|
|
53 |
'force' => array(),
|
54 |
),
|
55 |
),
|
|
|
56 |
|
57 |
-
|
|
|
|
|
58 |
) );
|
59 |
}
|
60 |
|
@@ -152,18 +232,8 @@ class WP_REST_Comments_Controller extends WP_REST_Controller {
|
|
152 |
}
|
153 |
|
154 |
$prepared_comment = $this->prepare_item_for_database( $request );
|
155 |
-
|
156 |
// Setting remaining values before wp_insert_comment so we can
|
157 |
// use wp_allow_comment().
|
158 |
-
if ( ! isset( $prepared_comment['comment_date_gmt'] ) ) {
|
159 |
-
$prepared_comment['comment_date_gmt'] = current_time( 'mysql', true );
|
160 |
-
}
|
161 |
-
if ( ! isset( $prepared_comment['comment_author_email'] ) ) {
|
162 |
-
$prepared_comment['comment_author_email'] = '';
|
163 |
-
}
|
164 |
-
if ( ! isset( $prepared_comment['comment_author_url'] ) ) {
|
165 |
-
$prepared_comment['comment_author_url'] = '';
|
166 |
-
}
|
167 |
$prepared_comment['comment_author_IP'] = '127.0.0.1';
|
168 |
$prepared_comment['comment_agent'] = '';
|
169 |
$prepared_comment['comment_approved'] = wp_allow_comment( $prepared_comment );
|
@@ -242,8 +312,13 @@ class WP_REST_Comments_Controller extends WP_REST_Controller {
|
|
242 |
'id' => $id,
|
243 |
'context' => 'edit',
|
244 |
) );
|
|
|
|
|
|
|
|
|
|
|
245 |
|
246 |
-
return
|
247 |
}
|
248 |
|
249 |
/**
|
@@ -701,52 +776,48 @@ class WP_REST_Comments_Controller extends WP_REST_Controller {
|
|
701 |
'type' => 'integer',
|
702 |
'context' => array( 'view', 'edit', 'embed' ),
|
703 |
'readonly' => true,
|
704 |
-
|
705 |
'author' => array(
|
706 |
'description' => 'The ID of the user object, if author was a user.',
|
707 |
'type' => 'integer',
|
708 |
'context' => array( 'view', 'edit', 'embed' ),
|
709 |
-
|
710 |
'author_avatar_urls' => array(
|
711 |
'description' => 'Avatar URLs for the object author.',
|
712 |
'type' => 'object',
|
713 |
'context' => array( 'view', 'edit', 'embed' ),
|
714 |
'readonly' => true,
|
715 |
'properties' => $avatar_properties,
|
716 |
-
|
717 |
'author_email' => array(
|
718 |
'description' => 'Email address for the object author.',
|
719 |
'type' => 'string',
|
720 |
'format' => 'email',
|
721 |
'context' => array( 'edit' ),
|
722 |
-
|
723 |
'author_ip' => array(
|
724 |
'description' => 'IP address for the object author.',
|
725 |
'type' => 'string',
|
726 |
'context' => array( 'edit' ),
|
727 |
'readonly' => true,
|
728 |
-
|
729 |
'author_name' => array(
|
730 |
'description' => 'Display name for the object author.',
|
731 |
'type' => 'string',
|
732 |
'context' => array( 'view', 'edit', 'embed' ),
|
733 |
-
'arg_options' => array(
|
734 |
-
'sanitize_callback' => 'sanitize_text_field',
|
735 |
-
'default' => '',
|
736 |
),
|
737 |
-
),
|
738 |
'author_url' => array(
|
739 |
'description' => 'URL for the object author.',
|
740 |
'type' => 'string',
|
741 |
'format' => 'uri',
|
742 |
'context' => array( 'view', 'edit', 'embed' ),
|
743 |
-
|
744 |
'author_user_agent' => array(
|
745 |
'description' => 'User agent for the object author.',
|
746 |
'type' => 'string',
|
747 |
'context' => array( 'edit' ),
|
748 |
'readonly' => true,
|
749 |
-
|
750 |
'content' => array(
|
751 |
'description' => 'The content for the object.',
|
752 |
'type' => 'object',
|
@@ -756,18 +827,14 @@ class WP_REST_Comments_Controller extends WP_REST_Controller {
|
|
756 |
'description' => 'Content for the object, as it exists in the database.',
|
757 |
'type' => 'string',
|
758 |
'context' => array( 'edit' ),
|
759 |
-
|
760 |
'rendered' => array(
|
761 |
'description' => 'Content for the object, transformed for display.',
|
762 |
'type' => 'string',
|
763 |
'context' => array( 'view', 'edit', 'embed' ),
|
|
|
764 |
),
|
765 |
),
|
766 |
-
'arg_options' => array(
|
767 |
-
'sanitize_callback' => 'wp_filter_post_kses',
|
768 |
-
'default' => '',
|
769 |
-
),
|
770 |
-
),
|
771 |
'date' => array(
|
772 |
'description' => 'The date the object was published.',
|
773 |
'type' => 'string',
|
@@ -784,6 +851,7 @@ class WP_REST_Comments_Controller extends WP_REST_Controller {
|
|
784 |
'description' => 'Karma for the object.',
|
785 |
'type' => 'integer',
|
786 |
'context' => array( 'edit' ),
|
|
|
787 |
),
|
788 |
'link' => array(
|
789 |
'description' => 'URL to the object.',
|
@@ -796,9 +864,6 @@ class WP_REST_Comments_Controller extends WP_REST_Controller {
|
|
796 |
'description' => 'The ID for the parent of the object.',
|
797 |
'type' => 'integer',
|
798 |
'context' => array( 'view', 'edit', 'embed' ),
|
799 |
-
'arg_options' => array(
|
800 |
-
'default' => 0,
|
801 |
-
),
|
802 |
),
|
803 |
'post' => array(
|
804 |
'description' => 'The ID of the associated post object.',
|
@@ -809,18 +874,11 @@ class WP_REST_Comments_Controller extends WP_REST_Controller {
|
|
809 |
'description' => 'State of the object.',
|
810 |
'type' => 'string',
|
811 |
'context' => array( 'view', 'edit' ),
|
812 |
-
'arg_options' => array(
|
813 |
-
'sanitize_callback' => 'sanitize_key',
|
814 |
-
),
|
815 |
),
|
816 |
'type' => array(
|
817 |
'description' => 'Type of Comment for the object.',
|
818 |
'type' => 'string',
|
819 |
'context' => array( 'view', 'edit', 'embed' ),
|
820 |
-
'arg_options' => array(
|
821 |
-
'sanitize_callback' => 'sanitize_key',
|
822 |
-
'default' => '',
|
823 |
-
),
|
824 |
),
|
825 |
),
|
826 |
);
|
22 |
'methods' => WP_REST_Server::CREATABLE,
|
23 |
'callback' => array( $this, 'create_item' ),
|
24 |
'permission_callback' => array( $this, 'create_item_permissions_check' ),
|
25 |
+
'args' => array(
|
26 |
+
'post' => array(
|
27 |
+
'required' => true,
|
28 |
+
'sanitize_callback' => 'absint',
|
29 |
+
),
|
30 |
+
'type' => array(
|
31 |
+
'default' => '',
|
32 |
+
'sanitize_callback' => 'sanitize_key',
|
33 |
+
),
|
34 |
+
'parent' => array(
|
35 |
+
'default' => 0,
|
36 |
+
'sanitize_callback' => 'absint',
|
37 |
+
),
|
38 |
+
'content' => array(
|
39 |
+
'default' => '',
|
40 |
+
'sanitize_callback' => 'wp_filter_post_kses',
|
41 |
+
),
|
42 |
+
'author' => array(
|
43 |
+
'default' => 0,
|
44 |
+
'sanitize_callback' => 'absint',
|
45 |
+
),
|
46 |
+
'author_name' => array(
|
47 |
+
'default' => '',
|
48 |
+
'sanitize_callback' => 'sanitize_text_field',
|
49 |
+
),
|
50 |
+
'author_email' => array(
|
51 |
+
'default' => '',
|
52 |
+
'sanitize_callback' => 'sanitize_email',
|
53 |
+
),
|
54 |
+
'author_url' => array(
|
55 |
+
'default' => '',
|
56 |
+
'sanitize_callback' => 'esc_url_raw',
|
57 |
+
),
|
58 |
+
'karma' => array(
|
59 |
+
'default' => 0,
|
60 |
+
'sanitize_callback' => 'absint',
|
61 |
+
),
|
62 |
+
'status' => array(
|
63 |
+
'sanitize_callback' => 'sanitize_key',
|
64 |
+
),
|
65 |
+
'date' => array(
|
66 |
+
'default' => current_time( 'mysql' ),
|
67 |
+
),
|
68 |
+
'date_gmt' => array(
|
69 |
+
'default' => current_time( 'mysql', true ),
|
70 |
+
),
|
71 |
+
),
|
72 |
),
|
|
|
|
|
73 |
) );
|
74 |
|
75 |
register_rest_route( 'wp/v2', '/comments/(?P<id>[\d]+)', array(
|
87 |
'methods' => WP_REST_Server::EDITABLE,
|
88 |
'callback' => array( $this, 'update_item' ),
|
89 |
'permission_callback' => array( $this, 'update_item_permissions_check' ),
|
90 |
+
'args' => array(
|
91 |
+
'post' => array(
|
92 |
+
'sanitize_callback' => 'absint',
|
93 |
+
),
|
94 |
+
'type' => array(
|
95 |
+
'sanitize_callback' => 'sanitize_key',
|
96 |
+
),
|
97 |
+
'parent' => array(
|
98 |
+
'sanitize_callback' => 'absint',
|
99 |
+
),
|
100 |
+
'content' => array(
|
101 |
+
'sanitize_callback' => 'wp_filter_post_kses',
|
102 |
+
),
|
103 |
+
'author' => array(
|
104 |
+
'sanitize_callback' => 'absint',
|
105 |
+
),
|
106 |
+
'author_name' => array(
|
107 |
+
'sanitize_callback' => 'sanitize_text_field',
|
108 |
+
),
|
109 |
+
'author_email' => array(
|
110 |
+
'sanitize_callback' => 'sanitize_email',
|
111 |
+
),
|
112 |
+
'author_url' => array(
|
113 |
+
'sanitize_callback' => 'esc_url_raw',
|
114 |
+
),
|
115 |
+
'karma' => array(
|
116 |
+
'sanitize_callback' => 'absint',
|
117 |
+
),
|
118 |
+
'status' => array(
|
119 |
+
'sanitize_callback' => 'sanitize_key',
|
120 |
+
),
|
121 |
+
'date' => array(),
|
122 |
+
'date_gmt' => array(),
|
123 |
+
),
|
124 |
),
|
125 |
array(
|
126 |
'methods' => WP_REST_Server::DELETABLE,
|
130 |
'force' => array(),
|
131 |
),
|
132 |
),
|
133 |
+
) );
|
134 |
|
135 |
+
register_rest_route( 'wp/v2', '/comments/schema', array(
|
136 |
+
'methods' => WP_REST_Server::READABLE,
|
137 |
+
'callback' => array( $this, 'get_public_item_schema' ),
|
138 |
) );
|
139 |
}
|
140 |
|
232 |
}
|
233 |
|
234 |
$prepared_comment = $this->prepare_item_for_database( $request );
|
|
|
235 |
// Setting remaining values before wp_insert_comment so we can
|
236 |
// use wp_allow_comment().
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
237 |
$prepared_comment['comment_author_IP'] = '127.0.0.1';
|
238 |
$prepared_comment['comment_agent'] = '';
|
239 |
$prepared_comment['comment_approved'] = wp_allow_comment( $prepared_comment );
|
312 |
'id' => $id,
|
313 |
'context' => 'edit',
|
314 |
) );
|
315 |
+
$response = rest_ensure_response( $response );
|
316 |
+
if ( is_wp_error( $response ) ) {
|
317 |
+
return $response;
|
318 |
+
}
|
319 |
+
$response->header( 'Location', rest_url( '/wp/v2/comments/' . $comment->comment_ID ) );
|
320 |
|
321 |
+
return $response;
|
322 |
}
|
323 |
|
324 |
/**
|
776 |
'type' => 'integer',
|
777 |
'context' => array( 'view', 'edit', 'embed' ),
|
778 |
'readonly' => true,
|
779 |
+
),
|
780 |
'author' => array(
|
781 |
'description' => 'The ID of the user object, if author was a user.',
|
782 |
'type' => 'integer',
|
783 |
'context' => array( 'view', 'edit', 'embed' ),
|
784 |
+
),
|
785 |
'author_avatar_urls' => array(
|
786 |
'description' => 'Avatar URLs for the object author.',
|
787 |
'type' => 'object',
|
788 |
'context' => array( 'view', 'edit', 'embed' ),
|
789 |
'readonly' => true,
|
790 |
'properties' => $avatar_properties,
|
791 |
+
),
|
792 |
'author_email' => array(
|
793 |
'description' => 'Email address for the object author.',
|
794 |
'type' => 'string',
|
795 |
'format' => 'email',
|
796 |
'context' => array( 'edit' ),
|
797 |
+
),
|
798 |
'author_ip' => array(
|
799 |
'description' => 'IP address for the object author.',
|
800 |
'type' => 'string',
|
801 |
'context' => array( 'edit' ),
|
802 |
'readonly' => true,
|
803 |
+
),
|
804 |
'author_name' => array(
|
805 |
'description' => 'Display name for the object author.',
|
806 |
'type' => 'string',
|
807 |
'context' => array( 'view', 'edit', 'embed' ),
|
|
|
|
|
|
|
808 |
),
|
|
|
809 |
'author_url' => array(
|
810 |
'description' => 'URL for the object author.',
|
811 |
'type' => 'string',
|
812 |
'format' => 'uri',
|
813 |
'context' => array( 'view', 'edit', 'embed' ),
|
814 |
+
),
|
815 |
'author_user_agent' => array(
|
816 |
'description' => 'User agent for the object author.',
|
817 |
'type' => 'string',
|
818 |
'context' => array( 'edit' ),
|
819 |
'readonly' => true,
|
820 |
+
),
|
821 |
'content' => array(
|
822 |
'description' => 'The content for the object.',
|
823 |
'type' => 'object',
|
827 |
'description' => 'Content for the object, as it exists in the database.',
|
828 |
'type' => 'string',
|
829 |
'context' => array( 'edit' ),
|
830 |
+
),
|
831 |
'rendered' => array(
|
832 |
'description' => 'Content for the object, transformed for display.',
|
833 |
'type' => 'string',
|
834 |
'context' => array( 'view', 'edit', 'embed' ),
|
835 |
+
),
|
836 |
),
|
837 |
),
|
|
|
|
|
|
|
|
|
|
|
838 |
'date' => array(
|
839 |
'description' => 'The date the object was published.',
|
840 |
'type' => 'string',
|
851 |
'description' => 'Karma for the object.',
|
852 |
'type' => 'integer',
|
853 |
'context' => array( 'edit' ),
|
854 |
+
'readonly' => true,
|
855 |
),
|
856 |
'link' => array(
|
857 |
'description' => 'URL to the object.',
|
864 |
'description' => 'The ID for the parent of the object.',
|
865 |
'type' => 'integer',
|
866 |
'context' => array( 'view', 'edit', 'embed' ),
|
|
|
|
|
|
|
867 |
),
|
868 |
'post' => array(
|
869 |
'description' => 'The ID of the associated post object.',
|
874 |
'description' => 'State of the object.',
|
875 |
'type' => 'string',
|
876 |
'context' => array( 'view', 'edit' ),
|
|
|
|
|
|
|
877 |
),
|
878 |
'type' => array(
|
879 |
'description' => 'Type of Comment for the object.',
|
880 |
'type' => 'string',
|
881 |
'context' => array( 'view', 'edit', 'embed' ),
|
|
|
|
|
|
|
|
|
882 |
),
|
883 |
),
|
884 |
);
|
lib/endpoints/class-wp-rest-meta-controller.php
CHANGED
@@ -50,10 +50,13 @@ abstract class WP_REST_Meta_Controller extends WP_REST_Controller {
|
|
50 |
'methods' => WP_REST_Server::CREATABLE,
|
51 |
'callback' => array( $this, 'create_item' ),
|
52 |
'permission_callback' => array( $this, 'create_item_permissions_check' ),
|
53 |
-
'args' =>
|
|
|
|
|
|
|
|
|
|
|
54 |
),
|
55 |
-
|
56 |
-
'schema' => array( $this, 'get_public_item_schema' ),
|
57 |
) );
|
58 |
register_rest_route( 'wp/v2', '/' . $this->parent_base . '/(?P<parent_id>[\d]+)/meta/(?P<id>[\d]+)', array(
|
59 |
array(
|
@@ -70,7 +73,10 @@ abstract class WP_REST_Meta_Controller extends WP_REST_Controller {
|
|
70 |
'methods' => WP_REST_Server::EDITABLE,
|
71 |
'callback' => array( $this, 'update_item' ),
|
72 |
'permission_callback' => array( $this, 'update_item_permissions_check' ),
|
73 |
-
'args' =>
|
|
|
|
|
|
|
74 |
),
|
75 |
array(
|
76 |
'methods' => WP_REST_Server::DELETABLE,
|
@@ -78,8 +84,10 @@ abstract class WP_REST_Meta_Controller extends WP_REST_Controller {
|
|
78 |
'permission_callback' => array( $this, 'delete_item_permissions_check' ),
|
79 |
'args' => array(),
|
80 |
),
|
81 |
-
|
82 |
-
|
|
|
|
|
83 |
) );
|
84 |
}
|
85 |
|
@@ -101,16 +109,11 @@ abstract class WP_REST_Meta_Controller extends WP_REST_Controller {
|
|
101 |
'description' => 'Unique identifier for the object.',
|
102 |
'type' => 'int',
|
103 |
'context' => array( 'edit' ),
|
104 |
-
'readonly' => true,
|
105 |
),
|
106 |
'key' => array(
|
107 |
'description' => 'The key for the custom field.',
|
108 |
'type' => 'string',
|
109 |
'context' => array( 'edit' ),
|
110 |
-
'required' => true,
|
111 |
-
'arg_options' => array(
|
112 |
-
'sanitize_callback' => 'sanitize_text_field',
|
113 |
-
),
|
114 |
),
|
115 |
'value' => array(
|
116 |
'description' => 'The value of the custom field.',
|
@@ -352,14 +355,14 @@ abstract class WP_REST_Meta_Controller extends WP_REST_Controller {
|
|
352 |
return new WP_Error( $code, __( 'Invalid provided meta data for action.' ), array( 'status' => 400 ) );
|
353 |
}
|
354 |
|
355 |
-
if ( empty( $request['key'] ) ) {
|
356 |
-
return new WP_Error( 'rest_meta_invalid_key', __( 'Invalid meta key.' ), array( 'status' => 400 ) );
|
357 |
-
}
|
358 |
-
|
359 |
if ( is_protected_meta( $request['key'] ) ) {
|
360 |
return new WP_Error( 'rest_meta_protected', sprintf( __( '%s is marked as a protected field.' ), $request['key'] ), array( 'status' => 403 ) );
|
361 |
}
|
362 |
|
|
|
|
|
|
|
|
|
363 |
$meta_key = wp_slash( $request['key'] );
|
364 |
$value = wp_slash( $request['value'] );
|
365 |
|
50 |
'methods' => WP_REST_Server::CREATABLE,
|
51 |
'callback' => array( $this, 'create_item' ),
|
52 |
'permission_callback' => array( $this, 'create_item_permissions_check' ),
|
53 |
+
'args' => array(
|
54 |
+
'key' => array(
|
55 |
+
'required' => true,
|
56 |
+
),
|
57 |
+
'value' => array(),
|
58 |
+
),
|
59 |
),
|
|
|
|
|
60 |
) );
|
61 |
register_rest_route( 'wp/v2', '/' . $this->parent_base . '/(?P<parent_id>[\d]+)/meta/(?P<id>[\d]+)', array(
|
62 |
array(
|
73 |
'methods' => WP_REST_Server::EDITABLE,
|
74 |
'callback' => array( $this, 'update_item' ),
|
75 |
'permission_callback' => array( $this, 'update_item_permissions_check' ),
|
76 |
+
'args' => array(
|
77 |
+
'key' => array(),
|
78 |
+
'value' => array(),
|
79 |
+
),
|
80 |
),
|
81 |
array(
|
82 |
'methods' => WP_REST_Server::DELETABLE,
|
84 |
'permission_callback' => array( $this, 'delete_item_permissions_check' ),
|
85 |
'args' => array(),
|
86 |
),
|
87 |
+
) );
|
88 |
+
register_rest_route( 'wp/v2', $this->parent_base . '/meta/schema', array(
|
89 |
+
'methods' => WP_REST_Server::READABLE,
|
90 |
+
'callback' => array( $this, 'get_public_item_schema' ),
|
91 |
) );
|
92 |
}
|
93 |
|
109 |
'description' => 'Unique identifier for the object.',
|
110 |
'type' => 'int',
|
111 |
'context' => array( 'edit' ),
|
|
|
112 |
),
|
113 |
'key' => array(
|
114 |
'description' => 'The key for the custom field.',
|
115 |
'type' => 'string',
|
116 |
'context' => array( 'edit' ),
|
|
|
|
|
|
|
|
|
117 |
),
|
118 |
'value' => array(
|
119 |
'description' => 'The value of the custom field.',
|
355 |
return new WP_Error( $code, __( 'Invalid provided meta data for action.' ), array( 'status' => 400 ) );
|
356 |
}
|
357 |
|
|
|
|
|
|
|
|
|
358 |
if ( is_protected_meta( $request['key'] ) ) {
|
359 |
return new WP_Error( 'rest_meta_protected', sprintf( __( '%s is marked as a protected field.' ), $request['key'] ), array( 'status' => 403 ) );
|
360 |
}
|
361 |
|
362 |
+
if ( empty( $request['key'] ) ) {
|
363 |
+
return new WP_Error( 'rest_meta_invalid_key', __( 'Invalid meta key.' ), array( 'status' => 400 ) );
|
364 |
+
}
|
365 |
+
|
366 |
$meta_key = wp_slash( $request['key'] );
|
367 |
$value = wp_slash( $request['value'] );
|
368 |
|
lib/endpoints/class-wp-rest-post-statuses-controller.php
CHANGED
@@ -8,19 +8,18 @@ class WP_REST_Post_Statuses_Controller extends WP_REST_Controller {
|
|
8 |
public function register_routes() {
|
9 |
|
10 |
register_rest_route( 'wp/v2', '/statuses', array(
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
|
|
|
|
16 |
) );
|
17 |
|
18 |
register_rest_route( 'wp/v2', '/statuses/(?P<status>[\w-]+)', array(
|
19 |
-
|
20 |
-
|
21 |
-
'callback' => array( $this, 'get_item' ),
|
22 |
-
),
|
23 |
-
'schema' => array( $this, 'get_public_item_schema' ),
|
24 |
) );
|
25 |
}
|
26 |
|
8 |
public function register_routes() {
|
9 |
|
10 |
register_rest_route( 'wp/v2', '/statuses', array(
|
11 |
+
'methods' => WP_REST_Server::READABLE,
|
12 |
+
'callback' => array( $this, 'get_items' ),
|
13 |
+
) );
|
14 |
+
|
15 |
+
register_rest_route( 'wp/v2', '/statuses/schema', array(
|
16 |
+
'methods' => WP_REST_Server::READABLE,
|
17 |
+
'callback' => array( $this, 'get_public_item_schema' ),
|
18 |
) );
|
19 |
|
20 |
register_rest_route( 'wp/v2', '/statuses/(?P<status>[\w-]+)', array(
|
21 |
+
'methods' => WP_REST_Server::READABLE,
|
22 |
+
'callback' => array( $this, 'get_item' ),
|
|
|
|
|
|
|
23 |
) );
|
24 |
}
|
25 |
|
lib/endpoints/class-wp-rest-post-types-controller.php
CHANGED
@@ -8,24 +8,23 @@ class WP_REST_Post_Types_Controller extends WP_REST_Controller {
|
|
8 |
public function register_routes() {
|
9 |
|
10 |
register_rest_route( 'wp/v2', '/types', array(
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
'
|
15 |
-
'
|
16 |
-
'sanitize_callback' => 'sanitize_key',
|
17 |
-
),
|
18 |
),
|
19 |
),
|
20 |
-
|
|
|
|
|
|
|
|
|
21 |
) );
|
22 |
|
23 |
register_rest_route( 'wp/v2', '/types/(?P<type>[\w-]+)', array(
|
24 |
-
|
25 |
-
|
26 |
-
'callback' => array( $this, 'get_item' ),
|
27 |
-
),
|
28 |
-
'schema' => array( $this, 'get_public_item_schema' ),
|
29 |
) );
|
30 |
}
|
31 |
|
8 |
public function register_routes() {
|
9 |
|
10 |
register_rest_route( 'wp/v2', '/types', array(
|
11 |
+
'methods' => WP_REST_Server::READABLE,
|
12 |
+
'callback' => array( $this, 'get_items' ),
|
13 |
+
'args' => array(
|
14 |
+
'post_type' => array(
|
15 |
+
'sanitize_callback' => 'sanitize_key',
|
|
|
|
|
16 |
),
|
17 |
),
|
18 |
+
) );
|
19 |
+
|
20 |
+
register_rest_route( 'wp/v2', '/types/schema', array(
|
21 |
+
'methods' => WP_REST_Server::READABLE,
|
22 |
+
'callback' => array( $this, 'get_public_item_schema' ),
|
23 |
) );
|
24 |
|
25 |
register_rest_route( 'wp/v2', '/types/(?P<type>[\w-]+)', array(
|
26 |
+
'methods' => WP_REST_Server::READABLE,
|
27 |
+
'callback' => array( $this, 'get_item' ),
|
|
|
|
|
|
|
28 |
) );
|
29 |
}
|
30 |
|
lib/endpoints/class-wp-rest-posts-controller.php
CHANGED
@@ -27,14 +27,18 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
|
|
27 |
'default' => 10,
|
28 |
'sanitize_callback' => 'absint',
|
29 |
),
|
30 |
-
'filter' => array(),
|
31 |
);
|
32 |
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
register_rest_route( 'wp/v2', '/' . $base, array(
|
34 |
array(
|
35 |
'methods' => WP_REST_Server::READABLE,
|
36 |
'callback' => array( $this, 'get_items' ),
|
37 |
-
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
38 |
'args' => $posts_args,
|
39 |
),
|
40 |
array(
|
@@ -43,8 +47,6 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
|
|
43 |
'permission_callback' => array( $this, 'create_item_permissions_check' ),
|
44 |
'args' => $this->get_endpoint_args_for_item_schema( true ),
|
45 |
),
|
46 |
-
|
47 |
-
'schema' => array( $this, 'get_public_item_schema' ),
|
48 |
) );
|
49 |
register_rest_route( 'wp/v2', '/' . $base . '/(?P<id>[\d]+)', array(
|
50 |
array(
|
@@ -73,8 +75,10 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
|
|
73 |
),
|
74 |
),
|
75 |
),
|
76 |
-
|
77 |
-
|
|
|
|
|
78 |
) );
|
79 |
}
|
80 |
|
@@ -85,17 +89,11 @@ 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
|
89 |
-
$args['paged'] = $request['page'];
|
90 |
-
$args['posts_per_page'] = $request['per_page'];
|
91 |
-
|
92 |
-
if ( isset( $request['filter'] ) ) {
|
93 |
-
$args = array_merge( $args, $request['filter'] );
|
94 |
-
unset( $args['filter'] );
|
95 |
-
}
|
96 |
-
|
97 |
-
// Force the post_type argument, since it's not a user input variable
|
98 |
$args['post_type'] = $this->post_type;
|
|
|
|
|
|
|
99 |
|
100 |
/**
|
101 |
* Alter the query arguments for a request.
|
@@ -225,7 +223,12 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
|
|
225 |
|
226 |
$this->update_additional_fields_for_object( get_post( $post_id ), $request );
|
227 |
|
228 |
-
|
|
|
|
|
|
|
|
|
|
|
229 |
|
230 |
$response = $this->get_item( array(
|
231 |
'id' => $post_id,
|
@@ -367,23 +370,6 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
|
|
367 |
return $response;
|
368 |
}
|
369 |
|
370 |
-
/**
|
371 |
-
* Check if a given request has access to read /posts
|
372 |
-
*
|
373 |
-
* @param WP_REST_Request $request Full details about the request.
|
374 |
-
* @return bool|WP_Error
|
375 |
-
*/
|
376 |
-
public function get_items_permissions_check( $request ) {
|
377 |
-
|
378 |
-
$post_type = get_post_type_object( $this->post_type );
|
379 |
-
|
380 |
-
if ( 'edit' === $request['context'] && ! current_user_can( $post_type->cap->edit_posts ) ) {
|
381 |
-
return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to edit these posts in this post type' ), array( 'status' => 403 ) );
|
382 |
-
}
|
383 |
-
|
384 |
-
return true;
|
385 |
-
}
|
386 |
-
|
387 |
/**
|
388 |
* Check if a given request has access to read a post
|
389 |
*
|
@@ -395,7 +381,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
|
|
395 |
$post = get_post( (int) $request['id'] );
|
396 |
|
397 |
if ( 'edit' === $request['context'] && $post && ! $this->check_update_permission( $post ) ) {
|
398 |
-
return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to
|
399 |
}
|
400 |
|
401 |
if ( $post ) {
|
@@ -682,7 +668,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
|
|
682 |
}
|
683 |
// Post slug
|
684 |
if ( isset( $request['slug'] ) ) {
|
685 |
-
$prepared_post->post_name = $request['slug'];
|
686 |
}
|
687 |
|
688 |
// Author
|
@@ -732,12 +718,12 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
|
|
732 |
|
733 |
// Comment status
|
734 |
if ( ! empty( $schema['properties']['comment_status'] ) && ! empty( $request['comment_status'] ) ) {
|
735 |
-
$prepared_post->comment_status = $request['comment_status'];
|
736 |
}
|
737 |
|
738 |
// Ping status
|
739 |
if ( ! empty( $schema['properties']['ping_status'] ) && ! empty( $request['ping_status'] ) ) {
|
740 |
-
$prepared_post->ping_status = $request['ping_status'];
|
741 |
}
|
742 |
|
743 |
return apply_filters( 'rest_pre_insert_' . $this->post_type, $prepared_post, $request );
|
@@ -751,7 +737,7 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
|
|
751 |
* @return WP_Error|string $post_status
|
752 |
*/
|
753 |
protected function handle_status_param( $post_status, $post_type ) {
|
754 |
-
$post_status = $post_status;
|
755 |
|
756 |
switch ( $post_status ) {
|
757 |
case 'draft':
|
@@ -1152,8 +1138,13 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
|
|
1152 |
continue;
|
1153 |
}
|
1154 |
|
1155 |
-
|
1156 |
-
|
|
|
|
|
|
|
|
|
|
|
1157 |
|
1158 |
$links['http://v2.wp-api.org/term'][] = array(
|
1159 |
'href' => $terms_url,
|
@@ -1253,9 +1244,6 @@ class WP_REST_Posts_Controller extends WP_REST_Controller {
|
|
1253 |
'description' => 'An alphanumeric identifier for the object unique to its type.',
|
1254 |
'type' => 'string',
|
1255 |
'context' => array( 'view', 'edit', 'embed' ),
|
1256 |
-
'arg_options' => array(
|
1257 |
-
'sanitize_callback' => 'sanitize_title',
|
1258 |
-
),
|
1259 |
),
|
1260 |
'status' => array(
|
1261 |
'description' => 'A named status for the object.',
|
27 |
'default' => 10,
|
28 |
'sanitize_callback' => 'absint',
|
29 |
),
|
|
|
30 |
);
|
31 |
|
32 |
+
foreach ( $this->get_allowed_query_vars() as $var ) {
|
33 |
+
if ( ! isset( $posts_args[ $var ] ) ) {
|
34 |
+
$posts_args[ $var ] = array();
|
35 |
+
}
|
36 |
+
}
|
37 |
+
|
38 |
register_rest_route( 'wp/v2', '/' . $base, array(
|
39 |
array(
|
40 |
'methods' => WP_REST_Server::READABLE,
|
41 |
'callback' => array( $this, 'get_items' ),
|
|
|
42 |
'args' => $posts_args,
|
43 |
),
|
44 |
array(
|
47 |
'permission_callback' => array( $this, 'create_item_permissions_check' ),
|
48 |
'args' => $this->get_endpoint_args_for_item_schema( true ),
|
49 |
),
|
|
|
|
|
50 |
) );
|
51 |
register_rest_route( 'wp/v2', '/' . $base . '/(?P<id>[\d]+)', array(
|
52 |
array(
|
75 |
),
|
76 |
),
|
77 |
),
|
78 |
+
) );
|
79 |
+
register_rest_route( 'wp/v2', '/' . $base . '/schema', array(
|
80 |
+
'methods' => WP_REST_Server::READABLE,
|
81 |
+
'callback' => array( $this, 'get_public_item_schema' ),
|
82 |
) );
|
83 |
}
|
84 |
|
89 |
* @return WP_Error|WP_REST_Response
|
90 |
*/
|
91 |
public function get_items( $request ) {
|
92 |
+
$args = (array) $request->get_params();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
93 |
$args['post_type'] = $this->post_type;
|
94 |
+
$args['paged'] = $args['page'];
|
95 |
+
$args['posts_per_page'] = $args['per_page'];
|
96 |
+
unset( $args['page'] );
|
97 |
|
98 |
/**
|
99 |
* Alter the query arguments for a request.
|
223 |
|
224 |
$this->update_additional_fields_for_object( get_post( $post_id ), $request );
|
225 |
|
226 |
+
/**
|
227 |
+
* @TODO: Enable rest_insert_post() action after
|
228 |
+
* Media Controller has been migrated to new style.
|
229 |
+
*
|
230 |
+
* do_action( 'rest_insert_post', $post, $request, true );
|
231 |
+
*/
|
232 |
|
233 |
$response = $this->get_item( array(
|
234 |
'id' => $post_id,
|
370 |
return $response;
|
371 |
}
|
372 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
373 |
/**
|
374 |
* Check if a given request has access to read a post
|
375 |
*
|
381 |
$post = get_post( (int) $request['id'] );
|
382 |
|
383 |
if ( 'edit' === $request['context'] && $post && ! $this->check_update_permission( $post ) ) {
|
384 |
+
return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to create password protected posts in this post type' ), array( 'status' => 403 ) );
|
385 |
}
|
386 |
|
387 |
if ( $post ) {
|
668 |
}
|
669 |
// Post slug
|
670 |
if ( isset( $request['slug'] ) ) {
|
671 |
+
$prepared_post->post_name = sanitize_title( $request['slug'] );
|
672 |
}
|
673 |
|
674 |
// Author
|
718 |
|
719 |
// Comment status
|
720 |
if ( ! empty( $schema['properties']['comment_status'] ) && ! empty( $request['comment_status'] ) ) {
|
721 |
+
$prepared_post->comment_status = sanitize_text_field( $request['comment_status'] );
|
722 |
}
|
723 |
|
724 |
// Ping status
|
725 |
if ( ! empty( $schema['properties']['ping_status'] ) && ! empty( $request['ping_status'] ) ) {
|
726 |
+
$prepared_post->ping_status = sanitize_text_field( $request['ping_status'] );
|
727 |
}
|
728 |
|
729 |
return apply_filters( 'rest_pre_insert_' . $this->post_type, $prepared_post, $request );
|
737 |
* @return WP_Error|string $post_status
|
738 |
*/
|
739 |
protected function handle_status_param( $post_status, $post_type ) {
|
740 |
+
$post_status = sanitize_text_field( $post_status );
|
741 |
|
742 |
switch ( $post_status ) {
|
743 |
case 'draft':
|
1138 |
continue;
|
1139 |
}
|
1140 |
|
1141 |
+
if ( 'post_tag' === $tax ) {
|
1142 |
+
$terms_url = rest_url( '/wp/v2/terms/tag' );
|
1143 |
+
} else {
|
1144 |
+
$terms_url = rest_url( '/wp/v2/terms/' . $tax );
|
1145 |
+
}
|
1146 |
+
|
1147 |
+
$terms_url = add_query_arg( 'post', $post->ID, $terms_url );
|
1148 |
|
1149 |
$links['http://v2.wp-api.org/term'][] = array(
|
1150 |
'href' => $terms_url,
|
1244 |
'description' => 'An alphanumeric identifier for the object unique to its type.',
|
1245 |
'type' => 'string',
|
1246 |
'context' => array( 'view', 'edit', 'embed' ),
|
|
|
|
|
|
|
1247 |
),
|
1248 |
'status' => array(
|
1249 |
'description' => 'A named status for the object.',
|
lib/endpoints/class-wp-rest-posts-terms-controller.php
CHANGED
@@ -16,21 +16,19 @@ class WP_REST_Posts_Terms_Controller extends WP_REST_Controller {
|
|
16 |
*/
|
17 |
public function register_routes() {
|
18 |
|
19 |
-
$base
|
20 |
-
$tax_base = $this->terms_controller->get_taxonomy_base( $this->taxonomy );
|
21 |
|
22 |
$query_params = $this->get_collection_params();
|
23 |
-
register_rest_route( 'wp/v2', sprintf( '/%s/(?P<post_id>[\d]+)/terms/%s', $base, $
|
24 |
array(
|
25 |
'methods' => WP_REST_Server::READABLE,
|
26 |
'callback' => array( $this, 'get_items' ),
|
27 |
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
28 |
'args' => $query_params,
|
29 |
),
|
30 |
-
'schema' => array( $this, 'get_public_item_schema' ),
|
31 |
) );
|
32 |
|
33 |
-
register_rest_route( 'wp/v2', sprintf( '/%s/(?P<post_id>[\d]+)/terms/%s/(?P<term_id>[\d]+)', $base, $
|
34 |
array(
|
35 |
'methods' => WP_REST_Server::READABLE,
|
36 |
'callback' => array( $this, 'get_item' ),
|
@@ -46,7 +44,11 @@ class WP_REST_Posts_Terms_Controller extends WP_REST_Controller {
|
|
46 |
'callback' => array( $this, 'delete_item' ),
|
47 |
'permission_callback' => array( $this, 'create_item_permissions_check' ),
|
48 |
),
|
49 |
-
|
|
|
|
|
|
|
|
|
50 |
) );
|
51 |
}
|
52 |
|
@@ -125,8 +127,7 @@ class WP_REST_Posts_Terms_Controller extends WP_REST_Controller {
|
|
125 |
return $is_request_valid;
|
126 |
}
|
127 |
|
128 |
-
$
|
129 |
-
$tt_ids = wp_set_object_terms( $post->ID, $term->term_id, $this->taxonomy, true );
|
130 |
|
131 |
if ( is_wp_error( $tt_ids ) ) {
|
132 |
return $tt_ids;
|
16 |
*/
|
17 |
public function register_routes() {
|
18 |
|
19 |
+
$base = $this->posts_controller->get_post_type_base( $this->post_type );
|
|
|
20 |
|
21 |
$query_params = $this->get_collection_params();
|
22 |
+
register_rest_route( 'wp/v2', sprintf( '/%s/(?P<post_id>[\d]+)/terms/%s', $base, $this->taxonomy ), array(
|
23 |
array(
|
24 |
'methods' => WP_REST_Server::READABLE,
|
25 |
'callback' => array( $this, 'get_items' ),
|
26 |
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
27 |
'args' => $query_params,
|
28 |
),
|
|
|
29 |
) );
|
30 |
|
31 |
+
register_rest_route( 'wp/v2', sprintf( '/%s/(?P<post_id>[\d]+)/terms/%s/(?P<term_id>[\d]+)', $base, $this->taxonomy ), array(
|
32 |
array(
|
33 |
'methods' => WP_REST_Server::READABLE,
|
34 |
'callback' => array( $this, 'get_item' ),
|
44 |
'callback' => array( $this, 'delete_item' ),
|
45 |
'permission_callback' => array( $this, 'create_item_permissions_check' ),
|
46 |
),
|
47 |
+
) );
|
48 |
+
|
49 |
+
register_rest_route( 'wp/v2', sprintf( '/%s/(?P<post_id>[\d]+)/terms/%s', $base, $this->taxonomy ) . '/schema', array(
|
50 |
+
'methods' => WP_REST_Server::READABLE,
|
51 |
+
'callback' => array( $this, 'get_public_item_schema' ),
|
52 |
) );
|
53 |
}
|
54 |
|
127 |
return $is_request_valid;
|
128 |
}
|
129 |
|
130 |
+
$tt_ids = wp_set_object_terms( $post->ID, $term_id, $this->taxonomy, true );
|
|
|
131 |
|
132 |
if ( is_wp_error( $tt_ids ) ) {
|
133 |
return $tt_ids;
|
lib/endpoints/class-wp-rest-revisions-controller.php
CHANGED
@@ -18,18 +18,14 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller {
|
|
18 |
public function register_routes() {
|
19 |
|
20 |
register_rest_route( 'wp/v2', '/' . $this->parent_base . '/(?P<parent_id>[\d]+)/revisions', array(
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
'
|
26 |
-
'
|
27 |
-
'default' => 'view',
|
28 |
-
),
|
29 |
),
|
30 |
),
|
31 |
-
|
32 |
-
'schema' => array( $this, 'get_public_item_schema' ),
|
33 |
) );
|
34 |
|
35 |
register_rest_route( 'wp/v2', '/' . $this->parent_base . '/(?P<parent_id>[\d]+)/revisions/(?P<id>[\d]+)', array(
|
@@ -48,10 +44,13 @@ class WP_REST_Revisions_Controller extends WP_REST_Controller {
|
|
48 |
'callback' => array( $this, 'delete_item' ),
|
49 |
'permission_callback' => array( $this, 'delete_item_permissions_check' ),
|
50 |
),
|
51 |
-
|
52 |
-
'schema' => array( $this, 'get_public_item_schema' ),
|
53 |
));
|
54 |
|
|
|
|
|
|
|
|
|
|
|
55 |
}
|
56 |
|
57 |
/**
|
18 |
public function register_routes() {
|
19 |
|
20 |
register_rest_route( 'wp/v2', '/' . $this->parent_base . '/(?P<parent_id>[\d]+)/revisions', array(
|
21 |
+
'methods' => WP_REST_Server::READABLE,
|
22 |
+
'callback' => array( $this, 'get_items' ),
|
23 |
+
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
24 |
+
'args' => array(
|
25 |
+
'context' => array(
|
26 |
+
'default' => 'view',
|
|
|
|
|
27 |
),
|
28 |
),
|
|
|
|
|
29 |
) );
|
30 |
|
31 |
register_rest_route( 'wp/v2', '/' . $this->parent_base . '/(?P<parent_id>[\d]+)/revisions/(?P<id>[\d]+)', array(
|
44 |
'callback' => array( $this, 'delete_item' ),
|
45 |
'permission_callback' => array( $this, 'delete_item_permissions_check' ),
|
46 |
),
|
|
|
|
|
47 |
));
|
48 |
|
49 |
+
register_rest_route( 'wp/v2', '/' . $this->parent_base . '/revisions/schema', array(
|
50 |
+
'methods' => WP_REST_Server::READABLE,
|
51 |
+
'callback' => array( $this, 'get_public_item_schema' ),
|
52 |
+
) );
|
53 |
+
|
54 |
}
|
55 |
|
56 |
/**
|
lib/endpoints/class-wp-rest-taxonomies-controller.php
CHANGED
@@ -8,25 +8,22 @@ class WP_REST_Taxonomies_Controller extends WP_REST_Controller {
|
|
8 |
public function register_routes() {
|
9 |
|
10 |
register_rest_route( 'wp/v2', '/taxonomies', array(
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
'
|
15 |
-
'
|
16 |
-
'sanitize_callback' => 'sanitize_key',
|
17 |
-
),
|
18 |
),
|
19 |
),
|
20 |
-
'schema' => array( $this, 'get_public_item_schema' ),
|
21 |
) );
|
22 |
-
|
|
|
|
|
|
|
23 |
register_rest_route( 'wp/v2', '/taxonomies/(?P<taxonomy>[\w-]+)', array(
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
'permission_callback' => array( $this, 'get_item_permissions_check' ),
|
28 |
-
),
|
29 |
-
'schema' => array( $this, 'get_public_item_schema' ),
|
30 |
) );
|
31 |
}
|
32 |
|
8 |
public function register_routes() {
|
9 |
|
10 |
register_rest_route( 'wp/v2', '/taxonomies', array(
|
11 |
+
'methods' => WP_REST_Server::READABLE,
|
12 |
+
'callback' => array( $this, 'get_items' ),
|
13 |
+
'args' => array(
|
14 |
+
'post_type' => array(
|
15 |
+
'sanitize_callback' => 'sanitize_key',
|
|
|
|
|
16 |
),
|
17 |
),
|
|
|
18 |
) );
|
19 |
+
register_rest_route( 'wp/v2', '/taxonomies/schema', array(
|
20 |
+
'methods' => WP_REST_Server::READABLE,
|
21 |
+
'callback' => array( $this, 'get_public_item_schema' ),
|
22 |
+
) );
|
23 |
register_rest_route( 'wp/v2', '/taxonomies/(?P<taxonomy>[\w-]+)', array(
|
24 |
+
'methods' => WP_REST_Server::READABLE,
|
25 |
+
'callback' => array( $this, 'get_item' ),
|
26 |
+
'permission_callback' => array( $this, 'get_item_permissions_check' ),
|
|
|
|
|
|
|
27 |
) );
|
28 |
}
|
29 |
|
lib/endpoints/class-wp-rest-terms-controller.php
CHANGED
@@ -32,10 +32,20 @@ class WP_REST_Terms_Controller extends WP_REST_Controller {
|
|
32 |
'methods' => WP_REST_Server::CREATABLE,
|
33 |
'callback' => array( $this, 'create_item' ),
|
34 |
'permission_callback' => array( $this, 'create_item_permissions_check' ),
|
35 |
-
'args' =>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
36 |
),
|
37 |
-
|
38 |
-
'schema' => array( $this, 'get_public_item_schema' ),
|
39 |
));
|
40 |
register_rest_route( 'wp/v2', '/terms/' . $base . '/(?P<id>[\d]+)', array(
|
41 |
array(
|
@@ -47,15 +57,28 @@ class WP_REST_Terms_Controller extends WP_REST_Controller {
|
|
47 |
'methods' => WP_REST_Server::EDITABLE,
|
48 |
'callback' => array( $this, 'update_item' ),
|
49 |
'permission_callback' => array( $this, 'update_item_permissions_check' ),
|
50 |
-
'args'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
),
|
52 |
array(
|
53 |
'methods' => WP_REST_Server::DELETABLE,
|
54 |
'callback' => array( $this, 'delete_item' ),
|
55 |
'permission_callback' => array( $this, 'delete_item_permissions_check' ),
|
56 |
),
|
57 |
-
|
58 |
-
|
|
|
|
|
59 |
) );
|
60 |
}
|
61 |
|
@@ -170,15 +193,6 @@ class WP_REST_Terms_Controller extends WP_REST_Controller {
|
|
170 |
|
171 |
$term = wp_insert_term( $name, $this->taxonomy, $args );
|
172 |
if ( is_wp_error( $term ) ) {
|
173 |
-
|
174 |
-
// If we're going to inform the client that the term exists, give them the identifier
|
175 |
-
// they can actually use (term_taxonomy_id) -- NOT term_id.
|
176 |
-
|
177 |
-
if ( ( $term_id = $term->get_error_data( 'term_exists' ) ) ) {
|
178 |
-
$existing_term = get_term( $term_id, $this->taxonomy );
|
179 |
-
$term->add_data( $existing_term->term_taxonomy_id, 'term_exists' );
|
180 |
-
}
|
181 |
-
|
182 |
return $term;
|
183 |
}
|
184 |
|
@@ -482,54 +496,44 @@ class WP_REST_Terms_Controller extends WP_REST_Controller {
|
|
482 |
'type' => 'integer',
|
483 |
'context' => array( 'view', 'embed' ),
|
484 |
'readonly' => true,
|
485 |
-
|
486 |
'count' => array(
|
487 |
'description' => 'Number of published posts for the object.',
|
488 |
'type' => 'integer',
|
489 |
'context' => array( 'view' ),
|
490 |
'readonly' => true,
|
491 |
-
|
492 |
'description' => array(
|
493 |
'description' => 'A human-readable description of the object.',
|
494 |
'type' => 'string',
|
495 |
'context' => array( 'view' ),
|
496 |
-
'arg_options' => array(
|
497 |
-
'sanitize_callback' => 'wp_filter_post_kses',
|
498 |
),
|
499 |
-
),
|
500 |
'link' => array(
|
501 |
'description' => 'URL to the object.',
|
502 |
'type' => 'string',
|
503 |
'format' => 'uri',
|
504 |
'context' => array( 'view', 'embed' ),
|
505 |
'readonly' => true,
|
506 |
-
|
507 |
'name' => array(
|
508 |
'description' => 'The title for the object.',
|
509 |
'type' => 'string',
|
510 |
'context' => array( 'view', 'embed' ),
|
511 |
-
'arg_options' => array(
|
512 |
-
'sanitize_callback' => 'sanitize_text_field',
|
513 |
),
|
514 |
-
'required' => true,
|
515 |
-
),
|
516 |
'slug' => array(
|
517 |
'description' => 'An alphanumeric identifier for the object unique to its type.',
|
518 |
'type' => 'string',
|
519 |
'context' => array( 'view', 'embed' ),
|
520 |
-
'arg_options' => array(
|
521 |
-
'sanitize_callback' => 'sanitize_title',
|
522 |
),
|
523 |
-
),
|
524 |
'taxonomy' => array(
|
525 |
'description' => 'Type attribution for the object.',
|
526 |
'type' => 'string',
|
527 |
'enum' => array_keys( get_taxonomies() ),
|
528 |
'context' => array( 'view', 'embed' ),
|
529 |
'readonly' => true,
|
|
|
530 |
),
|
531 |
-
)
|
532 |
-
);
|
533 |
$taxonomy = get_taxonomy( $this->taxonomy );
|
534 |
if ( $taxonomy->hierarchical ) {
|
535 |
$schema['properties']['parent'] = array(
|
32 |
'methods' => WP_REST_Server::CREATABLE,
|
33 |
'callback' => array( $this, 'create_item' ),
|
34 |
'permission_callback' => array( $this, 'create_item_permissions_check' ),
|
35 |
+
'args' => array(
|
36 |
+
'name' => array(
|
37 |
+
'required' => true,
|
38 |
+
'sanitize_callback' => 'sanitize_text_field',
|
39 |
+
),
|
40 |
+
'description' => array(
|
41 |
+
'sanitize_callback' => 'wp_filter_post_kses',
|
42 |
+
),
|
43 |
+
'slug' => array(
|
44 |
+
'sanitize_callback' => 'sanitize_title',
|
45 |
+
),
|
46 |
+
'parent' => array(),
|
47 |
+
),
|
48 |
),
|
|
|
|
|
49 |
));
|
50 |
register_rest_route( 'wp/v2', '/terms/' . $base . '/(?P<id>[\d]+)', array(
|
51 |
array(
|
57 |
'methods' => WP_REST_Server::EDITABLE,
|
58 |
'callback' => array( $this, 'update_item' ),
|
59 |
'permission_callback' => array( $this, 'update_item_permissions_check' ),
|
60 |
+
'args' => array(
|
61 |
+
'name' => array(
|
62 |
+
'sanitize_callback' => 'sanitize_text_field',
|
63 |
+
),
|
64 |
+
'description' => array(
|
65 |
+
'sanitize_callback' => 'wp_filter_post_kses',
|
66 |
+
),
|
67 |
+
'slug' => array(
|
68 |
+
'sanitize_callback' => 'sanitize_title',
|
69 |
+
),
|
70 |
+
'parent' => array(),
|
71 |
+
),
|
72 |
),
|
73 |
array(
|
74 |
'methods' => WP_REST_Server::DELETABLE,
|
75 |
'callback' => array( $this, 'delete_item' ),
|
76 |
'permission_callback' => array( $this, 'delete_item_permissions_check' ),
|
77 |
),
|
78 |
+
) );
|
79 |
+
register_rest_route( 'wp/v2', '/terms/' . $base . '/schema', array(
|
80 |
+
'methods' => WP_REST_Server::READABLE,
|
81 |
+
'callback' => array( $this, 'get_public_item_schema' ),
|
82 |
) );
|
83 |
}
|
84 |
|
193 |
|
194 |
$term = wp_insert_term( $name, $this->taxonomy, $args );
|
195 |
if ( is_wp_error( $term ) ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
196 |
return $term;
|
197 |
}
|
198 |
|
496 |
'type' => 'integer',
|
497 |
'context' => array( 'view', 'embed' ),
|
498 |
'readonly' => true,
|
499 |
+
),
|
500 |
'count' => array(
|
501 |
'description' => 'Number of published posts for the object.',
|
502 |
'type' => 'integer',
|
503 |
'context' => array( 'view' ),
|
504 |
'readonly' => true,
|
505 |
+
),
|
506 |
'description' => array(
|
507 |
'description' => 'A human-readable description of the object.',
|
508 |
'type' => 'string',
|
509 |
'context' => array( 'view' ),
|
|
|
|
|
510 |
),
|
|
|
511 |
'link' => array(
|
512 |
'description' => 'URL to the object.',
|
513 |
'type' => 'string',
|
514 |
'format' => 'uri',
|
515 |
'context' => array( 'view', 'embed' ),
|
516 |
'readonly' => true,
|
517 |
+
),
|
518 |
'name' => array(
|
519 |
'description' => 'The title for the object.',
|
520 |
'type' => 'string',
|
521 |
'context' => array( 'view', 'embed' ),
|
|
|
|
|
522 |
),
|
|
|
|
|
523 |
'slug' => array(
|
524 |
'description' => 'An alphanumeric identifier for the object unique to its type.',
|
525 |
'type' => 'string',
|
526 |
'context' => array( 'view', 'embed' ),
|
|
|
|
|
527 |
),
|
|
|
528 |
'taxonomy' => array(
|
529 |
'description' => 'Type attribution for the object.',
|
530 |
'type' => 'string',
|
531 |
'enum' => array_keys( get_taxonomies() ),
|
532 |
'context' => array( 'view', 'embed' ),
|
533 |
'readonly' => true,
|
534 |
+
),
|
535 |
),
|
536 |
+
);
|
|
|
537 |
$taxonomy = get_taxonomy( $this->taxonomy );
|
538 |
if ( $taxonomy->hierarchical ) {
|
539 |
$schema['properties']['parent'] = array(
|
lib/endpoints/class-wp-rest-users-controller.php
CHANGED
@@ -15,6 +15,7 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
|
|
15 |
array(
|
16 |
'methods' => WP_REST_Server::READABLE,
|
17 |
'callback' => array( $this, 'get_items' ),
|
|
|
18 |
'args' => $query_params,
|
19 |
),
|
20 |
array(
|
@@ -27,8 +28,6 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
|
|
27 |
),
|
28 |
) ),
|
29 |
),
|
30 |
-
|
31 |
-
'schema' => array( $this, 'get_public_item_schema' ),
|
32 |
) );
|
33 |
register_rest_route( 'wp/v2', '/users/(?P<id>[\d]+)', array(
|
34 |
array(
|
@@ -57,8 +56,6 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
|
|
57 |
'reassign' => array(),
|
58 |
),
|
59 |
),
|
60 |
-
|
61 |
-
'schema' => array( $this, 'get_public_item_schema' ),
|
62 |
) );
|
63 |
|
64 |
register_rest_route( 'wp/v2', '/users/me', array(
|
@@ -67,8 +64,12 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
|
|
67 |
'args' => array(
|
68 |
'context' => array(),
|
69 |
),
|
70 |
-
'schema' => array( $this, 'get_public_item_schema' ),
|
71 |
));
|
|
|
|
|
|
|
|
|
|
|
72 |
}
|
73 |
|
74 |
/**
|
@@ -87,24 +88,10 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
|
|
87 |
'id' => 'ID',
|
88 |
'name' => 'display_name',
|
89 |
'registered_date' => 'registered',
|
90 |
-
|
91 |
$prepared_args['orderby'] = $orderby_possibles[ $request['orderby'] ];
|
92 |
$prepared_args['search'] = $request['search'];
|
93 |
|
94 |
-
if ( ! current_user_can( 'list_users' ) ) {
|
95 |
-
$prepared_args['has_published_posts'] = true;
|
96 |
-
|
97 |
-
// Only display a public subset of information
|
98 |
-
$request['context'] = 'embed';
|
99 |
-
}
|
100 |
-
|
101 |
-
/**
|
102 |
-
* Filter arguments, before passing to WP_User_Query, when querying users via the REST API
|
103 |
-
*
|
104 |
-
* @see https://codex.wordpress.org/Class_Reference/WP_User_Query
|
105 |
-
* @param array $prepared_args Arguments for WP_User_Query
|
106 |
-
* @param WP_REST_Request $request The current request
|
107 |
-
*/
|
108 |
$prepared_args = apply_filters( 'rest_user_query', $prepared_args, $request );
|
109 |
|
110 |
$query = new WP_User_Query( $prepared_args );
|
@@ -205,6 +192,10 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
|
|
205 |
return new WP_Error( 'rest_user_exists', __( 'Cannot create existing user.' ), array( 'status' => 400 ) );
|
206 |
}
|
207 |
|
|
|
|
|
|
|
|
|
208 |
$user = $this->prepare_item_for_database( $request );
|
209 |
|
210 |
if ( is_multisite() ) {
|
@@ -234,13 +225,6 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
|
|
234 |
|
235 |
$this->update_additional_fields_for_object( $user, $request );
|
236 |
|
237 |
-
/**
|
238 |
-
* Fires after a user is created via the REST API
|
239 |
-
*
|
240 |
-
* @param object $user Data used to create user (not a WP_User object)
|
241 |
-
* @param WP_REST_Request $request Request object.
|
242 |
-
* @param bool $bool A boolean that is false.
|
243 |
-
*/
|
244 |
do_action( 'rest_insert_user', $user, $request, false );
|
245 |
|
246 |
$response = $this->get_item( array(
|
@@ -305,8 +289,10 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
|
|
305 |
'id' => $user_id,
|
306 |
'context' => 'edit',
|
307 |
));
|
|
|
|
|
308 |
|
309 |
-
return
|
310 |
}
|
311 |
|
312 |
/**
|
@@ -349,6 +335,21 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
|
|
349 |
return $orig_user;
|
350 |
}
|
351 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
352 |
/**
|
353 |
* Check if a given request has access to read a user
|
354 |
*
|
@@ -472,13 +473,6 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
|
|
472 |
|
473 |
$data->add_links( $this->prepare_links( $user ) );
|
474 |
|
475 |
-
/**
|
476 |
-
* Filter user data before returning via the REST API
|
477 |
-
*
|
478 |
-
* @param WP_REST_Response $data Response data
|
479 |
-
* @param object $user User object used to create response
|
480 |
-
* @param WP_REST_Request $request Request object.
|
481 |
-
*/
|
482 |
return apply_filters( 'rest_prepare_user', $data, $user, $request );
|
483 |
}
|
484 |
|
@@ -544,18 +538,12 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
|
|
544 |
$prepared_user->description = $request['description'];
|
545 |
}
|
546 |
if ( isset( $request['role'] ) ) {
|
547 |
-
$prepared_user->role = $request['role'];
|
548 |
}
|
549 |
if ( isset( $request['url'] ) ) {
|
550 |
$prepared_user->user_url = $request['url'];
|
551 |
}
|
552 |
|
553 |
-
/**
|
554 |
-
* Filter user data before inserting user via REST API
|
555 |
-
*
|
556 |
-
* @param object $prepared_user User object.
|
557 |
-
* @param WP_REST_Request $request Request object.
|
558 |
-
*/
|
559 |
return apply_filters( 'rest_pre_insert_user', $prepared_user, $request );
|
560 |
}
|
561 |
|
@@ -569,6 +557,10 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
|
|
569 |
protected function check_role_update( $user_id, $role ) {
|
570 |
global $wp_roles;
|
571 |
|
|
|
|
|
|
|
|
|
572 |
$potential_role = $wp_roles->role_objects[ $role ];
|
573 |
|
574 |
// Don't let anyone with 'edit_users' (admins) edit their own role to something without it.
|
@@ -603,8 +595,6 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
|
|
603 |
);
|
604 |
}
|
605 |
|
606 |
-
global $wp_roles;
|
607 |
-
|
608 |
$schema = array(
|
609 |
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
610 |
'title' => 'user',
|
@@ -621,7 +611,7 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
|
|
621 |
'description' => 'All capabilities assigned to the user.',
|
622 |
'type' => 'object',
|
623 |
'context' => array( 'view', 'edit' ),
|
624 |
-
|
625 |
'description' => array(
|
626 |
'description' => 'Description of the object.',
|
627 |
'type' => 'string',
|
@@ -642,7 +632,7 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
|
|
642 |
'type' => 'object',
|
643 |
'context' => array( 'edit' ),
|
644 |
'readonly' => true,
|
645 |
-
|
646 |
'first_name' => array(
|
647 |
'description' => 'First name for the object.',
|
648 |
'type' => 'string',
|
@@ -698,12 +688,6 @@ class WP_REST_Users_Controller extends WP_REST_Controller {
|
|
698 |
'description' => 'Roles assigned to the user.',
|
699 |
'type' => 'array',
|
700 |
'context' => array( 'view', 'edit' ),
|
701 |
-
'readonly' => true,
|
702 |
-
),
|
703 |
-
'role' => array(
|
704 |
-
'description' => 'Role assigned to the user.',
|
705 |
-
'type' => 'string',
|
706 |
-
'enum' => array_keys( $wp_roles->role_objects ),
|
707 |
),
|
708 |
'slug' => array(
|
709 |
'description' => 'An alphanumeric identifier for the object unique to its type.',
|
15 |
array(
|
16 |
'methods' => WP_REST_Server::READABLE,
|
17 |
'callback' => array( $this, 'get_items' ),
|
18 |
+
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
19 |
'args' => $query_params,
|
20 |
),
|
21 |
array(
|
28 |
),
|
29 |
) ),
|
30 |
),
|
|
|
|
|
31 |
) );
|
32 |
register_rest_route( 'wp/v2', '/users/(?P<id>[\d]+)', array(
|
33 |
array(
|
56 |
'reassign' => array(),
|
57 |
),
|
58 |
),
|
|
|
|
|
59 |
) );
|
60 |
|
61 |
register_rest_route( 'wp/v2', '/users/me', array(
|
64 |
'args' => array(
|
65 |
'context' => array(),
|
66 |
),
|
|
|
67 |
));
|
68 |
+
|
69 |
+
register_rest_route( 'wp/v2', '/users/schema', array(
|
70 |
+
'methods' => WP_REST_Server::READABLE,
|
71 |
+
'callback' => array( $this, 'get_public_item_schema' ),
|
72 |
+
) );
|
73 |
}
|
74 |
|
75 |
/**
|
88 |
'id' => 'ID',
|
89 |
'name' => 'display_name',
|
90 |
'registered_date' => 'registered',
|
91 |
+
);
|
92 |
$prepared_args['orderby'] = $orderby_possibles[ $request['orderby'] ];
|
93 |
$prepared_args['search'] = $request['search'];
|
94 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
95 |
$prepared_args = apply_filters( 'rest_user_query', $prepared_args, $request );
|
96 |
|
97 |
$query = new WP_User_Query( $prepared_args );
|
192 |
return new WP_Error( 'rest_user_exists', __( 'Cannot create existing user.' ), array( 'status' => 400 ) );
|
193 |
}
|
194 |
|
195 |
+
if ( ! empty( $request['role'] ) && ! isset( $wp_roles->role_objects[ $request['role'] ] ) ) {
|
196 |
+
return new WP_Error( 'rest_user_invalid_role', __( 'Role is invalid.' ), array( 'status' => 400 ) );
|
197 |
+
}
|
198 |
+
|
199 |
$user = $this->prepare_item_for_database( $request );
|
200 |
|
201 |
if ( is_multisite() ) {
|
225 |
|
226 |
$this->update_additional_fields_for_object( $user, $request );
|
227 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
228 |
do_action( 'rest_insert_user', $user, $request, false );
|
229 |
|
230 |
$response = $this->get_item( array(
|
289 |
'id' => $user_id,
|
290 |
'context' => 'edit',
|
291 |
));
|
292 |
+
$response = rest_ensure_response( $response );
|
293 |
+
$response->header( 'Location', rest_url( '/wp/v2/users/' . $user_id ) );
|
294 |
|
295 |
+
return $response;
|
296 |
}
|
297 |
|
298 |
/**
|
335 |
return $orig_user;
|
336 |
}
|
337 |
|
338 |
+
/**
|
339 |
+
* Check if a given request has access to list users
|
340 |
+
*
|
341 |
+
* @param WP_REST_Request $request Full details about the request.
|
342 |
+
* @return bool
|
343 |
+
*/
|
344 |
+
public function get_items_permissions_check( $request ) {
|
345 |
+
|
346 |
+
if ( ! current_user_can( 'list_users' ) ) {
|
347 |
+
return false;
|
348 |
+
}
|
349 |
+
|
350 |
+
return true;
|
351 |
+
}
|
352 |
+
|
353 |
/**
|
354 |
* Check if a given request has access to read a user
|
355 |
*
|
473 |
|
474 |
$data->add_links( $this->prepare_links( $user ) );
|
475 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
476 |
return apply_filters( 'rest_prepare_user', $data, $user, $request );
|
477 |
}
|
478 |
|
538 |
$prepared_user->description = $request['description'];
|
539 |
}
|
540 |
if ( isset( $request['role'] ) ) {
|
541 |
+
$prepared_user->role = sanitize_text_field( $request['role'] );
|
542 |
}
|
543 |
if ( isset( $request['url'] ) ) {
|
544 |
$prepared_user->user_url = $request['url'];
|
545 |
}
|
546 |
|
|
|
|
|
|
|
|
|
|
|
|
|
547 |
return apply_filters( 'rest_pre_insert_user', $prepared_user, $request );
|
548 |
}
|
549 |
|
557 |
protected function check_role_update( $user_id, $role ) {
|
558 |
global $wp_roles;
|
559 |
|
560 |
+
if ( ! isset( $wp_roles->role_objects[ $role ] ) ) {
|
561 |
+
return new WP_Error( 'rest_user_invalid_role', __( 'Role is invalid.' ), array( 'status' => 400 ) );
|
562 |
+
}
|
563 |
+
|
564 |
$potential_role = $wp_roles->role_objects[ $role ];
|
565 |
|
566 |
// Don't let anyone with 'edit_users' (admins) edit their own role to something without it.
|
595 |
);
|
596 |
}
|
597 |
|
|
|
|
|
598 |
$schema = array(
|
599 |
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
600 |
'title' => 'user',
|
611 |
'description' => 'All capabilities assigned to the user.',
|
612 |
'type' => 'object',
|
613 |
'context' => array( 'view', 'edit' ),
|
614 |
+
),
|
615 |
'description' => array(
|
616 |
'description' => 'Description of the object.',
|
617 |
'type' => 'string',
|
632 |
'type' => 'object',
|
633 |
'context' => array( 'edit' ),
|
634 |
'readonly' => true,
|
635 |
+
),
|
636 |
'first_name' => array(
|
637 |
'description' => 'First name for the object.',
|
638 |
'type' => 'string',
|
688 |
'description' => 'Roles assigned to the user.',
|
689 |
'type' => 'array',
|
690 |
'context' => array( 'view', 'edit' ),
|
|
|
|
|
|
|
|
|
|
|
|
|
691 |
),
|
692 |
'slug' => array(
|
693 |
'description' => 'An alphanumeric identifier for the object unique to its type.',
|
lib/infrastructure/class-wp-rest-request.php
CHANGED
@@ -680,7 +680,7 @@ class WP_REST_Request implements ArrayAccess {
|
|
680 |
|
681 |
$param = $this->get_param( $key );
|
682 |
|
683 |
-
if ( null !== $param && ! empty( $arg['validate_callback']
|
684 |
$valid_check = call_user_func( $arg['validate_callback'], $param, $this, $key );
|
685 |
|
686 |
if ( false === $valid_check ) {
|
680 |
|
681 |
$param = $this->get_param( $key );
|
682 |
|
683 |
+
if ( null !== $param && ! empty( $arg['validate_callback']) ) {
|
684 |
$valid_check = call_user_func( $arg['validate_callback'], $param, $this, $key );
|
685 |
|
686 |
if ( false === $valid_check ) {
|
lib/infrastructure/class-wp-rest-server.php
CHANGED
@@ -7,7 +7,7 @@
|
|
7 |
* @package WordPress
|
8 |
*/
|
9 |
|
10 |
-
require_once( ABSPATH . 'wp-admin/includes/admin.php' );
|
11 |
|
12 |
/**
|
13 |
* WordPress REST API server handler
|
@@ -15,84 +15,22 @@ require_once( ABSPATH . 'wp-admin/includes/admin.php' );
|
|
15 |
* @package WordPress
|
16 |
*/
|
17 |
class WP_REST_Server {
|
18 |
-
/**
|
19 |
-
* GET transport method.
|
20 |
-
*
|
21 |
-
* @var string
|
22 |
-
*/
|
23 |
const METHOD_GET = 'GET';
|
24 |
-
|
25 |
-
/**
|
26 |
-
* POST transport method.
|
27 |
-
*
|
28 |
-
* @var string
|
29 |
-
*/
|
30 |
const METHOD_POST = 'POST';
|
31 |
-
|
32 |
-
/**
|
33 |
-
* PUT transport method.
|
34 |
-
*
|
35 |
-
* @var string
|
36 |
-
*/
|
37 |
const METHOD_PUT = 'PUT';
|
38 |
-
|
39 |
-
/**
|
40 |
-
* PATCH transport method.
|
41 |
-
*
|
42 |
-
* @var string
|
43 |
-
*/
|
44 |
const METHOD_PATCH = 'PATCH';
|
45 |
-
|
46 |
-
/**
|
47 |
-
* DELETE transport method.
|
48 |
-
*
|
49 |
-
* @var string
|
50 |
-
*/
|
51 |
const METHOD_DELETE = 'DELETE';
|
52 |
|
53 |
-
/**
|
54 |
-
* Alias for GET transport method.
|
55 |
-
*
|
56 |
-
* @var string
|
57 |
-
*/
|
58 |
const READABLE = 'GET';
|
59 |
-
|
60 |
-
/**
|
61 |
-
* Alias for POST transport method.
|
62 |
-
*
|
63 |
-
* @var string
|
64 |
-
*/
|
65 |
const CREATABLE = 'POST';
|
66 |
-
|
67 |
-
/**
|
68 |
-
* Alias for GET, PUT, PATCH transport methods together.
|
69 |
-
*
|
70 |
-
* @var string
|
71 |
-
*/
|
72 |
const EDITABLE = 'POST, PUT, PATCH';
|
73 |
-
|
74 |
-
/**
|
75 |
-
* Alias for DELETE transport method.
|
76 |
-
*
|
77 |
-
* @var string
|
78 |
-
*/
|
79 |
const DELETABLE = 'DELETE';
|
80 |
-
|
81 |
-
/**
|
82 |
-
* Alias for GET, POST, PUT, PATCH & DELETE transport methods together.
|
83 |
-
*
|
84 |
-
* @var string
|
85 |
-
*/
|
86 |
const ALLMETHODS = 'GET, POST, PUT, PATCH, DELETE';
|
87 |
|
88 |
/**
|
89 |
* Does the endpoint accept raw JSON entities?
|
90 |
*/
|
91 |
const ACCEPT_RAW = 64;
|
92 |
-
|
93 |
-
/**
|
94 |
-
* Does the endpoint accept encoded JSON?
|
95 |
-
*/
|
96 |
const ACCEPT_JSON = 128;
|
97 |
|
98 |
/**
|
@@ -143,11 +81,6 @@ class WP_REST_Server {
|
|
143 |
'/' => array(
|
144 |
'callback' => array( $this, 'get_index' ),
|
145 |
'methods' => 'GET',
|
146 |
-
'args' => array(
|
147 |
-
'context' => array(
|
148 |
-
'default' => 'view',
|
149 |
-
),
|
150 |
-
),
|
151 |
),
|
152 |
);
|
153 |
}
|
@@ -232,7 +165,7 @@ class WP_REST_Server {
|
|
232 |
}
|
233 |
$error = compact( 'code', 'message' );
|
234 |
|
235 |
-
return
|
236 |
}
|
237 |
|
238 |
/**
|
@@ -267,7 +200,7 @@ class WP_REST_Server {
|
|
267 |
}
|
268 |
|
269 |
// Check for invalid characters (only alphanumeric allowed)
|
270 |
-
if ( ! is_string( $_GET['_jsonp'] ) || preg_match( '
|
271 |
echo $this->json_error( 'rest_callback_invalid', __( 'The JSONP callback function is invalid.' ), 400 );
|
272 |
return false;
|
273 |
}
|
@@ -302,6 +235,20 @@ class WP_REST_Server {
|
|
302 |
$result = $this->check_authentication();
|
303 |
|
304 |
if ( ! is_wp_error( $result ) ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
305 |
$result = $this->dispatch( $request );
|
306 |
}
|
307 |
|
@@ -357,13 +304,13 @@ class WP_REST_Server {
|
|
357 |
// Embed links inside the request
|
358 |
$result = $this->response_to_data( $result, isset( $_GET['_embed'] ) );
|
359 |
|
360 |
-
$result =
|
361 |
|
362 |
$json_error_message = $this->get_json_last_error();
|
363 |
if ( $json_error_message ) {
|
364 |
$json_error_obj = new WP_Error( 'rest_encode_error', $json_error_message, array( 'status' => 500 ) );
|
365 |
$result = $this->error_to_response( $json_error_obj );
|
366 |
-
$result =
|
367 |
}
|
368 |
|
369 |
if ( isset( $_GET['_jsonp'] ) ) {
|
@@ -390,12 +337,8 @@ class WP_REST_Server {
|
|
390 |
if ( ! empty( $links ) ) {
|
391 |
// Convert links to part of the data
|
392 |
$data['_links'] = $links;
|
393 |
-
|
394 |
-
|
395 |
-
// Is this a numeric array?
|
396 |
-
if ( rest_is_list( $data ) ) {
|
397 |
-
$data = array_map( array( $this, 'embed_links' ), $data );
|
398 |
-
} else {
|
399 |
$data = $this->embed_links( $data );
|
400 |
}
|
401 |
}
|
@@ -486,15 +429,13 @@ class WP_REST_Server {
|
|
486 |
}
|
487 |
|
488 |
// Embedded resources get passed context=embed
|
489 |
-
|
490 |
-
$query_params['context'] = 'embed';
|
491 |
-
}
|
492 |
|
493 |
$request = new WP_REST_Request( 'GET', $parsed['path'] );
|
494 |
$request->set_query_params( $query_params );
|
495 |
$response = $this->dispatch( $request );
|
496 |
|
497 |
-
$embeds[] = $
|
498 |
}
|
499 |
|
500 |
// Did we get any real links?
|
@@ -560,9 +501,6 @@ class WP_REST_Server {
|
|
560 |
'namespace' => array(
|
561 |
'default' => $namespace,
|
562 |
),
|
563 |
-
'context' => array(
|
564 |
-
'default' => 'view',
|
565 |
-
),
|
566 |
),
|
567 |
),
|
568 |
) );
|
@@ -652,20 +590,6 @@ class WP_REST_Server {
|
|
652 |
return array_keys( $this->namespaces );
|
653 |
}
|
654 |
|
655 |
-
/**
|
656 |
-
* Get specified options for a route.
|
657 |
-
*
|
658 |
-
* @param string $route Route pattern to fetch options for.
|
659 |
-
* @return array|null Data as an associative array if found, or null if not found.
|
660 |
-
*/
|
661 |
-
public function get_route_options( $route ) {
|
662 |
-
if ( ! isset( $this->route_options[ $route ] ) ) {
|
663 |
-
return null;
|
664 |
-
}
|
665 |
-
|
666 |
-
return $this->route_options[ $route ];
|
667 |
-
}
|
668 |
-
|
669 |
/**
|
670 |
* Match the request to a callback and call it
|
671 |
*
|
@@ -673,21 +597,6 @@ class WP_REST_Server {
|
|
673 |
* @return WP_REST_Response Response returned by the callback
|
674 |
*/
|
675 |
public function dispatch( $request ) {
|
676 |
-
/**
|
677 |
-
* Allow hijacking the request before dispatching
|
678 |
-
*
|
679 |
-
* If `$result` is non-empty, this value will be used to serve the
|
680 |
-
* request instead.
|
681 |
-
*
|
682 |
-
* @param mixed $result Response to replace the requested version with. Can be anything a normal endpoint can return, or null to not hijack the request.
|
683 |
-
* @param WP_REST_Server $this Server instance
|
684 |
-
* @param WP_REST_Request $request Request used to generate the response
|
685 |
-
*/
|
686 |
-
$result = apply_filters( 'rest_pre_dispatch', null, $this, $request );
|
687 |
-
if ( ! empty( $result ) ) {
|
688 |
-
return $result;
|
689 |
-
}
|
690 |
-
|
691 |
$method = $request->get_method();
|
692 |
$path = $request->get_route();
|
693 |
|
@@ -809,7 +718,7 @@ class WP_REST_Server {
|
|
809 |
*
|
810 |
* @return array Index entity
|
811 |
*/
|
812 |
-
public function get_index(
|
813 |
// General site data
|
814 |
$available = array(
|
815 |
'name' => get_option( 'blogname' ),
|
@@ -817,7 +726,7 @@ class WP_REST_Server {
|
|
817 |
'url' => get_option( 'siteurl' ),
|
818 |
'namespaces' => array_keys( $this->namespaces ),
|
819 |
'authentication' => array(),
|
820 |
-
'routes' => $this->
|
821 |
);
|
822 |
|
823 |
$response = new WP_REST_Response( $available );
|
@@ -853,7 +762,7 @@ class WP_REST_Server {
|
|
853 |
|
854 |
$data = array(
|
855 |
'namespace' => $namespace,
|
856 |
-
'routes' => $this->
|
857 |
);
|
858 |
$response = rest_ensure_response( $data );
|
859 |
|
@@ -876,15 +785,43 @@ class WP_REST_Server {
|
|
876 |
* Get the publicly-visible data for routes.
|
877 |
*
|
878 |
* @param array $routes Routes to get data for
|
879 |
-
* @param string $context Context for data. One of 'view', 'help'.
|
880 |
* @return array Route data to expose in indexes.
|
881 |
*/
|
882 |
-
|
883 |
$available = array();
|
884 |
// Find the available routes
|
885 |
foreach ( $routes as $route => $callbacks ) {
|
886 |
-
$data =
|
887 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
888 |
continue;
|
889 |
}
|
890 |
|
@@ -904,74 +841,6 @@ class WP_REST_Server {
|
|
904 |
return apply_filters( 'rest_route_data', $available, $routes );
|
905 |
}
|
906 |
|
907 |
-
/**
|
908 |
-
* Get publicly-visible data for the route.
|
909 |
-
*
|
910 |
-
* @param string $route Route to get data for.
|
911 |
-
* @param array $callbacks Callbacks to convert to data.
|
912 |
-
* @param string $context Context for the data.
|
913 |
-
* @return array|null Data for the route, or null if no publicly-visible data.
|
914 |
-
*/
|
915 |
-
public function get_data_for_route( $route, $callbacks, $context = 'view' ) {
|
916 |
-
$data = array(
|
917 |
-
'namespace' => '',
|
918 |
-
'methods' => array(),
|
919 |
-
'endpoints' => array(),
|
920 |
-
);
|
921 |
-
if ( isset( $this->route_options[ $route ] ) ) {
|
922 |
-
$options = $this->route_options[ $route ];
|
923 |
-
if ( isset( $options['namespace'] ) ) {
|
924 |
-
$data['namespace'] = $options['namespace'];
|
925 |
-
}
|
926 |
-
if ( isset( $options['schema'] ) && 'help' === $context ) {
|
927 |
-
$data['schema'] = call_user_func( $options['schema'] );
|
928 |
-
}
|
929 |
-
}
|
930 |
-
|
931 |
-
$route = preg_replace( '#\(\?P<(\w+?)>.*?\)#', '{$1}', $route );
|
932 |
-
|
933 |
-
foreach ( $callbacks as $callback ) {
|
934 |
-
// Skip to the next route if any callback is hidden
|
935 |
-
if ( empty( $callback['show_in_index'] ) ) {
|
936 |
-
continue;
|
937 |
-
}
|
938 |
-
|
939 |
-
$data['methods'] = array_merge( $data['methods'], array_keys( $callback['methods'] ) );
|
940 |
-
$endpoint_data = array(
|
941 |
-
'methods' => array_keys( $callback['methods'] ),
|
942 |
-
);
|
943 |
-
|
944 |
-
if ( isset( $callback['args'] ) ) {
|
945 |
-
$endpoint_data['args'] = array();
|
946 |
-
foreach ( $callback['args'] as $key => $opts ) {
|
947 |
-
$arg_data = array(
|
948 |
-
'required' => ! empty( $opts['required'] ),
|
949 |
-
);
|
950 |
-
if ( isset( $opts['default'] ) ) {
|
951 |
-
$arg_data['default'] = $opts['default'];
|
952 |
-
}
|
953 |
-
$endpoint_data['args'][ $key ] = $arg_data;
|
954 |
-
}
|
955 |
-
}
|
956 |
-
|
957 |
-
$data['endpoints'][] = $endpoint_data;
|
958 |
-
|
959 |
-
// For non-variable routes, generate links
|
960 |
-
if ( strpos( $route, '{' ) === false ) {
|
961 |
-
$data['_links'] = array(
|
962 |
-
'self' => rest_url( $route ),
|
963 |
-
);
|
964 |
-
}
|
965 |
-
}
|
966 |
-
|
967 |
-
if ( empty( $data['methods'] ) ) {
|
968 |
-
// No methods supported, hide the route
|
969 |
-
return null;
|
970 |
-
}
|
971 |
-
|
972 |
-
return $data;
|
973 |
-
}
|
974 |
-
|
975 |
/**
|
976 |
* Send a HTTP status code
|
977 |
*
|
7 |
* @package WordPress
|
8 |
*/
|
9 |
|
10 |
+
require_once ( ABSPATH . 'wp-admin/includes/admin.php' );
|
11 |
|
12 |
/**
|
13 |
* WordPress REST API server handler
|
15 |
* @package WordPress
|
16 |
*/
|
17 |
class WP_REST_Server {
|
|
|
|
|
|
|
|
|
|
|
18 |
const METHOD_GET = 'GET';
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
const METHOD_POST = 'POST';
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
const METHOD_PUT = 'PUT';
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
const METHOD_PATCH = 'PATCH';
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
const METHOD_DELETE = 'DELETE';
|
23 |
|
|
|
|
|
|
|
|
|
|
|
24 |
const READABLE = 'GET';
|
|
|
|
|
|
|
|
|
|
|
|
|
25 |
const CREATABLE = 'POST';
|
|
|
|
|
|
|
|
|
|
|
|
|
26 |
const EDITABLE = 'POST, PUT, PATCH';
|
|
|
|
|
|
|
|
|
|
|
|
|
27 |
const DELETABLE = 'DELETE';
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
const ALLMETHODS = 'GET, POST, PUT, PATCH, DELETE';
|
29 |
|
30 |
/**
|
31 |
* Does the endpoint accept raw JSON entities?
|
32 |
*/
|
33 |
const ACCEPT_RAW = 64;
|
|
|
|
|
|
|
|
|
34 |
const ACCEPT_JSON = 128;
|
35 |
|
36 |
/**
|
81 |
'/' => array(
|
82 |
'callback' => array( $this, 'get_index' ),
|
83 |
'methods' => 'GET',
|
|
|
|
|
|
|
|
|
|
|
84 |
),
|
85 |
);
|
86 |
}
|
165 |
}
|
166 |
$error = compact( 'code', 'message' );
|
167 |
|
168 |
+
return json_encode( array( $error ) );
|
169 |
}
|
170 |
|
171 |
/**
|
200 |
}
|
201 |
|
202 |
// Check for invalid characters (only alphanumeric allowed)
|
203 |
+
if ( ! is_string( $_GET['_jsonp'] ) || preg_match( '/\W\./', $_GET['_jsonp'] ) ) {
|
204 |
echo $this->json_error( 'rest_callback_invalid', __( 'The JSONP callback function is invalid.' ), 400 );
|
205 |
return false;
|
206 |
}
|
235 |
$result = $this->check_authentication();
|
236 |
|
237 |
if ( ! is_wp_error( $result ) ) {
|
238 |
+
/**
|
239 |
+
* Allow hijacking the request before dispatching
|
240 |
+
*
|
241 |
+
* If `$result` is non-empty, this value will be used to serve the
|
242 |
+
* request instead.
|
243 |
+
*
|
244 |
+
* @param mixed $result Response to replace the requested version with. Can be anything a normal endpoint can return, or null to not hijack the request.
|
245 |
+
* @param WP_REST_Server $this Server instance
|
246 |
+
* @param WP_REST_Request $request Request used to generate the response
|
247 |
+
*/
|
248 |
+
$result = apply_filters( 'rest_pre_dispatch', null, $this, $request );
|
249 |
+
}
|
250 |
+
|
251 |
+
if ( empty( $result ) ) {
|
252 |
$result = $this->dispatch( $request );
|
253 |
}
|
254 |
|
304 |
// Embed links inside the request
|
305 |
$result = $this->response_to_data( $result, isset( $_GET['_embed'] ) );
|
306 |
|
307 |
+
$result = json_encode( $result );
|
308 |
|
309 |
$json_error_message = $this->get_json_last_error();
|
310 |
if ( $json_error_message ) {
|
311 |
$json_error_obj = new WP_Error( 'rest_encode_error', $json_error_message, array( 'status' => 500 ) );
|
312 |
$result = $this->error_to_response( $json_error_obj );
|
313 |
+
$result = json_encode( $result->data[0] );
|
314 |
}
|
315 |
|
316 |
if ( isset( $_GET['_jsonp'] ) ) {
|
337 |
if ( ! empty( $links ) ) {
|
338 |
// Convert links to part of the data
|
339 |
$data['_links'] = $links;
|
340 |
+
|
341 |
+
if ( $embed ) {
|
|
|
|
|
|
|
|
|
342 |
$data = $this->embed_links( $data );
|
343 |
}
|
344 |
}
|
429 |
}
|
430 |
|
431 |
// Embedded resources get passed context=embed
|
432 |
+
$query_params['context'] = 'embed';
|
|
|
|
|
433 |
|
434 |
$request = new WP_REST_Request( 'GET', $parsed['path'] );
|
435 |
$request->set_query_params( $query_params );
|
436 |
$response = $this->dispatch( $request );
|
437 |
|
438 |
+
$embeds[] = $response;
|
439 |
}
|
440 |
|
441 |
// Did we get any real links?
|
501 |
'namespace' => array(
|
502 |
'default' => $namespace,
|
503 |
),
|
|
|
|
|
|
|
504 |
),
|
505 |
),
|
506 |
) );
|
590 |
return array_keys( $this->namespaces );
|
591 |
}
|
592 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
593 |
/**
|
594 |
* Match the request to a callback and call it
|
595 |
*
|
597 |
* @return WP_REST_Response Response returned by the callback
|
598 |
*/
|
599 |
public function dispatch( $request ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
600 |
$method = $request->get_method();
|
601 |
$path = $request->get_route();
|
602 |
|
718 |
*
|
719 |
* @return array Index entity
|
720 |
*/
|
721 |
+
public function get_index() {
|
722 |
// General site data
|
723 |
$available = array(
|
724 |
'name' => get_option( 'blogname' ),
|
726 |
'url' => get_option( 'siteurl' ),
|
727 |
'namespaces' => array_keys( $this->namespaces ),
|
728 |
'authentication' => array(),
|
729 |
+
'routes' => $this->get_route_data( $this->get_routes() ),
|
730 |
);
|
731 |
|
732 |
$response = new WP_REST_Response( $available );
|
762 |
|
763 |
$data = array(
|
764 |
'namespace' => $namespace,
|
765 |
+
'routes' => $this->get_route_data( $endpoints ),
|
766 |
);
|
767 |
$response = rest_ensure_response( $data );
|
768 |
|
785 |
* Get the publicly-visible data for routes.
|
786 |
*
|
787 |
* @param array $routes Routes to get data for
|
|
|
788 |
* @return array Route data to expose in indexes.
|
789 |
*/
|
790 |
+
protected function get_route_data( $routes ) {
|
791 |
$available = array();
|
792 |
// Find the available routes
|
793 |
foreach ( $routes as $route => $callbacks ) {
|
794 |
+
$data = array(
|
795 |
+
'namespace' => '',
|
796 |
+
'methods' => array(),
|
797 |
+
);
|
798 |
+
if ( isset( $this->route_options[ $route ] ) ) {
|
799 |
+
$options = $this->route_options[ $route ];
|
800 |
+
if ( isset( $options['namespace'] ) ) {
|
801 |
+
$data['namespace'] = $options['namespace'];
|
802 |
+
}
|
803 |
+
}
|
804 |
+
|
805 |
+
$route = preg_replace( '#\(\?P<(\w+?)>.*?\)#', '{$1}', $route );
|
806 |
+
|
807 |
+
foreach ( $callbacks as $callback ) {
|
808 |
+
// Skip to the next route if any callback is hidden
|
809 |
+
if ( empty( $callback['show_in_index'] ) ) {
|
810 |
+
continue;
|
811 |
+
}
|
812 |
+
|
813 |
+
$data['methods'] = array_merge( $data['methods'], array_keys( $callback['methods'] ) );
|
814 |
+
|
815 |
+
// For non-variable routes, generate links
|
816 |
+
if ( strpos( $route, '{' ) === false ) {
|
817 |
+
$data['_links'] = array(
|
818 |
+
'self' => rest_url( $route ),
|
819 |
+
);
|
820 |
+
}
|
821 |
+
}
|
822 |
+
|
823 |
+
if ( empty( $data['methods'] ) ) {
|
824 |
+
// No methods supported, hide the route
|
825 |
continue;
|
826 |
}
|
827 |
|
841 |
return apply_filters( 'rest_route_data', $available, $routes );
|
842 |
}
|
843 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
844 |
/**
|
845 |
* Send a HTTP status code
|
846 |
*
|
plugin.php
CHANGED
@@ -4,7 +4,7 @@
|
|
4 |
* Description: JSON-based REST API for WordPress, developed as part of GSoC 2013.
|
5 |
* Author: WP REST API Team
|
6 |
* Author URI: http://wp-api.org
|
7 |
-
* Version: 2.0-
|
8 |
* Plugin URI: https://github.com/WP-API/WP-API
|
9 |
* License: GPL2+
|
10 |
*/
|
@@ -14,7 +14,7 @@
|
|
14 |
*
|
15 |
* @var string
|
16 |
*/
|
17 |
-
define( 'REST_API_VERSION', '2.0-
|
18 |
|
19 |
/**
|
20 |
* Include our files for the API.
|
@@ -69,57 +69,20 @@ function register_rest_route( $namespace, $route, $args = array(), $override = f
|
|
69 |
'callback' => null,
|
70 |
'args' => array(),
|
71 |
);
|
72 |
-
foreach ( $args as
|
73 |
-
if ( ! is_numeric( $arg_group ) ) {
|
74 |
-
// Route option, skip here
|
75 |
-
continue;
|
76 |
-
}
|
77 |
-
|
78 |
$arg_group = array_merge( $defaults, $arg_group );
|
79 |
}
|
80 |
|
81 |
-
|
82 |
-
$full_route = '/' . trim( $namespace, '/' ) . '/' . trim( $route, '/' );
|
83 |
-
} else {
|
84 |
-
// Non-namespaced routes are not allowed, with the exception of the main
|
85 |
-
// and namespace indexes. If you really need to register a
|
86 |
-
// non-namespaced route, call `WP_REST_Server::register_route` directly.
|
87 |
-
_doing_it_wrong( 'register_rest_route', 'Routes must be namespaced with plugin name and version', 'WPAPI-2.0' );
|
88 |
-
|
89 |
-
$full_route = '/' . trim( $route, '/' );
|
90 |
-
}
|
91 |
-
|
92 |
$wp_rest_server->register_route( $namespace, $full_route, $args, $override );
|
93 |
}
|
94 |
|
95 |
/**
|
96 |
* Register a new field on an existing WordPress object type
|
97 |
*
|
98 |
-
* @
|
99 |
-
*
|
100 |
-
*
|
101 |
-
* @param string|array $object_type Object(s) the field is being registered
|
102 |
-
* to, "post"|"term"|"comment" etc.
|
103 |
-
* @param string $attribute The attribute name.
|
104 |
-
* @param array $args {
|
105 |
-
* Optional. An array of arguments used to handle the registered field.
|
106 |
-
*
|
107 |
-
* @type string|array|null $get_callback Optional. The callback function
|
108 |
-
* used to retrieve the field
|
109 |
-
* value. Default is 'null', the
|
110 |
-
* field will not be returned in
|
111 |
-
* the response.
|
112 |
-
* @type string|array|null $update_callback Optional. The callback function
|
113 |
-
* used to set and update the
|
114 |
-
* field value. Default is 'null',
|
115 |
-
* the value cannot be set or
|
116 |
-
* updated.
|
117 |
-
* @type string|array|null schema Optional. The callback function
|
118 |
-
* used to create the schema for
|
119 |
-
* this field. Default is 'null',
|
120 |
-
* no schema entry will be
|
121 |
-
* returned.
|
122 |
-
* }
|
123 |
* @return bool|wp_error
|
124 |
*/
|
125 |
function register_api_field( $object_type, $attribute, $args = array() ) {
|
@@ -170,17 +133,13 @@ add_action( 'init', '_add_extra_api_post_type_arguments', 11 );
|
|
170 |
function _add_extra_api_taxonomy_arguments() {
|
171 |
global $wp_taxonomies;
|
172 |
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
$wp_taxonomies['category']->rest_controller_class = 'WP_REST_Terms_Controller';
|
177 |
-
}
|
178 |
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
$wp_taxonomies['post_tag']->rest_controller_class = 'WP_REST_Terms_Controller';
|
183 |
-
}
|
184 |
}
|
185 |
add_action( 'init', '_add_extra_api_taxonomy_arguments', 11 );
|
186 |
|
@@ -461,18 +420,21 @@ function rest_get_url_prefix() {
|
|
461 |
* @param string $scheme Optional. Sanitization scheme. Default 'json'.
|
462 |
* @return string Full URL to the endpoint.
|
463 |
*/
|
464 |
-
function get_rest_url( $blog_id = null, $path = '
|
465 |
-
if ( empty( $path ) ) {
|
466 |
-
$path = '/';
|
467 |
-
}
|
468 |
-
|
469 |
if ( get_option( 'permalink_structure' ) ) {
|
470 |
$url = get_home_url( $blog_id, rest_get_url_prefix(), $scheme );
|
471 |
-
|
|
|
|
|
|
|
472 |
} else {
|
473 |
$url = trailingslashit( get_home_url( $blog_id, '', $scheme ) );
|
474 |
|
475 |
-
|
|
|
|
|
|
|
|
|
476 |
|
477 |
$url = add_query_arg( 'rest_route', $path, $url );
|
478 |
}
|
@@ -540,7 +502,8 @@ function rest_ensure_request( $request ) {
|
|
540 |
* immediately check for this value.
|
541 |
*
|
542 |
* @param WP_Error|WP_HTTP_ResponseInterface|mixed $response Response to check.
|
543 |
-
* @return
|
|
|
544 |
*/
|
545 |
function rest_ensure_response( $response ) {
|
546 |
if ( is_wp_error( $response ) ) {
|
@@ -623,7 +586,6 @@ function rest_handle_options_request( $response, $handler, $request ) {
|
|
623 |
}
|
624 |
|
625 |
$response = new WP_REST_Response();
|
626 |
-
$data = array();
|
627 |
|
628 |
$accept = array();
|
629 |
|
@@ -634,13 +596,15 @@ function rest_handle_options_request( $response, $handler, $request ) {
|
|
634 |
continue;
|
635 |
}
|
636 |
|
637 |
-
|
638 |
-
|
|
|
639 |
break;
|
640 |
}
|
|
|
|
|
641 |
$response->header( 'Accept', implode( ', ', $accept ) );
|
642 |
|
643 |
-
$response->set_data( $data );
|
644 |
return $response;
|
645 |
}
|
646 |
|
@@ -741,19 +705,3 @@ if ( ! function_exists( 'json_last_error_msg' ) ) :
|
|
741 |
}
|
742 |
}
|
743 |
endif;
|
744 |
-
|
745 |
-
/**
|
746 |
-
* Is the variable a list? (Numeric-indexed array)
|
747 |
-
*
|
748 |
-
* @param mixed $data Variable to check.
|
749 |
-
* @return boolean
|
750 |
-
*/
|
751 |
-
function rest_is_list( $data ) {
|
752 |
-
if ( ! is_array( $data ) ) {
|
753 |
-
return false;
|
754 |
-
}
|
755 |
-
|
756 |
-
$keys = array_keys( $data );
|
757 |
-
$string_keys = array_filter( $keys, 'is_string' );
|
758 |
-
return count( $string_keys ) === 0;
|
759 |
-
}
|
4 |
* Description: JSON-based REST API for WordPress, developed as part of GSoC 2013.
|
5 |
* Author: WP REST API Team
|
6 |
* Author URI: http://wp-api.org
|
7 |
+
* Version: 2.0-beta3.1
|
8 |
* Plugin URI: https://github.com/WP-API/WP-API
|
9 |
* License: GPL2+
|
10 |
*/
|
14 |
*
|
15 |
* @var string
|
16 |
*/
|
17 |
+
define( 'REST_API_VERSION', '2.0-beta3.1' );
|
18 |
|
19 |
/**
|
20 |
* Include our files for the API.
|
69 |
'callback' => null,
|
70 |
'args' => array(),
|
71 |
);
|
72 |
+
foreach ( $args as &$arg_group ) {
|
|
|
|
|
|
|
|
|
|
|
73 |
$arg_group = array_merge( $defaults, $arg_group );
|
74 |
}
|
75 |
|
76 |
+
$full_route = '/' . trim( $namespace, '/' ) . '/' . trim( $route, '/' );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
77 |
$wp_rest_server->register_route( $namespace, $full_route, $args, $override );
|
78 |
}
|
79 |
|
80 |
/**
|
81 |
* Register a new field on an existing WordPress object type
|
82 |
*
|
83 |
+
* @param string|array $object_type "post"|"term"|"comment" etc
|
84 |
+
* @param string $attribute The attribute name
|
85 |
+
* @param array $args
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
86 |
* @return bool|wp_error
|
87 |
*/
|
88 |
function register_api_field( $object_type, $attribute, $args = array() ) {
|
133 |
function _add_extra_api_taxonomy_arguments() {
|
134 |
global $wp_taxonomies;
|
135 |
|
136 |
+
$wp_taxonomies['category']->show_in_rest = true;
|
137 |
+
$wp_taxonomies['category']->rest_base = 'category';
|
138 |
+
$wp_taxonomies['category']->rest_controller_class = 'WP_REST_Terms_Controller';
|
|
|
|
|
139 |
|
140 |
+
$wp_taxonomies['post_tag']->show_in_rest = true;
|
141 |
+
$wp_taxonomies['post_tag']->rest_base = 'tag';
|
142 |
+
$wp_taxonomies['post_tag']->rest_controller_class = 'WP_REST_Terms_Controller';
|
|
|
|
|
143 |
}
|
144 |
add_action( 'init', '_add_extra_api_taxonomy_arguments', 11 );
|
145 |
|
420 |
* @param string $scheme Optional. Sanitization scheme. Default 'json'.
|
421 |
* @return string Full URL to the endpoint.
|
422 |
*/
|
423 |
+
function get_rest_url( $blog_id = null, $path = '', $scheme = 'json' ) {
|
|
|
|
|
|
|
|
|
424 |
if ( get_option( 'permalink_structure' ) ) {
|
425 |
$url = get_home_url( $blog_id, rest_get_url_prefix(), $scheme );
|
426 |
+
|
427 |
+
if ( ! empty( $path ) && is_string( $path ) && strpos( $path, '..' ) === false ) {
|
428 |
+
$url .= '/' . ltrim( $path, '/' );
|
429 |
+
}
|
430 |
} else {
|
431 |
$url = trailingslashit( get_home_url( $blog_id, '', $scheme ) );
|
432 |
|
433 |
+
if ( empty( $path ) ) {
|
434 |
+
$path = '/';
|
435 |
+
} else {
|
436 |
+
$path = '/' . ltrim( $path, '/' );
|
437 |
+
}
|
438 |
|
439 |
$url = add_query_arg( 'rest_route', $path, $url );
|
440 |
}
|
502 |
* immediately check for this value.
|
503 |
*
|
504 |
* @param WP_Error|WP_HTTP_ResponseInterface|mixed $response Response to check.
|
505 |
+
* @return mixed WP_Error if present, WP_HTTP_ResponseInterface if instance,
|
506 |
+
* otherwise WP_REST_Response.
|
507 |
*/
|
508 |
function rest_ensure_response( $response ) {
|
509 |
if ( is_wp_error( $response ) ) {
|
586 |
}
|
587 |
|
588 |
$response = new WP_REST_Response();
|
|
|
589 |
|
590 |
$accept = array();
|
591 |
|
596 |
continue;
|
597 |
}
|
598 |
|
599 |
+
foreach ( $endpoints as $endpoint ) {
|
600 |
+
$accept = array_merge( $accept, $endpoint['methods'] );
|
601 |
+
}
|
602 |
break;
|
603 |
}
|
604 |
+
$accept = array_keys( $accept );
|
605 |
+
|
606 |
$response->header( 'Accept', implode( ', ', $accept ) );
|
607 |
|
|
|
608 |
return $response;
|
609 |
}
|
610 |
|
705 |
}
|
706 |
}
|
707 |
endif;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
readme.txt
CHANGED
@@ -3,7 +3,7 @@ Contributors: rmccue, rachelbaker
|
|
3 |
Tags: json, rest, api, rest-api
|
4 |
Requires at least: 4.3-alpha
|
5 |
Tested up to: 4.3-beta
|
6 |
-
Stable tag: 2.0-
|
7 |
License: GPLv2 or later
|
8 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
9 |
|
@@ -36,531 +36,13 @@ For full-flavoured API support, you'll need to be using pretty permalinks to use
|
|
36 |
|
37 |
== Changelog ==
|
38 |
|
39 |
-
= 2.0 Beta
|
40 |
|
41 |
* Ensure media of private posts are private too.
|
42 |
|
43 |
Reported by @danielbachhuber on 2016-01-08.
|
44 |
|
45 |
-
= 2.0 Beta
|
46 |
-
|
47 |
-
* Show public user information through the user controller.
|
48 |
-
|
49 |
-
In WordPress as of [r32683](https://core.trac.wordpress.org/changeset/32683) (scheduled for 4.3), `WP_User_Query` now has support for getting users with published posts.
|
50 |
-
|
51 |
-
To match current behaviour in WordPress themes and feeds, we now expose this public user information. This includes the avatar, description, user ID, custom URL, display name, and URL, for users who have published at least one post on the site. This information is available to all clients; other fields and data for all users are still only available when authenticated.
|
52 |
-
|
53 |
-
(props @joehoyle, @rmccue, @Shelob9, [#1397][gh-1397], [#839][gh-839], [#1435][gh-1435])
|
54 |
-
|
55 |
-
* Send schema in OPTIONS requests and index.
|
56 |
-
|
57 |
-
Rather than using separate `/schema` endpoints, the schema for items is now available through an OPTIONS request to the route. This means that full documentation is now available for endpoints through an OPTIONS request; this includes available methods, what data you can pass to the endpoint, and the data you'll get back.
|
58 |
-
|
59 |
-
This data is now also available in the main index and namespace indexes. Simply request the index with `context=help` to get full schema data. Warning: this response will be huge. The schema for single endpoints is also available in the collection's OPTIONS response.
|
60 |
-
|
61 |
-
**⚠️ This breaks backwards compatibility** for clients relying on schemas being at their own routes. These clients should instead send `OPTIONS` requests.
|
62 |
-
|
63 |
-
Custom endpoints can register their own schema via the `schema` option on the route. This option should live side-by-side with the endpoints (similar to `relation` in WP's meta queries), so your registration call will look something like:
|
64 |
-
|
65 |
-
```php
|
66 |
-
register_rest_route( 'test-ns', '/test', array(
|
67 |
-
array(
|
68 |
-
'methods' => 'GET',
|
69 |
-
'callback' => 'my_test_callback',
|
70 |
-
),
|
71 |
-
|
72 |
-
'schema' => 'my_schema_callback',
|
73 |
-
) );
|
74 |
-
```
|
75 |
-
|
76 |
-
(props @rmccue, [#1415][gh-1415], [#1222][gh-1222], [#1305][gh-1305])
|
77 |
-
|
78 |
-
* Update JavaScript API for version 2.
|
79 |
-
|
80 |
-
Our fantastic JavaScript API from version 1 is now available for version 2, refreshed with the latest and greatest changes.
|
81 |
-
|
82 |
-
As a refresher: if you want to use it, simply make your script depend on `wp-api` when you enqueue it. If you want to enqueue the script manually, add `wp_enqueue_script( 'wp-api' )` to a callback on `wp_enqueue_scripts`.
|
83 |
-
|
84 |
-
(props @tlovett1, @kadamwhite, @nathanrice, [#1374][gh-1374], [#1320][gh-1320])
|
85 |
-
|
86 |
-
* Embed links inside items in a collection.
|
87 |
-
|
88 |
-
Previously when fetching a collection of items, you only received the items themselves. To fetch the links as well via embedding, you needed to make a request to the single item with `_embed` set.
|
89 |
-
|
90 |
-
No longer! You can now request a collection with embeds enabled (try `/wp/v2/posts?_embed`). This will embed links inside each item, allowing you to build interface items much easier (for example, post archive pages can get featured image data at the same time).
|
91 |
-
|
92 |
-
This also applies to custom endpoints. Any endpoint that returns a list of objects will automatically have the embedding applied to objects inside the list.
|
93 |
-
|
94 |
-
(props @rmccue, [#1459][gh-1459], [#865][gh-865])
|
95 |
-
|
96 |
-
* Fix potential XSS vulnerability.
|
97 |
-
|
98 |
-
Requests from other origins could potentially run code on the API domain, allowing cross-origin access to authentication cookies or similar.
|
99 |
-
|
100 |
-
Reported by @xknown on 2015-07-23.
|
101 |
-
|
102 |
-
* Move `/posts` `WP_Query` vars back to `filter` param.
|
103 |
-
|
104 |
-
In version 1, we had internal `WP_Query` vars available via `filter` (e.g. `filter[s]=search+term`). For our first betas of version 2, we tried something different and exposed these directly on the endpoint. The experiment has now concluded; we didn't like this that much, so `filter` is back.
|
105 |
-
|
106 |
-
We plan on adding nicer looking arguments to collections in future releases, with a view towards being consistent across different collections. We also plan on opening up the underlying query vars via `filter` for users, comments, and terms as well.
|
107 |
-
|
108 |
-
**⚠️ This breaks backwards compatibility** for users using WP Query vars. Simply change your `x=y` parameter to `filter[x]=y`.
|
109 |
-
|
110 |
-
(props @WP-API, [#1420][gh-1420])
|
111 |
-
|
112 |
-
* Respect `rest_base` for taxonomies.
|
113 |
-
|
114 |
-
**⚠️ This breaks backwards compatibility** by changing the `/wp/v2/posts/{id}/terms/post_tag` endpoint to `/wp/v2/posts/{id}/tag`.
|
115 |
-
|
116 |
-
(props @joehoyle, [#1466][gh-1466])
|
117 |
-
|
118 |
-
* Add permission check for retrieving the posts collection in edit context.
|
119 |
-
|
120 |
-
By extension of the fact that getting any individual post yields a forbidden context error when the `context=edit` and the user is not authorized, the user should also not be permitted to list any post items when unauthorized.
|
121 |
-
|
122 |
-
(props @danielpunkass, [#1412][gh-1412])
|
123 |
-
|
124 |
-
* Ensure the REST API URL always has a trailing slash.
|
125 |
-
|
126 |
-
Previously, when pretty permalinks were enabled, the API URL during autodiscovery looked like `/wp-json`, whereas the non-pretty permalink URL looked like `?rest_route=/`. These are now consistent, and always end with a slash character to simplify client URL building.
|
127 |
-
|
128 |
-
(props @danielpunkass, @rmccue, [#1426][gh-1426], [#1442][gh-1442], [#1455][gh-1455], [#1467][gh-1467])
|
129 |
-
|
130 |
-
* Use `wp_json_encode` instead of `json_encode`
|
131 |
-
|
132 |
-
Since WordPress 4.1, `wp_json_encode` has been available to ensure encoded values are sane, and that non-UTF8 encodings are supported. We now use this function rather than doing the encode ourselves.
|
133 |
-
|
134 |
-
(props @rmccue, @pento, [#1417][gh-1417])
|
135 |
-
|
136 |
-
* Add `role` to schema for users.
|
137 |
-
|
138 |
-
The available roles you can assign to a user are now available in the schema as an `enum`.
|
139 |
-
|
140 |
-
(props @joehoyle, [#1400][gh-1400])
|
141 |
-
|
142 |
-
* Use the schema for validation inside the comments controller.
|
143 |
-
|
144 |
-
Previously, the schema was merely a decorative element for documentation inside the comments controller. To bring it inline with our other controllers, the schema is now used internally for validation.
|
145 |
-
|
146 |
-
(props @joehoyle, [#1422][gh-1422])
|
147 |
-
|
148 |
-
* Don't set the Location header in update responses.
|
149 |
-
|
150 |
-
Previously, the Location header was sent when updating resources due to some inadvertent copypasta. This header should only be sent when creating to direct clients to the new resource, and isn't required when you're already on the correct resource.
|
151 |
-
|
152 |
-
(props @rachelbaker, [#1441][gh-1441])
|
153 |
-
|
154 |
-
* Re-enable the `rest_insert_post` action hook for `WP_REST_Posts_Controller`
|
155 |
-
|
156 |
-
This was disabled during 2.0 development to avoid breaking lots of plugins on the `json_insert_post` action. Now that we've changed namespaces and are Mostly Stable (tm), we can re-enable the action.
|
157 |
-
|
158 |
-
(props @jaredcobb, [#1427][gh-1427], [#1424][gh-1424])
|
159 |
-
|
160 |
-
* Fix post taxonomy terms link URLs.
|
161 |
-
|
162 |
-
When moving the routes in a previous beta, we forgot to correct the links on post objects to the new correct route. Sorry!
|
163 |
-
|
164 |
-
(props @rachelbaker, @joehoyle, [#1447][gh-1447], [#1383][gh-1383])
|
165 |
-
|
166 |
-
* Use `wp_get_attachment_image_src()` on the image sizes in attachments.
|
167 |
-
|
168 |
-
Since the first versions of the API, we've been building attachment URLs via `str_replace`. Who knows why we were doing this, but it caused problems with custom attachment URLs (such as CDN-hosted images). This now correctly uses the internal functions and filters.
|
169 |
-
|
170 |
-
(props @joehoyle, [#1462][gh-1462])
|
171 |
-
|
172 |
-
* Make the embed context a default, not forced.
|
173 |
-
|
174 |
-
If you want embeds to bring in full data rather than with `context=edit`, you can now change the link to specify `context=view` explicitly.
|
175 |
-
|
176 |
-
(props @rmccue, [#1464][gh-1464])
|
177 |
-
|
178 |
-
* Ensure we always use the `term_taxonomy_id` and never expose `term_id` publicly.
|
179 |
-
|
180 |
-
Previously, `term_id` was inadvertently exposed in some error responses.
|
181 |
-
|
182 |
-
(props @jdolan, [#1430][gh-1430])
|
183 |
-
|
184 |
-
* Fix adding alt text to attachments on creation.
|
185 |
-
|
186 |
-
Previously, this could only be set when updating an attachment, not when creating one.
|
187 |
-
|
188 |
-
(props @joehoyle, [#1398][gh-1398])
|
189 |
-
|
190 |
-
* Throw an error when registering routes without a namespace.
|
191 |
-
|
192 |
-
Namespaces should **always** be provided when registering routes. We now throw a `doing_it_wrong` error when attempting to register one. (Previously, this caused a warning, or an invalid internal route.)
|
193 |
-
|
194 |
-
If you *really* need to register namespaceless routes (e.g. to replicate an existing API), call `WP_REST_Server::register_route` directly rather than using the convenience function.
|
195 |
-
|
196 |
-
(props @joehoyle, @rmccue, [#1355][gh-1355])
|
197 |
-
|
198 |
-
* Show links on embeds.
|
199 |
-
|
200 |
-
Previously, links were accidentally stripped from embedded response data.
|
201 |
-
|
202 |
-
(props @rmccue, [#1472][gh-1472])
|
203 |
-
|
204 |
-
* Clarify insufficient permisssion error when editing posts.
|
205 |
-
|
206 |
-
(props @danielpunkass, [#1411][gh-1411])
|
207 |
-
|
208 |
-
* Improve @return inline docs for rest_ensure_response()
|
209 |
-
|
210 |
-
(props @Shelob9, [#1328][gh-1328])
|
211 |
-
|
212 |
-
* Check taxonomies exist before trying to set properties.
|
213 |
-
|
214 |
-
(props @joehoyle, @rachelbaker, [#1354][gh-1354])
|
215 |
-
|
216 |
-
* Update controllers to ensure we use `sanitize_callback` wherever possible.
|
217 |
-
|
218 |
-
(props @joehoyle, [#1399][gh-1399])
|
219 |
-
|
220 |
-
* Add more phpDoc documentation, and correct existing documentation.
|
221 |
-
|
222 |
-
(props @Shelob9, @rmccue, [#1432][gh-1432], [#1433][gh-1433], [#1465][gh-1465])
|
223 |
-
|
224 |
-
* Update testing infrastructure.
|
225 |
-
|
226 |
-
Travis now runs our coding standards tests in parallel, and now uses the new, faster container-based testing infrastructure.
|
227 |
-
|
228 |
-
(props @ntwb, @frozzare, [#1449][gh-1449], [#1457][gh-1457])
|
229 |
-
|
230 |
-
[View all changes](https://github.com/WP-API/WP-API/compare/2.0-beta3...2.0-beta4)
|
231 |
-
|
232 |
-
[gh-839]: https://github.com/WP-API/WP-API/issues/839
|
233 |
-
[gh-865]: https://github.com/WP-API/WP-API/issues/865
|
234 |
-
[gh-1222]: https://github.com/WP-API/WP-API/issues/1222
|
235 |
-
[gh-1305]: https://github.com/WP-API/WP-API/issues/1305
|
236 |
-
[gh-1310]: https://github.com/WP-API/WP-API/issues/1310
|
237 |
-
[gh-1320]: https://github.com/WP-API/WP-API/issues/1320
|
238 |
-
[gh-1328]: https://github.com/WP-API/WP-API/issues/1328
|
239 |
-
[gh-1354]: https://github.com/WP-API/WP-API/issues/1354
|
240 |
-
[gh-1355]: https://github.com/WP-API/WP-API/issues/1355
|
241 |
-
[gh-1372]: https://github.com/WP-API/WP-API/issues/1372
|
242 |
-
[gh-1374]: https://github.com/WP-API/WP-API/issues/1374
|
243 |
-
[gh-1383]: https://github.com/WP-API/WP-API/issues/1383
|
244 |
-
[gh-1397]: https://github.com/WP-API/WP-API/issues/1397
|
245 |
-
[gh-1398]: https://github.com/WP-API/WP-API/issues/1398
|
246 |
-
[gh-1399]: https://github.com/WP-API/WP-API/issues/1399
|
247 |
-
[gh-1400]: https://github.com/WP-API/WP-API/issues/1400
|
248 |
-
[gh-1402]: https://github.com/WP-API/WP-API/issues/1402
|
249 |
-
[gh-1411]: https://github.com/WP-API/WP-API/issues/1411
|
250 |
-
[gh-1412]: https://github.com/WP-API/WP-API/issues/1412
|
251 |
-
[gh-1413]: https://github.com/WP-API/WP-API/issues/1413
|
252 |
-
[gh-1415]: https://github.com/WP-API/WP-API/issues/1415
|
253 |
-
[gh-1417]: https://github.com/WP-API/WP-API/issues/1417
|
254 |
-
[gh-1420]: https://github.com/WP-API/WP-API/issues/1420
|
255 |
-
[gh-1422]: https://github.com/WP-API/WP-API/issues/1422
|
256 |
-
[gh-1424]: https://github.com/WP-API/WP-API/issues/1424
|
257 |
-
[gh-1426]: https://github.com/WP-API/WP-API/issues/1426
|
258 |
-
[gh-1427]: https://github.com/WP-API/WP-API/issues/1427
|
259 |
-
[gh-1430]: https://github.com/WP-API/WP-API/issues/1430
|
260 |
-
[gh-1432]: https://github.com/WP-API/WP-API/issues/1432
|
261 |
-
[gh-1433]: https://github.com/WP-API/WP-API/issues/1433
|
262 |
-
[gh-1435]: https://github.com/WP-API/WP-API/issues/1435
|
263 |
-
[gh-1441]: https://github.com/WP-API/WP-API/issues/1441
|
264 |
-
[gh-1442]: https://github.com/WP-API/WP-API/issues/1442
|
265 |
-
[gh-1447]: https://github.com/WP-API/WP-API/issues/1447
|
266 |
-
[gh-1449]: https://github.com/WP-API/WP-API/issues/1449
|
267 |
-
[gh-1455]: https://github.com/WP-API/WP-API/issues/1455
|
268 |
-
[gh-1455]: https://github.com/WP-API/WP-API/issues/1455
|
269 |
-
[gh-1457]: https://github.com/WP-API/WP-API/issues/1457
|
270 |
-
[gh-1459]: https://github.com/WP-API/WP-API/issues/1459
|
271 |
-
[gh-1462]: https://github.com/WP-API/WP-API/issues/1462
|
272 |
-
[gh-1464]: https://github.com/WP-API/WP-API/issues/1464
|
273 |
-
[gh-1465]: https://github.com/WP-API/WP-API/issues/1465
|
274 |
-
[gh-1466]: https://github.com/WP-API/WP-API/issues/1466
|
275 |
-
[gh-1467]: https://github.com/WP-API/WP-API/issues/1467
|
276 |
-
[gh-1472]: https://github.com/WP-API/WP-API/issues/1472
|
277 |
-
|
278 |
-
= 2.0 Beta 3.0 =
|
279 |
-
|
280 |
-
* Add ability to declare sanitization and default options for schema fields.
|
281 |
-
|
282 |
-
The `arg_options` array can be used to declare the sanitization callback,
|
283 |
-
default value, or requirement of a field.
|
284 |
-
|
285 |
-
(props @joehoyle, [#1345][gh-1345])
|
286 |
-
(props @joehoyle, [#1346][gh-1346])
|
287 |
-
|
288 |
-
* Expand supported parameters for creating and updating Comments.
|
289 |
-
|
290 |
-
(props @rachelbaker, [#1245][gh-1245])
|
291 |
-
|
292 |
-
* Declare collection parameters for Terms of a Post.
|
293 |
-
|
294 |
-
Define the available collection parameters in `get_collection_params()` and
|
295 |
-
allow Terms of a Post to be queried by term order.
|
296 |
-
|
297 |
-
(props @danielbachhuber, [#1332][gh-1332])
|
298 |
-
|
299 |
-
* Improve the Attachment error message for an invalid Content-Disposition
|
300 |
-
|
301 |
-
(props @danielbachhuber, [#1317][gh-1317])
|
302 |
-
|
303 |
-
* Return 200 status when updating Attachments, Comments, and Users.
|
304 |
-
|
305 |
-
(props @rachelbaker, [#1348][gh-1348])
|
306 |
-
|
307 |
-
* Remove unnecessary `handle_format_param()` method.
|
308 |
-
|
309 |
-
(props @danielbachhuber, [#1331][gh-1331])
|
310 |
-
|
311 |
-
* Add `author_avatar_url` field to the Comment response and schema.
|
312 |
-
|
313 |
-
(props @rachelbaker [#1327][gh-1327])
|
314 |
-
|
315 |
-
* Introduce `rest_do_request()` for making REST requests internally.
|
316 |
-
|
317 |
-
(props @danielbachhuber, [#1333][gh-1333])
|
318 |
-
|
319 |
-
* Remove unused DateTime class.
|
320 |
-
|
321 |
-
(props @rmccue, [#1314][gh-1314])
|
322 |
-
|
323 |
-
* Add inline documentation for `$wp_rest_server` global.
|
324 |
-
|
325 |
-
(props @Shelob9, [#1324][gh-1324])
|
326 |
-
|
327 |
-
[View all changes](https://github.com/WP-API/WP-API/compare/2.0-beta2...2.0-beta3)
|
328 |
-
[gh-1245]: https://github.com/WP-API/WP-API/issues/1245
|
329 |
-
[gh-1314]: https://github.com/WP-API/WP-API/issues/1314
|
330 |
-
[gh-1317]: https://github.com/WP-API/WP-API/issues/1317
|
331 |
-
[gh-1318]: https://github.com/WP-API/WP-API/issues/1318
|
332 |
-
[gh-1324]: https://github.com/WP-API/WP-API/issues/1324
|
333 |
-
[gh-1326]: https://github.com/WP-API/WP-API/issues/1326
|
334 |
-
[gh-1327]: https://github.com/WP-API/WP-API/issues/1327
|
335 |
-
[gh-1331]: https://github.com/WP-API/WP-API/issues/1331
|
336 |
-
[gh-1332]: https://github.com/WP-API/WP-API/issues/1332
|
337 |
-
[gh-1333]: https://github.com/WP-API/WP-API/issues/1333
|
338 |
-
[gh-1345]: https://github.com/WP-API/WP-API/issues/1345
|
339 |
-
[gh-1346]: https://github.com/WP-API/WP-API/issues/1346
|
340 |
-
[gh-1347]: https://github.com/WP-API/WP-API/issues/1347
|
341 |
-
[gh-1348]: https://github.com/WP-API/WP-API/issues/1348
|
342 |
-
|
343 |
-
= 2.0 Beta 2.0 =
|
344 |
-
|
345 |
-
* Load the WP REST API before the main query runs.
|
346 |
-
|
347 |
-
The `rest_api_loaded` function now hooks into the `parse_request` action.
|
348 |
-
This change prevents the main query from being run on every request and
|
349 |
-
allows sites to set `WP_USE_THEMES` to `false`. Previously, the main query
|
350 |
-
was always being run (`SELECT * FROM wp_posts LIMIT 10`), even though the
|
351 |
-
result was never used and couldn't be cached.
|
352 |
-
|
353 |
-
(props @rmccue, [#1270][gh-1270])
|
354 |
-
|
355 |
-
* Register a new field on an existing WordPress object type.
|
356 |
-
|
357 |
-
Introduces `register_api_field()` to add a field to an object and
|
358 |
-
its schema.
|
359 |
-
|
360 |
-
(props @joehoyle, @rachelbaker, [#927][gh-927])
|
361 |
-
(props @joehoyle, [#1207][gh-1207])
|
362 |
-
(props @joehoyle, [#1243][gh-1243])
|
363 |
-
|
364 |
-
* Add endpoints for viewing, creating, updating, and deleting Terms for a Post.
|
365 |
-
|
366 |
-
The new `WP_REST_Posts_Terms_Controller` class controller supports routes for
|
367 |
-
Terms that belong to a Post.
|
368 |
-
|
369 |
-
(props @joehoyle, @danielbachhuber, [#1216][gh-1216])
|
370 |
-
|
371 |
-
* Add pagination headers for collection queries.
|
372 |
-
|
373 |
-
The `X-WP-Total` and `X-WP-TotalPages` are now present in terms, comments,
|
374 |
-
and users collection responses.
|
375 |
-
|
376 |
-
(props @danielbachhuber, [#1182][gh-1182])
|
377 |
-
(props @danielbachhuber, [#1191][gh-1191])
|
378 |
-
(props @danielbachhuber, @joehoyle, [#1197][gh-1197])
|
379 |
-
|
380 |
-
* List registered namespaces in the index for feature detection.
|
381 |
-
|
382 |
-
The index (`/wp-json` by default) now contains a list of the available
|
383 |
-
namespaces. This allows for simple feature detection. You can grab the index
|
384 |
-
and check namespaces for `wp/v3` or `pluginname/v2`, which indicate the
|
385 |
-
supported endpoints on the site.
|
386 |
-
|
387 |
-
(props @rmccue,, [#1283][gh-1283])
|
388 |
-
|
389 |
-
* Standardize link property relations and support embedding for all resources.
|
390 |
-
|
391 |
-
Change link properties to use IANA-registered relations. Also adds embedding
|
392 |
-
support to Attachments, Comments and Terms.
|
393 |
-
|
394 |
-
(props @rmccue, @rachelbaker, [#1284][gh-1284])
|
395 |
-
|
396 |
-
* Add support for Composer dependency management.
|
397 |
-
|
398 |
-
Allows you to recursively install/update the WP REST API inside of WordPress
|
399 |
-
plugins or themes.
|
400 |
-
|
401 |
-
(props @QWp6t, [#1157][gh-1157])
|
402 |
-
|
403 |
-
* Return full objects in the delete response.
|
404 |
-
|
405 |
-
Instead of returning a random message when deleting a Post, Comment, Term, or
|
406 |
-
User provide the original resource data.
|
407 |
-
|
408 |
-
(props @danielbachhuber, [#1253][gh-1253])
|
409 |
-
(props @danielbachhuber, [#1254][gh-1254])
|
410 |
-
(props @danielbachhuber, [#1255][gh-1255])
|
411 |
-
(props @danielbachhuber, [#1256][gh-1256])
|
412 |
-
|
413 |
-
* Return programmatically readable error messages for invalid or missing
|
414 |
-
required parameters.
|
415 |
-
|
416 |
-
(props @joehoyle, [#1175][gh-1175])
|
417 |
-
|
418 |
-
* Declare supported arguments for Comment and User collection queries.
|
419 |
-
|
420 |
-
(props @danielbachhuber, [#1211][gh-1211])
|
421 |
-
(props @danielbachhuber, [#1217][gh-1217])
|
422 |
-
|
423 |
-
* Automatically validate parameters based on Schema data.
|
424 |
-
|
425 |
-
(props @joehoyle, [#1128][gh-1128])
|
426 |
-
|
427 |
-
* Use the `show_in_rest` attributes for exposing Taxonomies.
|
428 |
-
|
429 |
-
(props @joehoyle, [#1279][gh-1279])
|
430 |
-
|
431 |
-
* Handle `parent` when creating or updating a Term.
|
432 |
-
|
433 |
-
(props @joehoyle, [#1221][gh-1221])
|
434 |
-
|
435 |
-
* Limit fields returned in `embed` context User responses.
|
436 |
-
|
437 |
-
(props @rachelbaker, [#1251][gh-1251])
|
438 |
-
|
439 |
-
* Only include `parent` in term response when tax is hierarchical.
|
440 |
-
|
441 |
-
(props @danielbachhuber, [#1189][gh-1189])
|
442 |
-
|
443 |
-
* Fix bug in creating comments if `type` was not set.
|
444 |
-
|
445 |
-
(props @rachelbaker, [#1244][gh-1244])
|
446 |
-
|
447 |
-
* Rename `post_name` field to `post_slug`.
|
448 |
-
|
449 |
-
(props @danielbachhuber, [#1235][gh-1235])
|
450 |
-
|
451 |
-
* Add check when creating a user to verify the provided role is valid.
|
452 |
-
|
453 |
-
(props @rachelbaker, [#1267][gh-1267])
|
454 |
-
|
455 |
-
* Add link properties to the Post Status response.
|
456 |
-
|
457 |
-
(props @joehoyle, [#1243][gh-1243])
|
458 |
-
|
459 |
-
* Return `0` for `parent` in Post response instead of `null`.
|
460 |
-
|
461 |
-
(props @danielbachhuber, [#1269][gh-1269])
|
462 |
-
|
463 |
-
* Only link `author` when there's a valid author
|
464 |
-
|
465 |
-
(props @danielbachhuber, [#1203][gh-1203])
|
466 |
-
|
467 |
-
* Only permit querying by parent term when tax is hierarchical.
|
468 |
-
|
469 |
-
(props @danielbachhuber, [#1219][gh-1219])
|
470 |
-
|
471 |
-
* Only permit deleting posts of the proper type
|
472 |
-
|
473 |
-
(props @danielbachhuber, [#1257][gh-1257])
|
474 |
-
|
475 |
-
* Set pagination headers even when no found posts.
|
476 |
-
|
477 |
-
(props @danielbachhuber, [#1209][gh-1209])
|
478 |
-
|
479 |
-
* Correct prefix in `rest_request_parameter_order` filter.
|
480 |
-
|
481 |
-
(props @quasel, [#1158][gh-1158])
|
482 |
-
|
483 |
-
* Retool `WP_REST_Terms_Controller` to follow Posts controller pattern.
|
484 |
-
|
485 |
-
(props @danielbachhuber, [#1170][gh-1170])
|
486 |
-
|
487 |
-
* Remove unused `accept_json argument` from the `register_routes` method.
|
488 |
-
|
489 |
-
(props @quasel, [#1160][gh-1160])
|
490 |
-
|
491 |
-
* Fix typo in `sanitize_params` inline documentation.
|
492 |
-
|
493 |
-
(props @Shelob9, [#1226][gh-1226])
|
494 |
-
|
495 |
-
* Remove commented out code in dispatch method.
|
496 |
-
|
497 |
-
(props @rachelbaker, [#1162][gh-1162])
|
498 |
-
|
499 |
-
|
500 |
-
[View all changes](https://github.com/WP-API/WP-API/compare/2.0-beta1.1...2.0-beta2)
|
501 |
-
[gh-927]: https://github.com/WP-API/WP-API/issues/927
|
502 |
-
[gh-1128]: https://github.com/WP-API/WP-API/issues/1128
|
503 |
-
[gh-1157]: https://github.com/WP-API/WP-API/issues/1157
|
504 |
-
[gh-1158]: https://github.com/WP-API/WP-API/issues/1158
|
505 |
-
[gh-1160]: https://github.com/WP-API/WP-API/issues/1160
|
506 |
-
[gh-1162]: https://github.com/WP-API/WP-API/issues/1162
|
507 |
-
[gh-1168]: https://github.com/WP-API/WP-API/issues/1168
|
508 |
-
[gh-1170]: https://github.com/WP-API/WP-API/issues/1170
|
509 |
-
[gh-1171]: https://github.com/WP-API/WP-API/issues/1171
|
510 |
-
[gh-1175]: https://github.com/WP-API/WP-API/issues/1175
|
511 |
-
[gh-1176]: https://github.com/WP-API/WP-API/issues/1176
|
512 |
-
[gh-1177]: https://github.com/WP-API/WP-API/issues/1177
|
513 |
-
[gh-1181]: https://github.com/WP-API/WP-API/issues/1181
|
514 |
-
[gh-1182]: https://github.com/WP-API/WP-API/issues/1182
|
515 |
-
[gh-1188]: https://github.com/WP-API/WP-API/issues/1188
|
516 |
-
[gh-1189]: https://github.com/WP-API/WP-API/issues/1189
|
517 |
-
[gh-1191]: https://github.com/WP-API/WP-API/issues/1191
|
518 |
-
[gh-1197]: https://github.com/WP-API/WP-API/issues/1197
|
519 |
-
[gh-1200]: https://github.com/WP-API/WP-API/issues/1200
|
520 |
-
[gh-1203]: https://github.com/WP-API/WP-API/issues/1203
|
521 |
-
[gh-1207]: https://github.com/WP-API/WP-API/issues/1207
|
522 |
-
[gh-1209]: https://github.com/WP-API/WP-API/issues/1209
|
523 |
-
[gh-1210]: https://github.com/WP-API/WP-API/issues/1210
|
524 |
-
[gh-1211]: https://github.com/WP-API/WP-API/issues/1211
|
525 |
-
[gh-1216]: https://github.com/WP-API/WP-API/issues/1216
|
526 |
-
[gh-1217]: https://github.com/WP-API/WP-API/issues/1217
|
527 |
-
[gh-1219]: https://github.com/WP-API/WP-API/issues/1219
|
528 |
-
[gh-1221]: https://github.com/WP-API/WP-API/issues/1221
|
529 |
-
[gh-1226]: https://github.com/WP-API/WP-API/issues/1226
|
530 |
-
[gh-1235]: https://github.com/WP-API/WP-API/issues/1235
|
531 |
-
[gh-1243]: https://github.com/WP-API/WP-API/issues/1243
|
532 |
-
[gh-1244]: https://github.com/WP-API/WP-API/issues/1244
|
533 |
-
[gh-1249]: https://github.com/WP-API/WP-API/issues/1249
|
534 |
-
[gh-1251]: https://github.com/WP-API/WP-API/issues/1251
|
535 |
-
[gh-1253]: https://github.com/WP-API/WP-API/issues/1253
|
536 |
-
[gh-1254]: https://github.com/WP-API/WP-API/issues/1254
|
537 |
-
[gh-1255]: https://github.com/WP-API/WP-API/issues/1255
|
538 |
-
[gh-1256]: https://github.com/WP-API/WP-API/issues/1256
|
539 |
-
[gh-1257]: https://github.com/WP-API/WP-API/issues/1257
|
540 |
-
[gh-1259]: https://github.com/WP-API/WP-API/issues/1259
|
541 |
-
[gh-1267]: https://github.com/WP-API/WP-API/issues/1267
|
542 |
-
[gh-1268]: https://github.com/WP-API/WP-API/issues/1268
|
543 |
-
[gh-1269]: https://github.com/WP-API/WP-API/issues/1269
|
544 |
-
[gh-1270]: https://github.com/WP-API/WP-API/issues/1270
|
545 |
-
[gh-1276]: https://github.com/WP-API/WP-API/issues/1276
|
546 |
-
[gh-1277]: https://github.com/WP-API/WP-API/issues/1277
|
547 |
-
[gh-1279]: https://github.com/WP-API/WP-API/issues/1279
|
548 |
-
[gh-1283]: https://github.com/WP-API/WP-API/issues/1283
|
549 |
-
[gh-1284]: https://github.com/WP-API/WP-API/issues/1284
|
550 |
-
[gh-1295]: https://github.com/WP-API/WP-API/issues/1295
|
551 |
-
[gh-1301]: https://github.com/WP-API/WP-API/issues/1301
|
552 |
-
|
553 |
-
|
554 |
-
= 2.0 Beta 1.1 =
|
555 |
-
|
556 |
-
* Fix user access security vulnerability.
|
557 |
-
|
558 |
-
Authenticated users were able to escalate their privileges bypassing the
|
559 |
-
expected capabilities check.
|
560 |
-
|
561 |
-
Reported by @kacperszurek on 2015-05-16.
|
562 |
-
|
563 |
-
= 2.0 Beta 1 =
|
564 |
|
565 |
Partial rewrite and evolution of the REST API to prepare for core integration.
|
566 |
|
3 |
Tags: json, rest, api, rest-api
|
4 |
Requires at least: 4.3-alpha
|
5 |
Tested up to: 4.3-beta
|
6 |
+
Stable tag: 2.0-beta3.1
|
7 |
License: GPLv2 or later
|
8 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
9 |
|
36 |
|
37 |
== Changelog ==
|
38 |
|
39 |
+
= 2.0 Beta 3.1 =
|
40 |
|
41 |
* Ensure media of private posts are private too.
|
42 |
|
43 |
Reported by @danielbachhuber on 2016-01-08.
|
44 |
|
45 |
+
= Version 2.0 Beta 1 =
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
|
47 |
Partial rewrite and evolution of the REST API to prepare for core integration.
|
48 |
|
wp-api.js
CHANGED
@@ -1,20 +1,26 @@
|
|
1 |
-
(
|
|
|
2 |
'use strict';
|
3 |
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
window.wp = window.wp || {};
|
5 |
-
|
6 |
-
wp.api = {
|
7 |
-
models: {},
|
8 |
-
collections: {},
|
9 |
-
utils: {}
|
10 |
-
};
|
11 |
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
|
|
|
|
|
|
|
|
16 |
if ( ! Date.prototype.toISOString ) {
|
17 |
-
pad = function( number ) {
|
18 |
var r = String( number );
|
19 |
if ( r.length === 1 ) {
|
20 |
r = '0' + r;
|
@@ -34,49 +40,59 @@
|
|
34 |
};
|
35 |
}
|
36 |
|
|
|
|
|
|
|
37 |
|
38 |
-
var origParse = Date.parse;
|
39 |
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
* @param {Date} date
|
44 |
-
*/
|
45 |
-
wp.api.utils.parseISO8601 = function( date ) {
|
46 |
-
var timestamp, struct, i, k,
|
47 |
-
minutesOffset = 0,
|
48 |
-
numericKeys = [ 1, 4, 5, 6, 7, 10, 11 ];;
|
49 |
-
|
50 |
-
// ES5 §15.9.4.2 states that the string should attempt to be parsed as a Date Time String Format string
|
51 |
-
// before falling back to any implementation-specific date parsing, so that’s what we do, even if native
|
52 |
-
// implementations could be faster
|
53 |
-
// 1 YYYY 2 MM 3 DD 4 HH 5 mm 6 ss 7 msec 8 Z 9 ± 10 tzHH 11 tzmm
|
54 |
-
if ((struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(date))) {
|
55 |
-
// avoid NaN timestamps caused by “undefined” values being passed to Date.UTC
|
56 |
-
for ( i = 0; ( k = numericKeys[i] ); ++i) {
|
57 |
-
struct[k] = +struct[k] || 0;
|
58 |
-
}
|
59 |
|
60 |
-
//
|
61 |
-
|
62 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
|
64 |
-
|
65 |
-
|
66 |
|
67 |
-
|
68 |
-
|
|
|
69 |
}
|
|
|
|
|
|
|
|
|
|
|
70 |
}
|
71 |
|
72 |
-
timestamp
|
73 |
-
}
|
74 |
-
|
75 |
-
}
|
76 |
|
77 |
-
|
78 |
-
};
|
|
|
|
|
|
|
79 |
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
|
81 |
/**
|
82 |
* Array of parseable dates
|
@@ -127,7 +143,7 @@
|
|
127 |
});
|
128 |
|
129 |
// Parse the author into a User object
|
130 |
-
if ( 'undefined'
|
131 |
response.author = new wp.api.models.User( response.author );
|
132 |
}
|
133 |
|
@@ -157,7 +173,7 @@
|
|
157 |
|
158 |
var parentModel = this;
|
159 |
|
160 |
-
if (
|
161 |
/**
|
162 |
* Probably a better way to do this. Perhaps grab a cached version of the
|
163 |
* instantiated model?
|
@@ -171,7 +187,7 @@
|
|
171 |
} else {
|
172 |
// Otherwise, get the object directly
|
173 |
object = new parentModel.constructor( {
|
174 |
-
|
175 |
});
|
176 |
|
177 |
// Note that this acts asynchronously
|
@@ -198,7 +214,7 @@
|
|
198 |
sync: function( method, model, options ) {
|
199 |
options = options || {};
|
200 |
|
201 |
-
if (
|
202 |
var beforeSend = options.beforeSend;
|
203 |
|
204 |
options.beforeSend = function( xhr ) {
|
@@ -221,28 +237,35 @@
|
|
221 |
wp.api.models.User = BaseModel.extend(
|
222 |
/** @lends User.prototype */
|
223 |
{
|
224 |
-
idAttribute: '
|
225 |
|
226 |
urlRoot: WP_API_Settings.root + '/users',
|
227 |
|
228 |
defaults: {
|
229 |
-
|
230 |
-
|
231 |
-
capabilities: {},
|
232 |
-
description: '',
|
233 |
email: '',
|
234 |
-
|
|
|
235 |
first_name: '',
|
236 |
last_name: '',
|
237 |
-
link: '',
|
238 |
-
name: '',
|
239 |
nickname: '',
|
240 |
-
registered_date: new Date(),
|
241 |
-
roles: [],
|
242 |
slug: '',
|
243 |
-
|
244 |
-
|
245 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
246 |
}
|
247 |
}
|
248 |
);
|
@@ -260,11 +283,13 @@
|
|
260 |
defaults: {
|
261 |
name: '',
|
262 |
slug: null,
|
263 |
-
description: '',
|
264 |
labels: {},
|
265 |
-
types:
|
266 |
show_cloud: false,
|
267 |
-
hierarchical: false
|
|
|
|
|
|
|
268 |
}
|
269 |
}
|
270 |
);
|
@@ -272,10 +297,25 @@
|
|
272 |
/**
|
273 |
* Backbone model for term
|
274 |
*/
|
275 |
-
wp.api.models.Term = BaseModel.extend(
|
276 |
/** @lends Term.prototype */
|
277 |
{
|
278 |
-
idAttribute: '
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
279 |
|
280 |
/**
|
281 |
* Return URL for the model
|
@@ -283,25 +323,26 @@
|
|
283 |
* @returns {string}
|
284 |
*/
|
285 |
url: function() {
|
286 |
-
var id = this.get( '
|
287 |
id = id || '';
|
288 |
|
289 |
-
return WP_API_Settings.root + '/taxonomies/' + this.
|
290 |
},
|
291 |
|
292 |
defaults: {
|
293 |
-
|
294 |
name: '',
|
295 |
slug: '',
|
296 |
description: '',
|
297 |
parent: null,
|
298 |
count: 0,
|
299 |
link: '',
|
300 |
-
|
301 |
-
|
|
|
302 |
}
|
303 |
|
304 |
-
}
|
305 |
);
|
306 |
|
307 |
/**
|
@@ -310,32 +351,39 @@
|
|
310 |
wp.api.models.Post = BaseModel.extend( _.extend(
|
311 |
/** @lends Post.prototype */
|
312 |
{
|
313 |
-
idAttribute: '
|
314 |
|
315 |
urlRoot: WP_API_Settings.root + '/posts',
|
316 |
|
317 |
defaults: {
|
318 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
319 |
date: new Date(),
|
320 |
date_gmt: new Date(),
|
321 |
-
guid: {},
|
322 |
-
link: '',
|
323 |
modified: new Date(),
|
324 |
modified_gmt: new Date(),
|
325 |
-
|
326 |
slug: '',
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
content: {},
|
331 |
-
author: null,
|
332 |
-
excerpt: {},
|
333 |
-
featured_image: null,
|
334 |
comment_status: 'open',
|
335 |
ping_status: 'open',
|
336 |
sticky: false,
|
337 |
-
|
338 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
339 |
}
|
340 |
}, TimeStampedMixin, HierarchicalMixin )
|
341 |
);
|
@@ -346,32 +394,39 @@
|
|
346 |
wp.api.models.Page = BaseModel.extend( _.extend(
|
347 |
/** @lends Page.prototype */
|
348 |
{
|
349 |
-
idAttribute: '
|
350 |
|
351 |
urlRoot: WP_API_Settings.root + '/pages',
|
352 |
|
353 |
defaults: {
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
|
|
|
|
|
|
358 |
link: '',
|
|
|
359 |
modified: new Date(),
|
|
|
360 |
modified_gmt: new Date(),
|
361 |
-
|
|
|
|
|
362 |
slug: '',
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
content: {},
|
367 |
-
author: null,
|
368 |
-
excerpt: {},
|
369 |
-
featured_image: null,
|
370 |
comment_status: 'closed',
|
371 |
-
ping_status: '
|
372 |
-
|
373 |
-
|
374 |
-
|
|
|
|
|
|
|
|
|
375 |
}
|
376 |
}, TimeStampedMixin, HierarchicalMixin )
|
377 |
);
|
@@ -379,39 +434,34 @@
|
|
379 |
/**
|
380 |
* Backbone model for revisions
|
381 |
*/
|
382 |
-
wp.api.models.Revision =
|
383 |
/** @lends Revision.prototype */
|
384 |
{
|
385 |
-
idAttribute: 'id',
|
386 |
-
|
387 |
/**
|
388 |
-
* Return URL for
|
389 |
*
|
390 |
* @returns {string}
|
391 |
*/
|
392 |
url: function() {
|
393 |
-
var
|
|
|
|
|
|
|
|
|
394 |
|
395 |
-
return WP_API_Settings.root + '/posts/' +
|
396 |
},
|
397 |
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
parent: 0,
|
407 |
-
slug: '',
|
408 |
-
title: {},
|
409 |
-
content: {},
|
410 |
-
excerpt: {},
|
411 |
-
_links: {}
|
412 |
}
|
413 |
-
|
414 |
-
}, TimeStampedMixin, HierarchicalMixin )
|
415 |
);
|
416 |
|
417 |
/**
|
@@ -420,34 +470,41 @@
|
|
420 |
wp.api.models.Media = BaseModel.extend( _.extend(
|
421 |
/** @lends Media.prototype */
|
422 |
{
|
423 |
-
idAttribute: '
|
424 |
|
425 |
urlRoot: WP_API_Settings.root + '/media',
|
426 |
|
427 |
defaults: {
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
|
|
|
|
|
|
432 |
link: '',
|
|
|
433 |
modified: new Date(),
|
434 |
-
|
435 |
-
password: '',
|
436 |
slug: '',
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
author: null,
|
441 |
comment_status: 'open',
|
442 |
ping_status: 'open',
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
448 |
-
|
449 |
-
|
450 |
-
|
|
|
|
|
|
|
|
|
|
|
451 |
},
|
452 |
|
453 |
/**
|
@@ -468,26 +525,22 @@
|
|
468 |
wp.api.models.Comment = BaseModel.extend( _.extend(
|
469 |
/** @lends Comment.prototype */
|
470 |
{
|
471 |
-
idAttribute: '
|
472 |
|
473 |
defaults: {
|
474 |
-
|
475 |
-
author: null,
|
476 |
-
author_email: '',
|
477 |
-
author_ip: '',
|
478 |
-
author_name: '',
|
479 |
-
author_url: '',
|
480 |
-
author_user_agent: '',
|
481 |
-
content: {},
|
482 |
-
date: new Date(),
|
483 |
-
date_gmt: new Date(),
|
484 |
-
karma: 0,
|
485 |
-
link: '',
|
486 |
-
parent: 0,
|
487 |
post: null,
|
|
|
488 |
status: 'hold',
|
489 |
type: '',
|
490 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
491 |
},
|
492 |
|
493 |
/**
|
@@ -499,7 +552,7 @@
|
|
499 |
var post_id = this.get( 'post' );
|
500 |
post_id = post_id || '';
|
501 |
|
502 |
-
var id = this.get( '
|
503 |
id = id || '';
|
504 |
|
505 |
return WP_API_Settings.root + '/posts/' + post_id + '/comments/' + id;
|
@@ -522,7 +575,13 @@
|
|
522 |
name: '',
|
523 |
description: '',
|
524 |
labels: {},
|
525 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
526 |
},
|
527 |
|
528 |
/**
|
@@ -563,7 +622,9 @@
|
|
563 |
'private': false,
|
564 |
queryable: true,
|
565 |
show_in_list: true,
|
566 |
-
|
|
|
|
|
567 |
},
|
568 |
|
569 |
/**
|
@@ -586,9 +647,13 @@
|
|
586 |
}
|
587 |
);
|
588 |
|
589 |
-
|
590 |
-
|
591 |
-
|
|
|
|
|
|
|
|
|
592 |
var BaseCollection = Backbone.Collection.extend(
|
593 |
/** @lends BaseCollection.prototype */
|
594 |
{
|
@@ -617,45 +682,46 @@
|
|
617 |
*/
|
618 |
sync: function( method, model, options ) {
|
619 |
options = options || {};
|
620 |
-
var beforeSend = options.beforeSend
|
621 |
-
self = this;
|
622 |
|
623 |
-
if (
|
624 |
options.beforeSend = function( xhr ) {
|
625 |
xhr.setRequestHeader( 'X-WP-Nonce', WP_API_Settings.nonce );
|
626 |
|
627 |
if ( beforeSend ) {
|
628 |
-
return beforeSend.apply(
|
629 |
}
|
630 |
};
|
631 |
}
|
632 |
|
633 |
if ( 'read' === method ) {
|
|
|
|
|
634 |
if ( options.data ) {
|
635 |
-
|
636 |
|
637 |
-
delete
|
638 |
} else {
|
639 |
-
|
640 |
}
|
641 |
|
642 |
-
if (
|
643 |
-
|
644 |
-
|
645 |
-
|
646 |
} else {
|
647 |
-
|
648 |
}
|
649 |
|
650 |
var success = options.success;
|
651 |
options.success = function( data, textStatus, request ) {
|
652 |
-
|
653 |
-
|
654 |
|
655 |
-
if (
|
656 |
-
|
657 |
} else {
|
658 |
-
|
659 |
}
|
660 |
|
661 |
if ( success ) {
|
@@ -679,7 +745,7 @@
|
|
679 |
|
680 |
_.extend( options.data, this.state.data );
|
681 |
|
682 |
-
if (
|
683 |
if ( ! this.hasMore() ) {
|
684 |
return false;
|
685 |
}
|
@@ -753,15 +819,10 @@
|
|
753 |
wp.api.collections.PostStatuses = BaseCollection.extend(
|
754 |
/** @lends PostStatuses.prototype */
|
755 |
{
|
756 |
-
url: WP_API_Settings.root + '/statuses',
|
757 |
|
758 |
-
model: wp.api.models.PostStatus
|
759 |
|
760 |
-
parse: function( response ) {
|
761 |
-
var responseArray = _.values( response );
|
762 |
-
|
763 |
-
return this.constructor.__super__.parse.call( this, responseArray );
|
764 |
-
}
|
765 |
}
|
766 |
);
|
767 |
|
@@ -797,12 +858,29 @@
|
|
797 |
{
|
798 |
model: wp.api.models.Comment,
|
799 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
800 |
/**
|
801 |
* Return URL for collection
|
802 |
*
|
803 |
* @returns {string}
|
804 |
*/
|
805 |
-
url:
|
|
|
|
|
806 |
}
|
807 |
);
|
808 |
|
@@ -814,32 +892,20 @@
|
|
814 |
{
|
815 |
model: wp.api.models.PostType,
|
816 |
|
817 |
-
url: WP_API_Settings.root + '/types'
|
818 |
-
|
819 |
-
parse: function( response ) {
|
820 |
-
var responseArray = [];
|
821 |
-
|
822 |
-
for ( var property in response ) {
|
823 |
-
if ( response.hasOwnProperty( property ) ) {
|
824 |
-
responseArray.push( response[property] );
|
825 |
-
}
|
826 |
-
}
|
827 |
-
|
828 |
-
return this.constructor.__super__.parse.call( this, responseArray );
|
829 |
-
}
|
830 |
}
|
831 |
);
|
832 |
|
833 |
/**
|
834 |
* Backbone terms collection
|
835 |
-
*
|
836 |
-
* Usage: new wp.api.collections.Terms( {}, { taxonomy: 'taxonomy-slug' } )
|
837 |
*/
|
838 |
wp.api.collections.Terms = BaseCollection.extend(
|
839 |
/** @lends Terms.prototype */
|
840 |
{
|
841 |
model: wp.api.models.Term,
|
842 |
|
|
|
|
|
843 |
taxonomy: 'category',
|
844 |
|
845 |
/**
|
@@ -848,11 +914,29 @@
|
|
848 |
* @constructs
|
849 |
*/
|
850 |
initialize: function( models, options ) {
|
851 |
-
|
852 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
853 |
}
|
854 |
|
855 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
856 |
},
|
857 |
|
858 |
/**
|
@@ -861,15 +945,13 @@
|
|
861 |
* @returns {string}
|
862 |
*/
|
863 |
url: function() {
|
864 |
-
return WP_API_Settings.root + '/
|
865 |
}
|
866 |
}
|
867 |
);
|
868 |
|
869 |
/**
|
870 |
* Backbone revisions collection
|
871 |
-
*
|
872 |
-
* Usage: new wp.api.collections.Revisions( {}, { parent: POST_ID } )
|
873 |
*/
|
874 |
wp.api.collections.Revisions = BaseCollection.extend(
|
875 |
/** @lends Revisions.prototype */
|
@@ -902,12 +984,4 @@
|
|
902 |
}
|
903 |
);
|
904 |
|
905 |
-
|
906 |
-
* Todo: Handle schema endpoints
|
907 |
-
*/
|
908 |
-
|
909 |
-
/**
|
910 |
-
* Todo: Handle post meta
|
911 |
-
*/
|
912 |
-
|
913 |
-
})( WP_API_Settings, Backbone, _, window, ( void 0 ) );
|
1 |
+
(function( window, undefined ) {
|
2 |
+
|
3 |
'use strict';
|
4 |
|
5 |
+
function WP_API() {
|
6 |
+
this.models = {};
|
7 |
+
this.collections = {};
|
8 |
+
this.views = {};
|
9 |
+
}
|
10 |
+
|
11 |
window.wp = window.wp || {};
|
12 |
+
wp.api = wp.api || new WP_API();
|
|
|
|
|
|
|
|
|
|
|
13 |
|
14 |
+
})( window );
|
15 |
+
|
16 |
+
(function( Backbone, _, window, undefined ) {
|
17 |
+
|
18 |
+
//'use strict';
|
19 |
+
|
20 |
+
// ECMAScript 5 shim, from MDN
|
21 |
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString
|
22 |
if ( ! Date.prototype.toISOString ) {
|
23 |
+
var pad = function( number ) {
|
24 |
var r = String( number );
|
25 |
if ( r.length === 1 ) {
|
26 |
r = '0' + r;
|
40 |
};
|
41 |
}
|
42 |
|
43 |
+
function WP_API_Utils() {
|
44 |
+
var origParse = Date.parse,
|
45 |
+
numericKeys = [ 1, 4, 5, 6, 7, 10, 11 ];
|
46 |
|
|
|
47 |
|
48 |
+
this.parseISO8601 = function( date ) {
|
49 |
+
var timestamp, struct, i, k,
|
50 |
+
minutesOffset = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
|
52 |
+
// ES5 §15.9.4.2 states that the string should attempt to be parsed as a Date Time String Format string
|
53 |
+
// before falling back to any implementation-specific date parsing, so that’s what we do, even if native
|
54 |
+
// implementations could be faster
|
55 |
+
// 1 YYYY 2 MM 3 DD 4 HH 5 mm 6 ss 7 msec 8 Z 9 ± 10 tzHH 11 tzmm
|
56 |
+
if ((struct = /^(\d{4}|[+\-]\d{6})(?:-(\d{2})(?:-(\d{2}))?)?(?:T(\d{2}):(\d{2})(?::(\d{2})(?:\.(\d{3}))?)?(?:(Z)|([+\-])(\d{2})(?::(\d{2}))?)?)?$/.exec(date))) {
|
57 |
+
// avoid NaN timestamps caused by “undefined” values being passed to Date.UTC
|
58 |
+
for ( i = 0; ( k = numericKeys[i] ); ++i) {
|
59 |
+
struct[k] = +struct[k] || 0;
|
60 |
+
}
|
61 |
+
|
62 |
+
// allow undefined days and months
|
63 |
+
struct[2] = ( +struct[2] || 1 ) - 1;
|
64 |
+
struct[3] = +struct[3] || 1;
|
65 |
|
66 |
+
if ( struct[8] !== 'Z' && struct[9] !== undefined ) {
|
67 |
+
minutesOffset = struct[10] * 60 + struct[11];
|
68 |
|
69 |
+
if ( struct[9] === '+' ) {
|
70 |
+
minutesOffset = 0 - minutesOffset;
|
71 |
+
}
|
72 |
}
|
73 |
+
|
74 |
+
timestamp = Date.UTC( struct[1], struct[2], struct[3], struct[4], struct[5] + minutesOffset, struct[6], struct[7] );
|
75 |
+
}
|
76 |
+
else {
|
77 |
+
timestamp = origParse ? origParse( date ) : NaN;
|
78 |
}
|
79 |
|
80 |
+
return timestamp;
|
81 |
+
};
|
82 |
+
}
|
|
|
83 |
|
84 |
+
window.wp = window.wp || {};
|
85 |
+
wp.api = wp.api || {};
|
86 |
+
wp.api.utils = wp.api.utils || new WP_API_Utils();
|
87 |
+
|
88 |
+
})( Backbone, _, window );
|
89 |
|
90 |
+
/* global WP_API_Settings:false */
|
91 |
+
// Suppress warning about parse function's unused "options" argument:
|
92 |
+
/* jshint unused:false */
|
93 |
+
(function( wp, WP_API_Settings, Backbone, _, window, undefined ) {
|
94 |
+
|
95 |
+
'use strict';
|
96 |
|
97 |
/**
|
98 |
* Array of parseable dates
|
143 |
});
|
144 |
|
145 |
// Parse the author into a User object
|
146 |
+
if ( response.author !== 'undefined' ) {
|
147 |
response.author = new wp.api.models.User( response.author );
|
148 |
}
|
149 |
|
173 |
|
174 |
var parentModel = this;
|
175 |
|
176 |
+
if ( typeof this.parentModel !== 'undefined' ) {
|
177 |
/**
|
178 |
* Probably a better way to do this. Perhaps grab a cached version of the
|
179 |
* instantiated model?
|
187 |
} else {
|
188 |
// Otherwise, get the object directly
|
189 |
object = new parentModel.constructor( {
|
190 |
+
ID: parent
|
191 |
});
|
192 |
|
193 |
// Note that this acts asynchronously
|
214 |
sync: function( method, model, options ) {
|
215 |
options = options || {};
|
216 |
|
217 |
+
if ( typeof WP_API_Settings.nonce !== 'undefined' ) {
|
218 |
var beforeSend = options.beforeSend;
|
219 |
|
220 |
options.beforeSend = function( xhr ) {
|
237 |
wp.api.models.User = BaseModel.extend(
|
238 |
/** @lends User.prototype */
|
239 |
{
|
240 |
+
idAttribute: 'ID',
|
241 |
|
242 |
urlRoot: WP_API_Settings.root + '/users',
|
243 |
|
244 |
defaults: {
|
245 |
+
ID: null,
|
246 |
+
username: '',
|
|
|
|
|
247 |
email: '',
|
248 |
+
password: '',
|
249 |
+
name: '',
|
250 |
first_name: '',
|
251 |
last_name: '',
|
|
|
|
|
252 |
nickname: '',
|
|
|
|
|
253 |
slug: '',
|
254 |
+
URL: '',
|
255 |
+
avatar: '',
|
256 |
+
meta: {
|
257 |
+
links: {}
|
258 |
+
}
|
259 |
+
},
|
260 |
+
|
261 |
+
/**
|
262 |
+
* Return avatar URL
|
263 |
+
*
|
264 |
+
* @param {number} size
|
265 |
+
* @returns {string}
|
266 |
+
*/
|
267 |
+
avatar: function( size ) {
|
268 |
+
return this.get( 'avatar' ) + '&s=' + size;
|
269 |
}
|
270 |
}
|
271 |
);
|
283 |
defaults: {
|
284 |
name: '',
|
285 |
slug: null,
|
|
|
286 |
labels: {},
|
287 |
+
types: {},
|
288 |
show_cloud: false,
|
289 |
+
hierarchical: false,
|
290 |
+
meta: {
|
291 |
+
links: {}
|
292 |
+
}
|
293 |
}
|
294 |
}
|
295 |
);
|
297 |
/**
|
298 |
* Backbone model for term
|
299 |
*/
|
300 |
+
wp.api.models.Term = BaseModel.extend( _.extend(
|
301 |
/** @lends Term.prototype */
|
302 |
{
|
303 |
+
idAttribute: 'ID',
|
304 |
+
|
305 |
+
taxonomy: 'category',
|
306 |
+
|
307 |
+
/**
|
308 |
+
* @class Represent a term
|
309 |
+
* @augments Backbone.Model
|
310 |
+
* @constructs
|
311 |
+
*/
|
312 |
+
initialize: function( attributes, options ) {
|
313 |
+
if ( typeof options !== 'undefined' ) {
|
314 |
+
if ( options.taxonomy ) {
|
315 |
+
this.taxonomy = options.taxonomy;
|
316 |
+
}
|
317 |
+
}
|
318 |
+
},
|
319 |
|
320 |
/**
|
321 |
* Return URL for the model
|
323 |
* @returns {string}
|
324 |
*/
|
325 |
url: function() {
|
326 |
+
var id = this.get( 'ID' );
|
327 |
id = id || '';
|
328 |
|
329 |
+
return WP_API_Settings.root + '/taxonomies/' + this.taxonomy + '/terms/' + id;
|
330 |
},
|
331 |
|
332 |
defaults: {
|
333 |
+
ID: null,
|
334 |
name: '',
|
335 |
slug: '',
|
336 |
description: '',
|
337 |
parent: null,
|
338 |
count: 0,
|
339 |
link: '',
|
340 |
+
meta: {
|
341 |
+
links: {}
|
342 |
+
}
|
343 |
}
|
344 |
|
345 |
+
}, TimeStampedMixin, HierarchicalMixin )
|
346 |
);
|
347 |
|
348 |
/**
|
351 |
wp.api.models.Post = BaseModel.extend( _.extend(
|
352 |
/** @lends Post.prototype */
|
353 |
{
|
354 |
+
idAttribute: 'ID',
|
355 |
|
356 |
urlRoot: WP_API_Settings.root + '/posts',
|
357 |
|
358 |
defaults: {
|
359 |
+
ID: null,
|
360 |
+
title: '',
|
361 |
+
status: 'draft',
|
362 |
+
type: 'post',
|
363 |
+
author: new wp.api.models.User(),
|
364 |
+
content: '',
|
365 |
+
link: '',
|
366 |
+
'parent': 0,
|
367 |
date: new Date(),
|
368 |
date_gmt: new Date(),
|
|
|
|
|
369 |
modified: new Date(),
|
370 |
modified_gmt: new Date(),
|
371 |
+
format: 'standard',
|
372 |
slug: '',
|
373 |
+
guid: '',
|
374 |
+
excerpt: '',
|
375 |
+
menu_order: 0,
|
|
|
|
|
|
|
|
|
376 |
comment_status: 'open',
|
377 |
ping_status: 'open',
|
378 |
sticky: false,
|
379 |
+
date_tz: 'Etc/UTC',
|
380 |
+
modified_tz: 'Etc/UTC',
|
381 |
+
featured_image: null,
|
382 |
+
terms: {},
|
383 |
+
post_meta: {},
|
384 |
+
meta: {
|
385 |
+
links: {}
|
386 |
+
}
|
387 |
}
|
388 |
}, TimeStampedMixin, HierarchicalMixin )
|
389 |
);
|
394 |
wp.api.models.Page = BaseModel.extend( _.extend(
|
395 |
/** @lends Page.prototype */
|
396 |
{
|
397 |
+
idAttribute: 'ID',
|
398 |
|
399 |
urlRoot: WP_API_Settings.root + '/pages',
|
400 |
|
401 |
defaults: {
|
402 |
+
ID: null,
|
403 |
+
title: '',
|
404 |
+
status: 'draft',
|
405 |
+
type: 'page',
|
406 |
+
author: new wp.api.models.User(),
|
407 |
+
content: '',
|
408 |
+
parent: 0,
|
409 |
link: '',
|
410 |
+
date: new Date(),
|
411 |
modified: new Date(),
|
412 |
+
date_gmt: new Date(),
|
413 |
modified_gmt: new Date(),
|
414 |
+
date_tz: 'Etc/UTC',
|
415 |
+
modified_tz: 'Etc/UTC',
|
416 |
+
format: 'standard',
|
417 |
slug: '',
|
418 |
+
guid: '',
|
419 |
+
excerpt: '',
|
420 |
+
menu_order: 0,
|
|
|
|
|
|
|
|
|
421 |
comment_status: 'closed',
|
422 |
+
ping_status: 'open',
|
423 |
+
sticky: false,
|
424 |
+
password: '',
|
425 |
+
meta: {
|
426 |
+
links: {}
|
427 |
+
},
|
428 |
+
featured_image: null,
|
429 |
+
terms: []
|
430 |
}
|
431 |
}, TimeStampedMixin, HierarchicalMixin )
|
432 |
);
|
434 |
/**
|
435 |
* Backbone model for revisions
|
436 |
*/
|
437 |
+
wp.api.models.Revision = wp.api.models.Post.extend(
|
438 |
/** @lends Revision.prototype */
|
439 |
{
|
|
|
|
|
440 |
/**
|
441 |
+
* Return URL for model
|
442 |
*
|
443 |
* @returns {string}
|
444 |
*/
|
445 |
url: function() {
|
446 |
+
var parent_id = this.get( 'parent' );
|
447 |
+
parent_id = parent_id || '';
|
448 |
+
|
449 |
+
var id = this.get( 'ID' );
|
450 |
+
id = id || '';
|
451 |
|
452 |
+
return WP_API_Settings.root + '/posts/' + parent_id + '/revisions/' + id;
|
453 |
},
|
454 |
|
455 |
+
/**
|
456 |
+
* @class Represent a revision
|
457 |
+
* @augments Backbone.Model
|
458 |
+
* @constructs
|
459 |
+
*/
|
460 |
+
initialize: function() {
|
461 |
+
// Todo: what of the parent model is a page?
|
462 |
+
this.parentModel = wp.api.models.Post;
|
|
|
|
|
|
|
|
|
|
|
|
|
463 |
}
|
464 |
+
}
|
|
|
465 |
);
|
466 |
|
467 |
/**
|
470 |
wp.api.models.Media = BaseModel.extend( _.extend(
|
471 |
/** @lends Media.prototype */
|
472 |
{
|
473 |
+
idAttribute: 'ID',
|
474 |
|
475 |
urlRoot: WP_API_Settings.root + '/media',
|
476 |
|
477 |
defaults: {
|
478 |
+
ID: null,
|
479 |
+
title: '',
|
480 |
+
status: 'inherit',
|
481 |
+
type: 'attachment',
|
482 |
+
author: new wp.api.models.User(),
|
483 |
+
content: '',
|
484 |
+
parent: 0,
|
485 |
link: '',
|
486 |
+
date: new Date(),
|
487 |
modified: new Date(),
|
488 |
+
format: 'standard',
|
|
|
489 |
slug: '',
|
490 |
+
guid: '',
|
491 |
+
excerpt: '',
|
492 |
+
menu_order: 0,
|
|
|
493 |
comment_status: 'open',
|
494 |
ping_status: 'open',
|
495 |
+
sticky: false,
|
496 |
+
date_tz: 'Etc/UTC',
|
497 |
+
modified_tz: 'Etc/UTC',
|
498 |
+
date_gmt: new Date(),
|
499 |
+
modified_gmt: new Date(),
|
500 |
+
meta: {
|
501 |
+
links: {}
|
502 |
+
},
|
503 |
+
terms: [],
|
504 |
+
source: '',
|
505 |
+
is_image: true,
|
506 |
+
attachment_meta: {},
|
507 |
+
image_meta: {}
|
508 |
},
|
509 |
|
510 |
/**
|
525 |
wp.api.models.Comment = BaseModel.extend( _.extend(
|
526 |
/** @lends Comment.prototype */
|
527 |
{
|
528 |
+
idAttribute: 'ID',
|
529 |
|
530 |
defaults: {
|
531 |
+
ID: null,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
532 |
post: null,
|
533 |
+
content: '',
|
534 |
status: 'hold',
|
535 |
type: '',
|
536 |
+
parent: 0,
|
537 |
+
author: new wp.api.models.User(),
|
538 |
+
date: new Date(),
|
539 |
+
date_gmt: new Date(),
|
540 |
+
date_tz: 'Etc/UTC',
|
541 |
+
meta: {
|
542 |
+
links: {}
|
543 |
+
}
|
544 |
},
|
545 |
|
546 |
/**
|
552 |
var post_id = this.get( 'post' );
|
553 |
post_id = post_id || '';
|
554 |
|
555 |
+
var id = this.get( 'ID' );
|
556 |
id = id || '';
|
557 |
|
558 |
return WP_API_Settings.root + '/posts/' + post_id + '/comments/' + id;
|
575 |
name: '',
|
576 |
description: '',
|
577 |
labels: {},
|
578 |
+
queryable: false,
|
579 |
+
searchable: false,
|
580 |
+
hierarchical: false,
|
581 |
+
meta: {
|
582 |
+
links: {}
|
583 |
+
},
|
584 |
+
taxonomies: []
|
585 |
},
|
586 |
|
587 |
/**
|
622 |
'private': false,
|
623 |
queryable: true,
|
624 |
show_in_list: true,
|
625 |
+
meta: {
|
626 |
+
links: {}
|
627 |
+
}
|
628 |
},
|
629 |
|
630 |
/**
|
647 |
}
|
648 |
);
|
649 |
|
650 |
+
})( wp, WP_API_Settings, Backbone, _, window );
|
651 |
+
|
652 |
+
/* global WP_API_Settings:false */
|
653 |
+
(function( wp, WP_API_Settings, Backbone, _, window, undefined ) {
|
654 |
+
|
655 |
+
'use strict';
|
656 |
+
|
657 |
var BaseCollection = Backbone.Collection.extend(
|
658 |
/** @lends BaseCollection.prototype */
|
659 |
{
|
682 |
*/
|
683 |
sync: function( method, model, options ) {
|
684 |
options = options || {};
|
685 |
+
var beforeSend = options.beforeSend;
|
|
|
686 |
|
687 |
+
if ( typeof WP_API_Settings.nonce !== 'undefined' ) {
|
688 |
options.beforeSend = function( xhr ) {
|
689 |
xhr.setRequestHeader( 'X-WP-Nonce', WP_API_Settings.nonce );
|
690 |
|
691 |
if ( beforeSend ) {
|
692 |
+
return beforeSend.apply( this, arguments );
|
693 |
}
|
694 |
};
|
695 |
}
|
696 |
|
697 |
if ( 'read' === method ) {
|
698 |
+
var SELF = this;
|
699 |
+
|
700 |
if ( options.data ) {
|
701 |
+
SELF.state.data = _.clone( options.data );
|
702 |
|
703 |
+
delete SELF.state.data.page;
|
704 |
} else {
|
705 |
+
SELF.state.data = options.data = {};
|
706 |
}
|
707 |
|
708 |
+
if ( typeof options.data.page === 'undefined' ) {
|
709 |
+
SELF.state.currentPage = null;
|
710 |
+
SELF.state.totalPages = null;
|
711 |
+
SELF.state.totalObjects = null;
|
712 |
} else {
|
713 |
+
SELF.state.currentPage = options.data.page - 1;
|
714 |
}
|
715 |
|
716 |
var success = options.success;
|
717 |
options.success = function( data, textStatus, request ) {
|
718 |
+
SELF.state.totalPages = parseInt( request.getResponseHeader( 'X-WP-TotalPages' ), 10 );
|
719 |
+
SELF.state.totalObjects = parseInt( request.getResponseHeader( 'X-WP-Total' ), 10 );
|
720 |
|
721 |
+
if ( SELF.state.currentPage === null ) {
|
722 |
+
SELF.state.currentPage = 1;
|
723 |
} else {
|
724 |
+
SELF.state.currentPage++;
|
725 |
}
|
726 |
|
727 |
if ( success ) {
|
745 |
|
746 |
_.extend( options.data, this.state.data );
|
747 |
|
748 |
+
if ( typeof options.data.page === 'undefined' ) {
|
749 |
if ( ! this.hasMore() ) {
|
750 |
return false;
|
751 |
}
|
819 |
wp.api.collections.PostStatuses = BaseCollection.extend(
|
820 |
/** @lends PostStatuses.prototype */
|
821 |
{
|
822 |
+
url: WP_API_Settings.root + '/posts/statuses',
|
823 |
|
824 |
+
model: wp.api.models.PostStatus
|
825 |
|
|
|
|
|
|
|
|
|
|
|
826 |
}
|
827 |
);
|
828 |
|
858 |
{
|
859 |
model: wp.api.models.Comment,
|
860 |
|
861 |
+
post: null,
|
862 |
+
|
863 |
+
/**
|
864 |
+
* @class Represent an array of comments
|
865 |
+
* @augments Backbone.Collection
|
866 |
+
* @constructs
|
867 |
+
*/
|
868 |
+
initialize: function( models, options ) {
|
869 |
+
BaseCollection.prototype.initialize.apply( this, arguments );
|
870 |
+
|
871 |
+
if ( options && options.post ) {
|
872 |
+
this.post = options.post;
|
873 |
+
}
|
874 |
+
},
|
875 |
+
|
876 |
/**
|
877 |
* Return URL for collection
|
878 |
*
|
879 |
* @returns {string}
|
880 |
*/
|
881 |
+
url: function() {
|
882 |
+
return WP_API_Settings.root + '/posts/' + this.post + '/comments';
|
883 |
+
}
|
884 |
}
|
885 |
);
|
886 |
|
892 |
{
|
893 |
model: wp.api.models.PostType,
|
894 |
|
895 |
+
url: WP_API_Settings.root + '/posts/types'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
896 |
}
|
897 |
);
|
898 |
|
899 |
/**
|
900 |
* Backbone terms collection
|
|
|
|
|
901 |
*/
|
902 |
wp.api.collections.Terms = BaseCollection.extend(
|
903 |
/** @lends Terms.prototype */
|
904 |
{
|
905 |
model: wp.api.models.Term,
|
906 |
|
907 |
+
type: 'post',
|
908 |
+
|
909 |
taxonomy: 'category',
|
910 |
|
911 |
/**
|
914 |
* @constructs
|
915 |
*/
|
916 |
initialize: function( models, options ) {
|
917 |
+
BaseCollection.prototype.initialize.apply( this, arguments );
|
918 |
+
|
919 |
+
if ( typeof options !== 'undefined' ) {
|
920 |
+
if ( options.type ) {
|
921 |
+
this.type = options.type;
|
922 |
+
}
|
923 |
+
|
924 |
+
if ( options.taxonomy ) {
|
925 |
+
this.taxonomy = options.taxonomy;
|
926 |
+
}
|
927 |
}
|
928 |
|
929 |
+
this.on( 'add', _.bind( this.addModel, this ) );
|
930 |
+
},
|
931 |
+
|
932 |
+
/**
|
933 |
+
* We need to set the type and taxonomy for each model
|
934 |
+
*
|
935 |
+
* @param {Backbone.model} model
|
936 |
+
*/
|
937 |
+
addModel: function( model ) {
|
938 |
+
model.type = this.type;
|
939 |
+
model.taxonomy = this.taxonomy;
|
940 |
},
|
941 |
|
942 |
/**
|
945 |
* @returns {string}
|
946 |
*/
|
947 |
url: function() {
|
948 |
+
return WP_API_Settings.root + '/posts/types/' + this.type + '/taxonomies/' + this.taxonomy + '/terms/';
|
949 |
}
|
950 |
}
|
951 |
);
|
952 |
|
953 |
/**
|
954 |
* Backbone revisions collection
|
|
|
|
|
955 |
*/
|
956 |
wp.api.collections.Revisions = BaseCollection.extend(
|
957 |
/** @lends Revisions.prototype */
|
984 |
}
|
985 |
);
|
986 |
|
987 |
+
})( wp, WP_API_Settings, Backbone, _, window );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|