214 } |
254 } |
215 |
255 |
216 // Check for & assign any parameters which require special handling or setting. |
256 // Check for & assign any parameters which require special handling or setting. |
217 $args['date_query'] = array(); |
257 $args['date_query'] = array(); |
218 |
258 |
219 // Set before into date query. Date query must be specified as an array of an array. |
|
220 if ( isset( $registered['before'], $request['before'] ) ) { |
259 if ( isset( $registered['before'], $request['before'] ) ) { |
221 $args['date_query'][0]['before'] = $request['before']; |
260 $args['date_query'][] = array( |
222 } |
261 'before' => $request['before'], |
223 |
262 'column' => 'post_date', |
224 // Set after into date query. Date query must be specified as an array of an array. |
263 ); |
|
264 } |
|
265 |
|
266 if ( isset( $registered['modified_before'], $request['modified_before'] ) ) { |
|
267 $args['date_query'][] = array( |
|
268 'before' => $request['modified_before'], |
|
269 'column' => 'post_modified', |
|
270 ); |
|
271 } |
|
272 |
225 if ( isset( $registered['after'], $request['after'] ) ) { |
273 if ( isset( $registered['after'], $request['after'] ) ) { |
226 $args['date_query'][0]['after'] = $request['after']; |
274 $args['date_query'][] = array( |
|
275 'after' => $request['after'], |
|
276 'column' => 'post_date', |
|
277 ); |
|
278 } |
|
279 |
|
280 if ( isset( $registered['modified_after'], $request['modified_after'] ) ) { |
|
281 $args['date_query'][] = array( |
|
282 'after' => $request['modified_after'], |
|
283 'column' => 'post_modified', |
|
284 ); |
227 } |
285 } |
228 |
286 |
229 // Ensure our per_page parameter overrides any provided posts_per_page filter. |
287 // Ensure our per_page parameter overrides any provided posts_per_page filter. |
230 if ( isset( $registered['per_page'] ) ) { |
288 if ( isset( $registered['per_page'] ) ) { |
231 $args['posts_per_page'] = $request['per_page']; |
289 $args['posts_per_page'] = $request['per_page']; |
260 */ |
318 */ |
261 $args['post__not_in'] = array_merge( $args['post__not_in'], $sticky_posts ); |
319 $args['post__not_in'] = array_merge( $args['post__not_in'], $sticky_posts ); |
262 } |
320 } |
263 } |
321 } |
264 |
322 |
|
323 $args = $this->prepare_tax_query( $args, $request ); |
|
324 |
265 // Force the post_type argument, since it's not a user input variable. |
325 // Force the post_type argument, since it's not a user input variable. |
266 $args['post_type'] = $this->post_type; |
326 $args['post_type'] = $this->post_type; |
267 |
327 |
268 /** |
328 /** |
269 * Filters the query arguments for a request. |
329 * Filters WP_Query arguments when querying posts via the REST API. |
|
330 * |
|
331 * The dynamic portion of the hook name, `$this->post_type`, refers to the post type slug. |
|
332 * |
|
333 * Possible hook names include: |
|
334 * |
|
335 * - `rest_post_query` |
|
336 * - `rest_page_query` |
|
337 * - `rest_attachment_query` |
270 * |
338 * |
271 * Enables adding extra arguments or setting defaults for a post collection request. |
339 * Enables adding extra arguments or setting defaults for a post collection request. |
272 * |
340 * |
273 * @since 4.7.0 |
341 * @since 4.7.0 |
|
342 * @since 5.7.0 Moved after the `tax_query` query arg is generated. |
274 * |
343 * |
275 * @link https://developer.wordpress.org/reference/classes/wp_query/ |
344 * @link https://developer.wordpress.org/reference/classes/wp_query/ |
276 * |
345 * |
277 * @param array $args Key value array of query var to query value. |
346 * @param array $args Array of arguments for WP_Query. |
278 * @param WP_REST_Request $request The request used. |
347 * @param WP_REST_Request $request The REST API request. |
279 */ |
348 */ |
280 $args = apply_filters( "rest_{$this->post_type}_query", $args, $request ); |
349 $args = apply_filters( "rest_{$this->post_type}_query", $args, $request ); |
281 $query_args = $this->prepare_items_query( $args, $request ); |
350 $query_args = $this->prepare_items_query( $args, $request ); |
282 |
351 |
283 $taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) ); |
|
284 |
|
285 if ( ! empty( $request['tax_relation'] ) ) { |
|
286 $query_args['tax_query'] = array( 'relation' => $request['tax_relation'] ); |
|
287 } |
|
288 |
|
289 foreach ( $taxonomies as $taxonomy ) { |
|
290 $base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name; |
|
291 $tax_exclude = $base . '_exclude'; |
|
292 |
|
293 if ( ! empty( $request[ $base ] ) ) { |
|
294 $query_args['tax_query'][] = array( |
|
295 'taxonomy' => $taxonomy->name, |
|
296 'field' => 'term_id', |
|
297 'terms' => $request[ $base ], |
|
298 'include_children' => false, |
|
299 ); |
|
300 } |
|
301 |
|
302 if ( ! empty( $request[ $tax_exclude ] ) ) { |
|
303 $query_args['tax_query'][] = array( |
|
304 'taxonomy' => $taxonomy->name, |
|
305 'field' => 'term_id', |
|
306 'terms' => $request[ $tax_exclude ], |
|
307 'include_children' => false, |
|
308 'operator' => 'NOT IN', |
|
309 ); |
|
310 } |
|
311 } |
|
312 |
|
313 $posts_query = new WP_Query(); |
352 $posts_query = new WP_Query(); |
314 $query_result = $posts_query->query( $query_args ); |
353 $query_result = $posts_query->query( $query_args ); |
315 |
354 |
316 // Allow access to all password protected posts if the context is edit. |
355 // Allow access to all password protected posts if the context is edit. |
317 if ( 'edit' === $request['context'] ) { |
356 if ( 'edit' === $request['context'] ) { |
318 add_filter( 'post_password_required', '__return_false' ); |
357 add_filter( 'post_password_required', array( $this, 'check_password_required' ), 10, 2 ); |
319 } |
358 } |
320 |
359 |
321 $posts = array(); |
360 $posts = array(); |
322 |
361 |
323 foreach ( $query_result as $post ) { |
362 foreach ( $query_result as $post ) { |
667 /** |
718 /** |
668 * Fires after a single post is completely created or updated via the REST API. |
719 * Fires after a single post is completely created or updated via the REST API. |
669 * |
720 * |
670 * The dynamic portion of the hook name, `$this->post_type`, refers to the post type slug. |
721 * The dynamic portion of the hook name, `$this->post_type`, refers to the post type slug. |
671 * |
722 * |
|
723 * Possible hook names include: |
|
724 * |
|
725 * - `rest_after_insert_post` |
|
726 * - `rest_after_insert_page` |
|
727 * - `rest_after_insert_attachment` |
|
728 * |
672 * @since 5.0.0 |
729 * @since 5.0.0 |
673 * |
730 * |
674 * @param WP_Post $post Inserted or updated post object. |
731 * @param WP_Post $post Inserted or updated post object. |
675 * @param WP_REST_Request $request Request object. |
732 * @param WP_REST_Request $request Request object. |
676 * @param bool $creating True when creating a post, false when updating. |
733 * @param bool $creating True when creating a post, false when updating. |
677 */ |
734 */ |
678 do_action( "rest_after_insert_{$this->post_type}", $post, $request, true ); |
735 do_action( "rest_after_insert_{$this->post_type}", $post, $request, true ); |
679 |
736 |
|
737 wp_after_insert_post( $post, false, null ); |
|
738 |
680 $response = $this->prepare_item_for_response( $post, $request ); |
739 $response = $this->prepare_item_for_response( $post, $request ); |
681 $response = rest_ensure_response( $response ); |
740 $response = rest_ensure_response( $response ); |
682 |
741 |
683 $response->set_status( 201 ); |
742 $response->set_status( 201 ); |
684 $response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $post_id ) ) ); |
743 $response->header( 'Location', rest_url( sprintf( '%s/%s/%d', $this->namespace, $this->rest_base, $post_id ) ) ); |
1239 /** |
1313 /** |
1240 * Filters a post before it is inserted via the REST API. |
1314 * Filters a post before it is inserted via the REST API. |
1241 * |
1315 * |
1242 * The dynamic portion of the hook name, `$this->post_type`, refers to the post type slug. |
1316 * The dynamic portion of the hook name, `$this->post_type`, refers to the post type slug. |
1243 * |
1317 * |
|
1318 * Possible hook names include: |
|
1319 * |
|
1320 * - `rest_pre_insert_post` |
|
1321 * - `rest_pre_insert_page` |
|
1322 * - `rest_pre_insert_attachment` |
|
1323 * |
1244 * @since 4.7.0 |
1324 * @since 4.7.0 |
1245 * |
1325 * |
1246 * @param stdClass $prepared_post An object representing a single post prepared |
1326 * @param stdClass $prepared_post An object representing a single post prepared |
1247 * for inserting or updating the database. |
1327 * for inserting or updating the database. |
1248 * @param WP_REST_Request $request Request object. |
1328 * @param WP_REST_Request $request Request object. |
1249 */ |
1329 */ |
1250 return apply_filters( "rest_pre_insert_{$this->post_type}", $prepared_post, $request ); |
1330 return apply_filters( "rest_pre_insert_{$this->post_type}", $prepared_post, $request ); |
1251 |
1331 |
|
1332 } |
|
1333 |
|
1334 /** |
|
1335 * Checks whether the status is valid for the given post. |
|
1336 * |
|
1337 * Allows for sending an update request with the current status, even if that status would not be acceptable. |
|
1338 * |
|
1339 * @since 5.6.0 |
|
1340 * |
|
1341 * @param string $status The provided status. |
|
1342 * @param WP_REST_Request $request The request object. |
|
1343 * @param string $param The parameter name. |
|
1344 * @return true|WP_Error True if the status is valid, or WP_Error if not. |
|
1345 */ |
|
1346 public function check_status( $status, $request, $param ) { |
|
1347 if ( $request['id'] ) { |
|
1348 $post = $this->get_post( $request['id'] ); |
|
1349 |
|
1350 if ( ! is_wp_error( $post ) && $post->post_status === $status ) { |
|
1351 return true; |
|
1352 } |
|
1353 } |
|
1354 |
|
1355 $args = $request->get_attributes()['args'][ $param ]; |
|
1356 |
|
1357 return rest_validate_value_from_schema( $status, $args, $param ); |
1252 } |
1358 } |
1253 |
1359 |
1254 /** |
1360 /** |
1255 * Determines validity and normalizes the given status parameter. |
1361 * Determines validity and normalizes the given status parameter. |
1256 * |
1362 * |
2036 'title' => $this->post_type, |
2151 'title' => $this->post_type, |
2037 'type' => 'object', |
2152 'type' => 'object', |
2038 // Base properties for every Post. |
2153 // Base properties for every Post. |
2039 'properties' => array( |
2154 'properties' => array( |
2040 'date' => array( |
2155 'date' => array( |
2041 'description' => __( "The date the object was published, in the site's timezone." ), |
2156 'description' => __( "The date the post was published, in the site's timezone." ), |
2042 'type' => array( 'string', 'null' ), |
2157 'type' => array( 'string', 'null' ), |
2043 'format' => 'date-time', |
2158 'format' => 'date-time', |
2044 'context' => array( 'view', 'edit', 'embed' ), |
2159 'context' => array( 'view', 'edit', 'embed' ), |
2045 ), |
2160 ), |
2046 'date_gmt' => array( |
2161 'date_gmt' => array( |
2047 'description' => __( 'The date the object was published, as GMT.' ), |
2162 'description' => __( 'The date the post was published, as GMT.' ), |
2048 'type' => array( 'string', 'null' ), |
2163 'type' => array( 'string', 'null' ), |
2049 'format' => 'date-time', |
2164 'format' => 'date-time', |
2050 'context' => array( 'view', 'edit' ), |
2165 'context' => array( 'view', 'edit' ), |
2051 ), |
2166 ), |
2052 'guid' => array( |
2167 'guid' => array( |
2053 'description' => __( 'The globally unique identifier for the object.' ), |
2168 'description' => __( 'The globally unique identifier for the post.' ), |
2054 'type' => 'object', |
2169 'type' => 'object', |
2055 'context' => array( 'view', 'edit' ), |
2170 'context' => array( 'view', 'edit' ), |
2056 'readonly' => true, |
2171 'readonly' => true, |
2057 'properties' => array( |
2172 'properties' => array( |
2058 'raw' => array( |
2173 'raw' => array( |
2059 'description' => __( 'GUID for the object, as it exists in the database.' ), |
2174 'description' => __( 'GUID for the post, as it exists in the database.' ), |
2060 'type' => 'string', |
2175 'type' => 'string', |
2061 'context' => array( 'edit' ), |
2176 'context' => array( 'edit' ), |
2062 'readonly' => true, |
2177 'readonly' => true, |
2063 ), |
2178 ), |
2064 'rendered' => array( |
2179 'rendered' => array( |
2065 'description' => __( 'GUID for the object, transformed for display.' ), |
2180 'description' => __( 'GUID for the post, transformed for display.' ), |
2066 'type' => 'string', |
2181 'type' => 'string', |
2067 'context' => array( 'view', 'edit' ), |
2182 'context' => array( 'view', 'edit' ), |
2068 'readonly' => true, |
2183 'readonly' => true, |
2069 ), |
2184 ), |
2070 ), |
2185 ), |
2071 ), |
2186 ), |
2072 'id' => array( |
2187 'id' => array( |
2073 'description' => __( 'Unique identifier for the object.' ), |
2188 'description' => __( 'Unique identifier for the post.' ), |
2074 'type' => 'integer', |
2189 'type' => 'integer', |
2075 'context' => array( 'view', 'edit', 'embed' ), |
2190 'context' => array( 'view', 'edit', 'embed' ), |
2076 'readonly' => true, |
2191 'readonly' => true, |
2077 ), |
2192 ), |
2078 'link' => array( |
2193 'link' => array( |
2079 'description' => __( 'URL to the object.' ), |
2194 'description' => __( 'URL to the post.' ), |
2080 'type' => 'string', |
2195 'type' => 'string', |
2081 'format' => 'uri', |
2196 'format' => 'uri', |
2082 'context' => array( 'view', 'edit', 'embed' ), |
2197 'context' => array( 'view', 'edit', 'embed' ), |
2083 'readonly' => true, |
2198 'readonly' => true, |
2084 ), |
2199 ), |
2085 'modified' => array( |
2200 'modified' => array( |
2086 'description' => __( "The date the object was last modified, in the site's timezone." ), |
2201 'description' => __( "The date the post was last modified, in the site's timezone." ), |
2087 'type' => 'string', |
2202 'type' => 'string', |
2088 'format' => 'date-time', |
2203 'format' => 'date-time', |
2089 'context' => array( 'view', 'edit' ), |
2204 'context' => array( 'view', 'edit' ), |
2090 'readonly' => true, |
2205 'readonly' => true, |
2091 ), |
2206 ), |
2092 'modified_gmt' => array( |
2207 'modified_gmt' => array( |
2093 'description' => __( 'The date the object was last modified, as GMT.' ), |
2208 'description' => __( 'The date the post was last modified, as GMT.' ), |
2094 'type' => 'string', |
2209 'type' => 'string', |
2095 'format' => 'date-time', |
2210 'format' => 'date-time', |
2096 'context' => array( 'view', 'edit' ), |
2211 'context' => array( 'view', 'edit' ), |
2097 'readonly' => true, |
2212 'readonly' => true, |
2098 ), |
2213 ), |
2099 'slug' => array( |
2214 'slug' => array( |
2100 'description' => __( 'An alphanumeric identifier for the object unique to its type.' ), |
2215 'description' => __( 'An alphanumeric identifier for the post unique to its type.' ), |
2101 'type' => 'string', |
2216 'type' => 'string', |
2102 'context' => array( 'view', 'edit', 'embed' ), |
2217 'context' => array( 'view', 'edit', 'embed' ), |
2103 'arg_options' => array( |
2218 'arg_options' => array( |
2104 'sanitize_callback' => array( $this, 'sanitize_slug' ), |
2219 'sanitize_callback' => array( $this, 'sanitize_slug' ), |
2105 ), |
2220 ), |
2106 ), |
2221 ), |
2107 'status' => array( |
2222 'status' => array( |
2108 'description' => __( 'A named status for the object.' ), |
2223 'description' => __( 'A named status for the post.' ), |
2109 'type' => 'string', |
2224 'type' => 'string', |
2110 'enum' => array_keys( get_post_stati( array( 'internal' => false ) ) ), |
2225 'enum' => array_keys( get_post_stati( array( 'internal' => false ) ) ), |
2111 'context' => array( 'view', 'edit' ), |
2226 'context' => array( 'view', 'edit' ), |
|
2227 'arg_options' => array( |
|
2228 'validate_callback' => array( $this, 'check_status' ), |
|
2229 ), |
2112 ), |
2230 ), |
2113 'type' => array( |
2231 'type' => array( |
2114 'description' => __( 'Type of Post for the object.' ), |
2232 'description' => __( 'Type of post.' ), |
2115 'type' => 'string', |
2233 'type' => 'string', |
2116 'context' => array( 'view', 'edit', 'embed' ), |
2234 'context' => array( 'view', 'edit', 'embed' ), |
2117 'readonly' => true, |
2235 'readonly' => true, |
2118 ), |
2236 ), |
2119 'password' => array( |
2237 'password' => array( |
2125 ); |
2243 ); |
2126 |
2244 |
2127 $post_type_obj = get_post_type_object( $this->post_type ); |
2245 $post_type_obj = get_post_type_object( $this->post_type ); |
2128 if ( is_post_type_viewable( $post_type_obj ) && $post_type_obj->public ) { |
2246 if ( is_post_type_viewable( $post_type_obj ) && $post_type_obj->public ) { |
2129 $schema['properties']['permalink_template'] = array( |
2247 $schema['properties']['permalink_template'] = array( |
2130 'description' => __( 'Permalink template for the object.' ), |
2248 'description' => __( 'Permalink template for the post.' ), |
2131 'type' => 'string', |
2249 'type' => 'string', |
2132 'context' => array( 'edit' ), |
2250 'context' => array( 'edit' ), |
2133 'readonly' => true, |
2251 'readonly' => true, |
2134 ); |
2252 ); |
2135 |
2253 |
2136 $schema['properties']['generated_slug'] = array( |
2254 $schema['properties']['generated_slug'] = array( |
2137 'description' => __( 'Slug automatically generated from the object title.' ), |
2255 'description' => __( 'Slug automatically generated from the post title.' ), |
2138 'type' => 'string', |
2256 'type' => 'string', |
2139 'context' => array( 'edit' ), |
2257 'context' => array( 'edit' ), |
2140 'readonly' => true, |
2258 'readonly' => true, |
2141 ); |
2259 ); |
2142 } |
2260 } |
2143 |
2261 |
2144 if ( $post_type_obj->hierarchical ) { |
2262 if ( $post_type_obj->hierarchical ) { |
2145 $schema['properties']['parent'] = array( |
2263 $schema['properties']['parent'] = array( |
2146 'description' => __( 'The ID for the parent of the object.' ), |
2264 'description' => __( 'The ID for the parent of the post.' ), |
2147 'type' => 'integer', |
2265 'type' => 'integer', |
2148 'context' => array( 'view', 'edit' ), |
2266 'context' => array( 'view', 'edit' ), |
2149 ); |
2267 ); |
2150 } |
2268 } |
2151 |
2269 |
2202 |
2320 |
2203 switch ( $attribute ) { |
2321 switch ( $attribute ) { |
2204 |
2322 |
2205 case 'title': |
2323 case 'title': |
2206 $schema['properties']['title'] = array( |
2324 $schema['properties']['title'] = array( |
2207 'description' => __( 'The title for the object.' ), |
2325 'description' => __( 'The title for the post.' ), |
2208 'type' => 'object', |
2326 'type' => 'object', |
2209 'context' => array( 'view', 'edit', 'embed' ), |
2327 'context' => array( 'view', 'edit', 'embed' ), |
2210 'arg_options' => array( |
2328 'arg_options' => array( |
2211 'sanitize_callback' => null, // Note: sanitization implemented in self::prepare_item_for_database(). |
2329 'sanitize_callback' => null, // Note: sanitization implemented in self::prepare_item_for_database(). |
2212 'validate_callback' => null, // Note: validation implemented in self::prepare_item_for_database(). |
2330 'validate_callback' => null, // Note: validation implemented in self::prepare_item_for_database(). |
2213 ), |
2331 ), |
2214 'properties' => array( |
2332 'properties' => array( |
2215 'raw' => array( |
2333 'raw' => array( |
2216 'description' => __( 'Title for the object, as it exists in the database.' ), |
2334 'description' => __( 'Title for the post, as it exists in the database.' ), |
2217 'type' => 'string', |
2335 'type' => 'string', |
2218 'context' => array( 'edit' ), |
2336 'context' => array( 'edit' ), |
2219 ), |
2337 ), |
2220 'rendered' => array( |
2338 'rendered' => array( |
2221 'description' => __( 'HTML title for the object, transformed for display.' ), |
2339 'description' => __( 'HTML title for the post, transformed for display.' ), |
2222 'type' => 'string', |
2340 'type' => 'string', |
2223 'context' => array( 'view', 'edit', 'embed' ), |
2341 'context' => array( 'view', 'edit', 'embed' ), |
2224 'readonly' => true, |
2342 'readonly' => true, |
2225 ), |
2343 ), |
2226 ), |
2344 ), |
2227 ); |
2345 ); |
2228 break; |
2346 break; |
2229 |
2347 |
2230 case 'editor': |
2348 case 'editor': |
2231 $schema['properties']['content'] = array( |
2349 $schema['properties']['content'] = array( |
2232 'description' => __( 'The content for the object.' ), |
2350 'description' => __( 'The content for the post.' ), |
2233 'type' => 'object', |
2351 'type' => 'object', |
2234 'context' => array( 'view', 'edit' ), |
2352 'context' => array( 'view', 'edit' ), |
2235 'arg_options' => array( |
2353 'arg_options' => array( |
2236 'sanitize_callback' => null, // Note: sanitization implemented in self::prepare_item_for_database(). |
2354 'sanitize_callback' => null, // Note: sanitization implemented in self::prepare_item_for_database(). |
2237 'validate_callback' => null, // Note: validation implemented in self::prepare_item_for_database(). |
2355 'validate_callback' => null, // Note: validation implemented in self::prepare_item_for_database(). |
2238 ), |
2356 ), |
2239 'properties' => array( |
2357 'properties' => array( |
2240 'raw' => array( |
2358 'raw' => array( |
2241 'description' => __( 'Content for the object, as it exists in the database.' ), |
2359 'description' => __( 'Content for the post, as it exists in the database.' ), |
2242 'type' => 'string', |
2360 'type' => 'string', |
2243 'context' => array( 'edit' ), |
2361 'context' => array( 'edit' ), |
2244 ), |
2362 ), |
2245 'rendered' => array( |
2363 'rendered' => array( |
2246 'description' => __( 'HTML content for the object, transformed for display.' ), |
2364 'description' => __( 'HTML content for the post, transformed for display.' ), |
2247 'type' => 'string', |
2365 'type' => 'string', |
2248 'context' => array( 'view', 'edit' ), |
2366 'context' => array( 'view', 'edit' ), |
2249 'readonly' => true, |
2367 'readonly' => true, |
2250 ), |
2368 ), |
2251 'block_version' => array( |
2369 'block_version' => array( |
2252 'description' => __( 'Version of the content block format used by the object.' ), |
2370 'description' => __( 'Version of the content block format used by the post.' ), |
2253 'type' => 'integer', |
2371 'type' => 'integer', |
2254 'context' => array( 'edit' ), |
2372 'context' => array( 'edit' ), |
2255 'readonly' => true, |
2373 'readonly' => true, |
2256 ), |
2374 ), |
2257 'protected' => array( |
2375 'protected' => array( |
2264 ); |
2382 ); |
2265 break; |
2383 break; |
2266 |
2384 |
2267 case 'author': |
2385 case 'author': |
2268 $schema['properties']['author'] = array( |
2386 $schema['properties']['author'] = array( |
2269 'description' => __( 'The ID for the author of the object.' ), |
2387 'description' => __( 'The ID for the author of the post.' ), |
2270 'type' => 'integer', |
2388 'type' => 'integer', |
2271 'context' => array( 'view', 'edit', 'embed' ), |
2389 'context' => array( 'view', 'edit', 'embed' ), |
2272 ); |
2390 ); |
2273 break; |
2391 break; |
2274 |
2392 |
2275 case 'excerpt': |
2393 case 'excerpt': |
2276 $schema['properties']['excerpt'] = array( |
2394 $schema['properties']['excerpt'] = array( |
2277 'description' => __( 'The excerpt for the object.' ), |
2395 'description' => __( 'The excerpt for the post.' ), |
2278 'type' => 'object', |
2396 'type' => 'object', |
2279 'context' => array( 'view', 'edit', 'embed' ), |
2397 'context' => array( 'view', 'edit', 'embed' ), |
2280 'arg_options' => array( |
2398 'arg_options' => array( |
2281 'sanitize_callback' => null, // Note: sanitization implemented in self::prepare_item_for_database(). |
2399 'sanitize_callback' => null, // Note: sanitization implemented in self::prepare_item_for_database(). |
2282 'validate_callback' => null, // Note: validation implemented in self::prepare_item_for_database(). |
2400 'validate_callback' => null, // Note: validation implemented in self::prepare_item_for_database(). |
2283 ), |
2401 ), |
2284 'properties' => array( |
2402 'properties' => array( |
2285 'raw' => array( |
2403 'raw' => array( |
2286 'description' => __( 'Excerpt for the object, as it exists in the database.' ), |
2404 'description' => __( 'Excerpt for the post, as it exists in the database.' ), |
2287 'type' => 'string', |
2405 'type' => 'string', |
2288 'context' => array( 'edit' ), |
2406 'context' => array( 'edit' ), |
2289 ), |
2407 ), |
2290 'rendered' => array( |
2408 'rendered' => array( |
2291 'description' => __( 'HTML excerpt for the object, transformed for display.' ), |
2409 'description' => __( 'HTML excerpt for the post, transformed for display.' ), |
2292 'type' => 'string', |
2410 'type' => 'string', |
2293 'context' => array( 'view', 'edit', 'embed' ), |
2411 'context' => array( 'view', 'edit', 'embed' ), |
2294 'readonly' => true, |
2412 'readonly' => true, |
2295 ), |
2413 ), |
2296 'protected' => array( |
2414 'protected' => array( |
2303 ); |
2421 ); |
2304 break; |
2422 break; |
2305 |
2423 |
2306 case 'thumbnail': |
2424 case 'thumbnail': |
2307 $schema['properties']['featured_media'] = array( |
2425 $schema['properties']['featured_media'] = array( |
2308 'description' => __( 'The ID of the featured media for the object.' ), |
2426 'description' => __( 'The ID of the featured media for the post.' ), |
2309 'type' => 'integer', |
2427 'type' => 'integer', |
2310 'context' => array( 'view', 'edit', 'embed' ), |
2428 'context' => array( 'view', 'edit', 'embed' ), |
2311 ); |
2429 ); |
2312 break; |
2430 break; |
2313 |
2431 |
2314 case 'comments': |
2432 case 'comments': |
2315 $schema['properties']['comment_status'] = array( |
2433 $schema['properties']['comment_status'] = array( |
2316 'description' => __( 'Whether or not comments are open on the object.' ), |
2434 'description' => __( 'Whether or not comments are open on the post.' ), |
2317 'type' => 'string', |
2435 'type' => 'string', |
2318 'enum' => array( 'open', 'closed' ), |
2436 'enum' => array( 'open', 'closed' ), |
2319 'context' => array( 'view', 'edit' ), |
2437 'context' => array( 'view', 'edit' ), |
2320 ); |
2438 ); |
2321 $schema['properties']['ping_status'] = array( |
2439 $schema['properties']['ping_status'] = array( |
2322 'description' => __( 'Whether or not the object can be pinged.' ), |
2440 'description' => __( 'Whether or not the post can be pinged.' ), |
2323 'type' => 'string', |
2441 'type' => 'string', |
2324 'enum' => array( 'open', 'closed' ), |
2442 'enum' => array( 'open', 'closed' ), |
2325 'context' => array( 'view', 'edit' ), |
2443 'context' => array( 'view', 'edit' ), |
2326 ); |
2444 ); |
2327 break; |
2445 break; |
2328 |
2446 |
2329 case 'page-attributes': |
2447 case 'page-attributes': |
2330 $schema['properties']['menu_order'] = array( |
2448 $schema['properties']['menu_order'] = array( |
2331 'description' => __( 'The order of the object in relation to other object of its type.' ), |
2449 'description' => __( 'The order of the post in relation to other posts.' ), |
2332 'type' => 'integer', |
2450 'type' => 'integer', |
2333 'context' => array( 'view', 'edit' ), |
2451 'context' => array( 'view', 'edit' ), |
2334 ); |
2452 ); |
2335 break; |
2453 break; |
2336 |
2454 |
2337 case 'post-formats': |
2455 case 'post-formats': |
2338 // Get the native post formats and remove the array keys. |
2456 // Get the native post formats and remove the array keys. |
2339 $formats = array_values( get_post_format_slugs() ); |
2457 $formats = array_values( get_post_format_slugs() ); |
2340 |
2458 |
2341 $schema['properties']['format'] = array( |
2459 $schema['properties']['format'] = array( |
2342 'description' => __( 'The format for the object.' ), |
2460 'description' => __( 'The format for the post.' ), |
2343 'type' => 'string', |
2461 'type' => 'string', |
2344 'enum' => $formats, |
2462 'enum' => $formats, |
2345 'context' => array( 'view', 'edit' ), |
2463 'context' => array( 'view', 'edit' ), |
2346 ); |
2464 ); |
2347 break; |
2465 break; |
2708 'type' => 'string', |
2840 'type' => 'string', |
2709 ), |
2841 ), |
2710 'sanitize_callback' => array( $this, 'sanitize_post_statuses' ), |
2842 'sanitize_callback' => array( $this, 'sanitize_post_statuses' ), |
2711 ); |
2843 ); |
2712 |
2844 |
2713 $taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) ); |
2845 $query_params = $this->prepare_taxonomy_limit_schema( $query_params ); |
2714 |
|
2715 if ( ! empty( $taxonomies ) ) { |
|
2716 $query_params['tax_relation'] = array( |
|
2717 'description' => __( 'Limit result set based on relationship between multiple taxonomies.' ), |
|
2718 'type' => 'string', |
|
2719 'enum' => array( 'AND', 'OR' ), |
|
2720 ); |
|
2721 } |
|
2722 |
|
2723 foreach ( $taxonomies as $taxonomy ) { |
|
2724 $base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name; |
|
2725 |
|
2726 $query_params[ $base ] = array( |
|
2727 /* translators: %s: Taxonomy name. */ |
|
2728 'description' => sprintf( __( 'Limit result set to all items that have the specified term assigned in the %s taxonomy.' ), $base ), |
|
2729 'type' => 'array', |
|
2730 'items' => array( |
|
2731 'type' => 'integer', |
|
2732 ), |
|
2733 'default' => array(), |
|
2734 ); |
|
2735 |
|
2736 $query_params[ $base . '_exclude' ] = array( |
|
2737 /* translators: %s: Taxonomy name. */ |
|
2738 'description' => sprintf( __( 'Limit result set to all items except those that have the specified term assigned in the %s taxonomy.' ), $base ), |
|
2739 'type' => 'array', |
|
2740 'items' => array( |
|
2741 'type' => 'integer', |
|
2742 ), |
|
2743 'default' => array(), |
|
2744 ); |
|
2745 } |
|
2746 |
2846 |
2747 if ( 'post' === $this->post_type ) { |
2847 if ( 'post' === $this->post_type ) { |
2748 $query_params['sticky'] = array( |
2848 $query_params['sticky'] = array( |
2749 'description' => __( 'Limit result set to items that are sticky.' ), |
2849 'description' => __( 'Limit result set to items that are sticky.' ), |
2750 'type' => 'boolean', |
2850 'type' => 'boolean', |
2751 ); |
2851 ); |
2752 } |
2852 } |
2753 |
2853 |
2754 /** |
2854 /** |
2755 * Filter collection parameters for the posts controller. |
2855 * Filters collection parameters for the posts controller. |
2756 * |
2856 * |
2757 * The dynamic part of the filter `$this->post_type` refers to the post |
2857 * The dynamic part of the filter `$this->post_type` refers to the post |
2758 * type slug for the controller. |
2858 * type slug for the controller. |
2759 * |
2859 * |
2760 * This filter registers the collection parameter, but does not map the |
2860 * This filter registers the collection parameter, but does not map the |
2808 } |
2908 } |
2809 } |
2909 } |
2810 |
2910 |
2811 return $statuses; |
2911 return $statuses; |
2812 } |
2912 } |
|
2913 |
|
2914 /** |
|
2915 * Prepares the 'tax_query' for a collection of posts. |
|
2916 * |
|
2917 * @since 5.7.0 |
|
2918 * |
|
2919 * @param array $args WP_Query arguments. |
|
2920 * @param WP_REST_Request $request Full details about the request. |
|
2921 * @return array Updated query arguments. |
|
2922 */ |
|
2923 private function prepare_tax_query( array $args, WP_REST_Request $request ) { |
|
2924 $relation = $request['tax_relation']; |
|
2925 |
|
2926 if ( $relation ) { |
|
2927 $args['tax_query'] = array( 'relation' => $relation ); |
|
2928 } |
|
2929 |
|
2930 $taxonomies = wp_list_filter( |
|
2931 get_object_taxonomies( $this->post_type, 'objects' ), |
|
2932 array( 'show_in_rest' => true ) |
|
2933 ); |
|
2934 |
|
2935 foreach ( $taxonomies as $taxonomy ) { |
|
2936 $base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name; |
|
2937 |
|
2938 $tax_include = $request[ $base ]; |
|
2939 $tax_exclude = $request[ $base . '_exclude' ]; |
|
2940 |
|
2941 if ( $tax_include ) { |
|
2942 $terms = array(); |
|
2943 $include_children = false; |
|
2944 $operator = 'IN'; |
|
2945 |
|
2946 if ( rest_is_array( $tax_include ) ) { |
|
2947 $terms = $tax_include; |
|
2948 } elseif ( rest_is_object( $tax_include ) ) { |
|
2949 $terms = empty( $tax_include['terms'] ) ? array() : $tax_include['terms']; |
|
2950 $include_children = ! empty( $tax_include['include_children'] ); |
|
2951 |
|
2952 if ( isset( $tax_include['operator'] ) && 'AND' === $tax_include['operator'] ) { |
|
2953 $operator = 'AND'; |
|
2954 } |
|
2955 } |
|
2956 |
|
2957 if ( $terms ) { |
|
2958 $args['tax_query'][] = array( |
|
2959 'taxonomy' => $taxonomy->name, |
|
2960 'field' => 'term_id', |
|
2961 'terms' => $terms, |
|
2962 'include_children' => $include_children, |
|
2963 'operator' => $operator, |
|
2964 ); |
|
2965 } |
|
2966 } |
|
2967 |
|
2968 if ( $tax_exclude ) { |
|
2969 $terms = array(); |
|
2970 $include_children = false; |
|
2971 |
|
2972 if ( rest_is_array( $tax_exclude ) ) { |
|
2973 $terms = $tax_exclude; |
|
2974 } elseif ( rest_is_object( $tax_exclude ) ) { |
|
2975 $terms = empty( $tax_exclude['terms'] ) ? array() : $tax_exclude['terms']; |
|
2976 $include_children = ! empty( $tax_exclude['include_children'] ); |
|
2977 } |
|
2978 |
|
2979 if ( $terms ) { |
|
2980 $args['tax_query'][] = array( |
|
2981 'taxonomy' => $taxonomy->name, |
|
2982 'field' => 'term_id', |
|
2983 'terms' => $terms, |
|
2984 'include_children' => $include_children, |
|
2985 'operator' => 'NOT IN', |
|
2986 ); |
|
2987 } |
|
2988 } |
|
2989 } |
|
2990 |
|
2991 return $args; |
|
2992 } |
|
2993 |
|
2994 /** |
|
2995 * Prepares the collection schema for including and excluding items by terms. |
|
2996 * |
|
2997 * @since 5.7.0 |
|
2998 * |
|
2999 * @param array $query_params Collection schema. |
|
3000 * @return array Updated schema. |
|
3001 */ |
|
3002 private function prepare_taxonomy_limit_schema( array $query_params ) { |
|
3003 $taxonomies = wp_list_filter( get_object_taxonomies( $this->post_type, 'objects' ), array( 'show_in_rest' => true ) ); |
|
3004 |
|
3005 if ( ! $taxonomies ) { |
|
3006 return $query_params; |
|
3007 } |
|
3008 |
|
3009 $query_params['tax_relation'] = array( |
|
3010 'description' => __( 'Limit result set based on relationship between multiple taxonomies.' ), |
|
3011 'type' => 'string', |
|
3012 'enum' => array( 'AND', 'OR' ), |
|
3013 ); |
|
3014 |
|
3015 $limit_schema = array( |
|
3016 'type' => array( 'object', 'array' ), |
|
3017 'oneOf' => array( |
|
3018 array( |
|
3019 'title' => __( 'Term ID List' ), |
|
3020 'description' => __( 'Match terms with the listed IDs.' ), |
|
3021 'type' => 'array', |
|
3022 'items' => array( |
|
3023 'type' => 'integer', |
|
3024 ), |
|
3025 ), |
|
3026 array( |
|
3027 'title' => __( 'Term ID Taxonomy Query' ), |
|
3028 'description' => __( 'Perform an advanced term query.' ), |
|
3029 'type' => 'object', |
|
3030 'properties' => array( |
|
3031 'terms' => array( |
|
3032 'description' => __( 'Term IDs.' ), |
|
3033 'type' => 'array', |
|
3034 'items' => array( |
|
3035 'type' => 'integer', |
|
3036 ), |
|
3037 'default' => array(), |
|
3038 ), |
|
3039 'include_children' => array( |
|
3040 'description' => __( 'Whether to include child terms in the terms limiting the result set.' ), |
|
3041 'type' => 'boolean', |
|
3042 'default' => false, |
|
3043 ), |
|
3044 ), |
|
3045 'additionalProperties' => false, |
|
3046 ), |
|
3047 ), |
|
3048 ); |
|
3049 |
|
3050 $include_schema = array_merge( |
|
3051 array( |
|
3052 /* translators: %s: Taxonomy name. */ |
|
3053 'description' => __( 'Limit result set to items with specific terms assigned in the %s taxonomy.' ), |
|
3054 ), |
|
3055 $limit_schema |
|
3056 ); |
|
3057 // 'operator' is supported only for 'include' queries. |
|
3058 $include_schema['oneOf'][1]['properties']['operator'] = array( |
|
3059 'description' => __( 'Whether items must be assigned all or any of the specified terms.' ), |
|
3060 'type' => 'string', |
|
3061 'enum' => array( 'AND', 'OR' ), |
|
3062 'default' => 'OR', |
|
3063 ); |
|
3064 |
|
3065 $exclude_schema = array_merge( |
|
3066 array( |
|
3067 /* translators: %s: Taxonomy name. */ |
|
3068 'description' => __( 'Limit result set to items except those with specific terms assigned in the %s taxonomy.' ), |
|
3069 ), |
|
3070 $limit_schema |
|
3071 ); |
|
3072 |
|
3073 foreach ( $taxonomies as $taxonomy ) { |
|
3074 $base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name; |
|
3075 $base_exclude = $base . '_exclude'; |
|
3076 |
|
3077 $query_params[ $base ] = $include_schema; |
|
3078 $query_params[ $base ]['description'] = sprintf( $query_params[ $base ]['description'], $base ); |
|
3079 |
|
3080 $query_params[ $base_exclude ] = $exclude_schema; |
|
3081 $query_params[ $base_exclude ]['description'] = sprintf( $query_params[ $base_exclude ]['description'], $base ); |
|
3082 |
|
3083 if ( ! $taxonomy->hierarchical ) { |
|
3084 unset( $query_params[ $base ]['oneOf'][1]['properties']['include_children'] ); |
|
3085 unset( $query_params[ $base_exclude ]['oneOf'][1]['properties']['include_children'] ); |
|
3086 } |
|
3087 } |
|
3088 |
|
3089 return $query_params; |
|
3090 } |
2813 } |
3091 } |