Changeset 49257
- Timestamp:
- 10/20/2020 08:17:20 PM (4 years ago)
- Location:
- trunk
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/rest-api.php
r49246 r49257 1876 1876 1877 1877 /** 1878 * Validate a value based on a schema. 1879 * 1880 * @since 4.7.0 1881 * @since 4.9.0 Support the "object" type. 1882 * @since 5.2.0 Support validating "additionalProperties" against a schema. 1883 * @since 5.3.0 Support multiple types. 1884 * @since 5.4.0 Convert an empty string to an empty object. 1885 * @since 5.5.0 Add the "uuid" and "hex-color" formats. 1886 * Support the "minLength", "maxLength" and "pattern" keywords for strings. 1887 * Support the "minItems", "maxItems" and "uniqueItems" keywords for arrays. 1888 * Validate required properties. 1889 * @since 5.6.0 Support the "minProperties" and "maxProperties" keywords for objects. 1890 * Support the "multipleOf" keyword for numbers and integers. 1891 * Support the "patternProperties" keyword for objects. 1892 * Support the "anyOf" and "oneOf" keywords. 1893 * 1894 * @param mixed $value The value to validate. 1895 * @param array $args Schema array to use for validation. 1896 * @param string $param The parameter name, used in error messages. 1897 * @return true|WP_Error 1898 */ 1899 function rest_validate_value_from_schema( $value, $args, $param = '' ) { 1900 if ( isset( $args['anyOf'] ) ) { 1901 $matching_schema = rest_find_any_matching_schema( $value, $args, $param ); 1902 if ( is_wp_error( $matching_schema ) ) { 1903 return $matching_schema; 1904 } 1905 1906 if ( ! isset( $args['type'] ) && isset( $matching_schema['type'] ) ) { 1907 $args['type'] = $matching_schema['type']; 1908 } 1909 } 1910 1911 if ( isset( $args['oneOf'] ) ) { 1912 $matching_schema = rest_find_one_matching_schema( $value, $args, $param ); 1913 if ( is_wp_error( $matching_schema ) ) { 1914 return $matching_schema; 1915 } 1916 1917 if ( ! isset( $args['type'] ) && isset( $matching_schema['type'] ) ) { 1918 $args['type'] = $matching_schema['type']; 1919 } 1920 } 1921 1922 $allowed_types = array( 'array', 'object', 'string', 'number', 'integer', 'boolean', 'null' ); 1923 1924 if ( ! isset( $args['type'] ) ) { 1925 /* translators: %s: Parameter. */ 1926 _doing_it_wrong( __FUNCTION__, sprintf( __( 'The "type" schema keyword for %s is required.' ), $param ), '5.5.0' ); 1927 } 1928 1929 if ( is_array( $args['type'] ) ) { 1930 $best_type = rest_handle_multi_type_schema( $value, $args, $param ); 1931 1932 if ( ! $best_type ) { 1933 return new WP_Error( 1934 'rest_invalid_type', 1935 /* translators: 1: Parameter, 2: List of types. */ 1936 sprintf( __( '%1$s is not of type %2$s.' ), $param, implode( ',', $args['type'] ) ), 1937 array( 'param' => $param ) 1938 ); 1939 } 1940 1941 $args['type'] = $best_type; 1942 } 1943 1944 if ( ! in_array( $args['type'], $allowed_types, true ) ) { 1945 _doing_it_wrong( 1946 __FUNCTION__, 1947 /* translators: 1: Parameter, 2: The list of allowed types. */ 1948 wp_sprintf( __( 'The "type" schema keyword for %1$s can only be one of the built-in types: %2$l.' ), $param, $allowed_types ), 1949 '5.5.0' 1950 ); 1951 } 1952 1953 if ( 'array' === $args['type'] ) { 1954 if ( ! rest_is_array( $value ) ) { 1955 return new WP_Error( 1956 'rest_invalid_type', 1957 /* translators: 1: Parameter, 2: Type name. */ 1958 sprintf( __( '%1$s is not of type %2$s.' ), $param, 'array' ), 1959 array( 'param' => $param ) 1960 ); 1961 } 1962 1963 $value = rest_sanitize_array( $value ); 1964 1965 if ( isset( $args['items'] ) ) { 1966 foreach ( $value as $index => $v ) { 1967 $is_valid = rest_validate_value_from_schema( $v, $args['items'], $param . '[' . $index . ']' ); 1968 if ( is_wp_error( $is_valid ) ) { 1969 return $is_valid; 1970 } 1971 } 1972 } 1973 1974 if ( isset( $args['minItems'] ) && count( $value ) < $args['minItems'] ) { 1975 /* translators: 1: Parameter, 2: Number. */ 1976 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must contain at least %2$s items.' ), $param, number_format_i18n( $args['minItems'] ) ) ); 1977 } 1978 1979 if ( isset( $args['maxItems'] ) && count( $value ) > $args['maxItems'] ) { 1980 /* translators: 1: Parameter, 2: Number. */ 1981 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must contain at most %2$s items.' ), $param, number_format_i18n( $args['maxItems'] ) ) ); 1982 } 1983 1984 if ( ! empty( $args['uniqueItems'] ) && ! rest_validate_array_contains_unique_items( $value ) ) { 1985 /* translators: 1: Parameter. */ 1986 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s has duplicate items.' ), $param ) ); 1987 } 1988 } 1989 1990 if ( 'object' === $args['type'] ) { 1991 if ( ! rest_is_object( $value ) ) { 1992 return new WP_Error( 1993 'rest_invalid_type', 1994 /* translators: 1: Parameter, 2: Type name. */ 1995 sprintf( __( '%1$s is not of type %2$s.' ), $param, 'object' ), 1996 array( 'param' => $param ) 1997 ); 1998 } 1999 2000 $value = rest_sanitize_object( $value ); 2001 2002 if ( isset( $args['required'] ) && is_array( $args['required'] ) ) { // schema version 4 2003 foreach ( $args['required'] as $name ) { 2004 if ( ! array_key_exists( $name, $value ) ) { 2005 /* translators: 1: Property of an object, 2: Parameter. */ 2006 return new WP_Error( 'rest_property_required', sprintf( __( '%1$s is a required property of %2$s.' ), $name, $param ) ); 2007 } 2008 } 2009 } elseif ( isset( $args['properties'] ) ) { // schema version 3 2010 foreach ( $args['properties'] as $name => $property ) { 2011 if ( isset( $property['required'] ) && true === $property['required'] && ! array_key_exists( $name, $value ) ) { 2012 /* translators: 1: Property of an object, 2: Parameter. */ 2013 return new WP_Error( 'rest_property_required', sprintf( __( '%1$s is a required property of %2$s.' ), $name, $param ) ); 2014 } 2015 } 2016 } 2017 2018 foreach ( $value as $property => $v ) { 2019 if ( isset( $args['properties'][ $property ] ) ) { 2020 $is_valid = rest_validate_value_from_schema( $v, $args['properties'][ $property ], $param . '[' . $property . ']' ); 2021 if ( is_wp_error( $is_valid ) ) { 2022 return $is_valid; 2023 } 2024 continue; 2025 } 2026 2027 $pattern_property_schema = rest_find_matching_pattern_property_schema( $property, $args ); 2028 if ( null !== $pattern_property_schema ) { 2029 $is_valid = rest_validate_value_from_schema( $v, $pattern_property_schema, $param . '[' . $property . ']' ); 2030 if ( is_wp_error( $is_valid ) ) { 2031 return $is_valid; 2032 } 2033 continue; 2034 } 2035 2036 if ( isset( $args['additionalProperties'] ) ) { 2037 if ( false === $args['additionalProperties'] ) { 2038 /* translators: %s: Property of an object. */ 2039 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s is not a valid property of Object.' ), $property ) ); 2040 } 2041 2042 if ( is_array( $args['additionalProperties'] ) ) { 2043 $is_valid = rest_validate_value_from_schema( $v, $args['additionalProperties'], $param . '[' . $property . ']' ); 2044 if ( is_wp_error( $is_valid ) ) { 2045 return $is_valid; 2046 } 2047 } 2048 } 2049 } 2050 2051 if ( isset( $args['minProperties'] ) && count( $value ) < $args['minProperties'] ) { 2052 /* translators: 1: Parameter, 2: Number. */ 2053 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must contain at least %2$s properties.' ), $param, number_format_i18n( $args['minProperties'] ) ) ); 2054 } 2055 2056 if ( isset( $args['maxProperties'] ) && count( $value ) > $args['maxProperties'] ) { 2057 /* translators: 1: Parameter, 2: Number. */ 2058 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must contain at most %2$s properties.' ), $param, number_format_i18n( $args['maxProperties'] ) ) ); 2059 } 2060 } 2061 2062 if ( 'null' === $args['type'] ) { 2063 if ( null !== $value ) { 2064 return new WP_Error( 2065 'rest_invalid_type', 2066 /* translators: 1: Parameter, 2: Type name. */ 2067 sprintf( __( '%1$s is not of type %2$s.' ), $param, 'null' ), 2068 array( 'param' => $param ) 2069 ); 2070 } 2071 2072 return true; 2073 } 2074 2075 if ( ! empty( $args['enum'] ) ) { 2076 if ( ! in_array( $value, $args['enum'], true ) ) { 2077 /* translators: 1: Parameter, 2: List of valid values. */ 2078 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s is not one of %2$s.' ), $param, implode( ', ', $args['enum'] ) ) ); 2079 } 2080 } 2081 2082 if ( in_array( $args['type'], array( 'integer', 'number' ), true ) ) { 2083 if ( ! is_numeric( $value ) ) { 2084 return new WP_Error( 2085 'rest_invalid_type', 2086 /* translators: 1: Parameter, 2: Type name. */ 2087 sprintf( __( '%1$s is not of type %2$s.' ), $param, $args['type'] ), 2088 array( 'param' => $param ) 2089 ); 2090 } 2091 2092 if ( isset( $args['multipleOf'] ) && fmod( $value, $args['multipleOf'] ) !== 0.0 ) { 2093 /* translators: 1: Parameter, 2: Multiplier. */ 2094 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be a multiple of %2$s.' ), $param, $args['multipleOf'] ) ); 2095 } 2096 } 2097 2098 if ( 'integer' === $args['type'] && ! rest_is_integer( $value ) ) { 2099 return new WP_Error( 2100 'rest_invalid_type', 2101 /* translators: 1: Parameter, 2: Type name. */ 2102 sprintf( __( '%1$s is not of type %2$s.' ), $param, 'integer' ), 2103 array( 'param' => $param ) 2104 ); 2105 } 2106 2107 if ( 'boolean' === $args['type'] && ! rest_is_boolean( $value ) ) { 2108 return new WP_Error( 2109 'rest_invalid_type', 2110 /* translators: 1: Parameter, 2: Type name. */ 2111 sprintf( __( '%1$s is not of type %2$s.' ), $param, 'boolean' ), 2112 array( 'param' => $param ) 2113 ); 2114 } 2115 2116 if ( 'string' === $args['type'] ) { 2117 if ( ! is_string( $value ) ) { 2118 return new WP_Error( 2119 'rest_invalid_type', 2120 /* translators: 1: Parameter, 2: Type name. */ 2121 sprintf( __( '%1$s is not of type %2$s.' ), $param, 'string' ), 2122 array( 'param' => $param ) 2123 ); 2124 } 2125 2126 if ( isset( $args['minLength'] ) && mb_strlen( $value ) < $args['minLength'] ) { 2127 return new WP_Error( 2128 'rest_invalid_param', 2129 sprintf( 2130 /* translators: 1: Parameter, 2: Number of characters. */ 2131 _n( '%1$s must be at least %2$s character long.', '%1$s must be at least %2$s characters long.', $args['minLength'] ), 2132 $param, 2133 number_format_i18n( $args['minLength'] ) 2134 ) 2135 ); 2136 } 2137 2138 if ( isset( $args['maxLength'] ) && mb_strlen( $value ) > $args['maxLength'] ) { 2139 return new WP_Error( 2140 'rest_invalid_param', 2141 sprintf( 2142 /* translators: 1: Parameter, 2: Number of characters. */ 2143 _n( '%1$s must be at most %2$s character long.', '%1$s must be at most %2$s characters long.', $args['maxLength'] ), 2144 $param, 2145 number_format_i18n( $args['maxLength'] ) 2146 ) 2147 ); 2148 } 2149 2150 if ( isset( $args['pattern'] ) && ! rest_validate_json_schema_pattern( $args['pattern'], $value ) ) { 2151 /* translators: 1: Parameter, 2: Pattern. */ 2152 return new WP_Error( 'rest_invalid_pattern', sprintf( __( '%1$s does not match pattern %2$s.' ), $param, $args['pattern'] ) ); 2153 } 2154 } 2155 2156 // The "format" keyword should only be applied to strings. However, for backward compatibility, 2157 // we allow the "format" keyword if the type keyword was not specified, or was set to an invalid value. 2158 if ( isset( $args['format'] ) 2159 && ( ! isset( $args['type'] ) || 'string' === $args['type'] || ! in_array( $args['type'], $allowed_types, true ) ) 2160 ) { 2161 switch ( $args['format'] ) { 2162 case 'hex-color': 2163 if ( ! rest_parse_hex_color( $value ) ) { 2164 return new WP_Error( 'rest_invalid_hex_color', __( 'Invalid hex color.' ) ); 2165 } 2166 break; 2167 2168 case 'date-time': 2169 if ( ! rest_parse_date( $value ) ) { 2170 return new WP_Error( 'rest_invalid_date', __( 'Invalid date.' ) ); 2171 } 2172 break; 2173 2174 case 'email': 2175 if ( ! is_email( $value ) ) { 2176 return new WP_Error( 'rest_invalid_email', __( 'Invalid email address.' ) ); 2177 } 2178 break; 2179 case 'ip': 2180 if ( ! rest_is_ip_address( $value ) ) { 2181 /* translators: %s: IP address. */ 2182 return new WP_Error( 'rest_invalid_param', sprintf( __( '%s is not a valid IP address.' ), $param ) ); 2183 } 2184 break; 2185 case 'uuid': 2186 if ( ! wp_is_uuid( $value ) ) { 2187 /* translators: %s: The name of a JSON field expecting a valid UUID. */ 2188 return new WP_Error( 'rest_invalid_uuid', sprintf( __( '%s is not a valid UUID.' ), $param ) ); 2189 } 2190 break; 2191 } 2192 } 2193 2194 if ( in_array( $args['type'], array( 'number', 'integer' ), true ) && ( isset( $args['minimum'] ) || isset( $args['maximum'] ) ) ) { 2195 if ( isset( $args['minimum'] ) && ! isset( $args['maximum'] ) ) { 2196 if ( ! empty( $args['exclusiveMinimum'] ) && $value <= $args['minimum'] ) { 2197 /* translators: 1: Parameter, 2: Minimum number. */ 2198 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be greater than %2$d' ), $param, $args['minimum'] ) ); 2199 } elseif ( empty( $args['exclusiveMinimum'] ) && $value < $args['minimum'] ) { 2200 /* translators: 1: Parameter, 2: Minimum number. */ 2201 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be greater than or equal to %2$d' ), $param, $args['minimum'] ) ); 2202 } 2203 } elseif ( isset( $args['maximum'] ) && ! isset( $args['minimum'] ) ) { 2204 if ( ! empty( $args['exclusiveMaximum'] ) && $value >= $args['maximum'] ) { 2205 /* translators: 1: Parameter, 2: Maximum number. */ 2206 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be less than %2$d' ), $param, $args['maximum'] ) ); 2207 } elseif ( empty( $args['exclusiveMaximum'] ) && $value > $args['maximum'] ) { 2208 /* translators: 1: Parameter, 2: Maximum number. */ 2209 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be less than or equal to %2$d' ), $param, $args['maximum'] ) ); 2210 } 2211 } elseif ( isset( $args['maximum'] ) && isset( $args['minimum'] ) ) { 2212 if ( ! empty( $args['exclusiveMinimum'] ) && ! empty( $args['exclusiveMaximum'] ) ) { 2213 if ( $value >= $args['maximum'] || $value <= $args['minimum'] ) { 2214 /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */ 2215 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be between %2$d (exclusive) and %3$d (exclusive)' ), $param, $args['minimum'], $args['maximum'] ) ); 2216 } 2217 } elseif ( empty( $args['exclusiveMinimum'] ) && ! empty( $args['exclusiveMaximum'] ) ) { 2218 if ( $value >= $args['maximum'] || $value < $args['minimum'] ) { 2219 /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */ 2220 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be between %2$d (inclusive) and %3$d (exclusive)' ), $param, $args['minimum'], $args['maximum'] ) ); 2221 } 2222 } elseif ( ! empty( $args['exclusiveMinimum'] ) && empty( $args['exclusiveMaximum'] ) ) { 2223 if ( $value > $args['maximum'] || $value <= $args['minimum'] ) { 2224 /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */ 2225 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be between %2$d (exclusive) and %3$d (inclusive)' ), $param, $args['minimum'], $args['maximum'] ) ); 2226 } 2227 } elseif ( empty( $args['exclusiveMinimum'] ) && empty( $args['exclusiveMaximum'] ) ) { 2228 if ( $value > $args['maximum'] || $value < $args['minimum'] ) { 2229 /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */ 2230 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be between %2$d (inclusive) and %3$d (inclusive)' ), $param, $args['minimum'], $args['maximum'] ) ); 2231 } 2232 } 2233 } 2234 } 2235 2236 return true; 2237 } 2238 2239 /** 2240 * Sanitize a value based on a schema. 2241 * 2242 * @since 4.7.0 2243 * @since 5.5.0 Added the `$param` parameter. 2244 * @since 5.6.0 Support the "anyOf" and "oneOf" keywords. 2245 * 2246 * @param mixed $value The value to sanitize. 2247 * @param array $args Schema array to use for sanitization. 2248 * @param string $param The parameter name, used in error messages. 2249 * @return mixed|WP_Error The sanitized value or a WP_Error instance if the value cannot be safely sanitized. 2250 */ 2251 function rest_sanitize_value_from_schema( $value, $args, $param = '' ) { 2252 if ( isset( $args['anyOf'] ) ) { 2253 $matching_schema = rest_find_any_matching_schema( $value, $args, $param ); 2254 if ( is_wp_error( $matching_schema ) ) { 2255 return $matching_schema; 2256 } 2257 2258 if ( ! isset( $args['type'] ) ) { 2259 $args['type'] = $matching_schema['type']; 2260 } 2261 2262 $value = rest_sanitize_value_from_schema( $value, $matching_schema, $param ); 2263 } 2264 2265 if ( isset( $args['oneOf'] ) ) { 2266 $matching_schema = rest_find_one_matching_schema( $value, $args, $param ); 2267 if ( is_wp_error( $matching_schema ) ) { 2268 return $matching_schema; 2269 } 2270 2271 if ( ! isset( $args['type'] ) ) { 2272 $args['type'] = $matching_schema['type']; 2273 } 2274 2275 $value = rest_sanitize_value_from_schema( $value, $matching_schema, $param ); 2276 } 2277 2278 $allowed_types = array( 'array', 'object', 'string', 'number', 'integer', 'boolean', 'null' ); 2279 2280 if ( ! isset( $args['type'] ) ) { 2281 /* translators: %s: Parameter. */ 2282 _doing_it_wrong( __FUNCTION__, sprintf( __( 'The "type" schema keyword for %s is required.' ), $param ), '5.5.0' ); 2283 } 2284 2285 if ( is_array( $args['type'] ) ) { 2286 $best_type = rest_handle_multi_type_schema( $value, $args, $param ); 2287 2288 if ( ! $best_type ) { 2289 return null; 2290 } 2291 2292 $args['type'] = $best_type; 2293 } 2294 2295 if ( ! in_array( $args['type'], $allowed_types, true ) ) { 2296 _doing_it_wrong( 2297 __FUNCTION__, 2298 /* translators: 1: Parameter, 2: The list of allowed types. */ 2299 wp_sprintf( __( 'The "type" schema keyword for %1$s can only be one of the built-in types: %2$l.' ), $param, $allowed_types ), 2300 '5.5.0' 2301 ); 2302 } 2303 2304 if ( 'array' === $args['type'] ) { 2305 $value = rest_sanitize_array( $value ); 2306 2307 if ( ! empty( $args['items'] ) ) { 2308 foreach ( $value as $index => $v ) { 2309 $value[ $index ] = rest_sanitize_value_from_schema( $v, $args['items'], $param . '[' . $index . ']' ); 2310 } 2311 } 2312 2313 if ( ! empty( $args['uniqueItems'] ) && ! rest_validate_array_contains_unique_items( $value ) ) { 2314 /* translators: 1: Parameter. */ 2315 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s has duplicate items.' ), $param ) ); 2316 } 2317 2318 return $value; 2319 } 2320 2321 if ( 'object' === $args['type'] ) { 2322 $value = rest_sanitize_object( $value ); 2323 2324 foreach ( $value as $property => $v ) { 2325 if ( isset( $args['properties'][ $property ] ) ) { 2326 $value[ $property ] = rest_sanitize_value_from_schema( $v, $args['properties'][ $property ], $param . '[' . $property . ']' ); 2327 continue; 2328 } 2329 2330 $pattern_property_schema = rest_find_matching_pattern_property_schema( $property, $args ); 2331 if ( null !== $pattern_property_schema ) { 2332 $value[ $property ] = rest_sanitize_value_from_schema( $v, $pattern_property_schema, $param . '[' . $property . ']' ); 2333 continue; 2334 } 2335 2336 if ( isset( $args['additionalProperties'] ) ) { 2337 if ( false === $args['additionalProperties'] ) { 2338 unset( $value[ $property ] ); 2339 } elseif ( is_array( $args['additionalProperties'] ) ) { 2340 $value[ $property ] = rest_sanitize_value_from_schema( $v, $args['additionalProperties'], $param . '[' . $property . ']' ); 2341 } 2342 } 2343 } 2344 2345 return $value; 2346 } 2347 2348 if ( 'null' === $args['type'] ) { 2349 return null; 2350 } 2351 2352 if ( 'integer' === $args['type'] ) { 2353 return (int) $value; 2354 } 2355 2356 if ( 'number' === $args['type'] ) { 2357 return (float) $value; 2358 } 2359 2360 if ( 'boolean' === $args['type'] ) { 2361 return rest_sanitize_boolean( $value ); 2362 } 2363 2364 // This behavior matches rest_validate_value_from_schema(). 2365 if ( isset( $args['format'] ) 2366 && ( ! isset( $args['type'] ) || 'string' === $args['type'] || ! in_array( $args['type'], $allowed_types, true ) ) 2367 ) { 2368 switch ( $args['format'] ) { 2369 case 'hex-color': 2370 return (string) sanitize_hex_color( $value ); 2371 2372 case 'date-time': 2373 return sanitize_text_field( $value ); 2374 2375 case 'email': 2376 // sanitize_email() validates, which would be unexpected. 2377 return sanitize_text_field( $value ); 2378 2379 case 'uri': 2380 return esc_url_raw( $value ); 2381 2382 case 'ip': 2383 return sanitize_text_field( $value ); 2384 2385 case 'uuid': 2386 return sanitize_text_field( $value ); 2387 } 2388 } 2389 2390 if ( 'string' === $args['type'] ) { 2391 return (string) $value; 2392 } 2393 2394 return $value; 2395 } 2396 2397 /** 2398 * Append result of internal request to REST API for purpose of preloading data to be attached to a page. 2399 * Expected to be called in the context of `array_reduce`. 2400 * 2401 * @since 5.0.0 2402 * 2403 * @param array $memo Reduce accumulator. 2404 * @param string $path REST API path to preload. 2405 * @return array Modified reduce accumulator. 2406 */ 2407 function rest_preload_api_request( $memo, $path ) { 2408 // array_reduce() doesn't support passing an array in PHP 5.2, 2409 // so we need to make sure we start with one. 2410 if ( ! is_array( $memo ) ) { 2411 $memo = array(); 2412 } 2413 2414 if ( empty( $path ) ) { 2415 return $memo; 2416 } 2417 2418 $method = 'GET'; 2419 if ( is_array( $path ) && 2 === count( $path ) ) { 2420 $method = end( $path ); 2421 $path = reset( $path ); 2422 2423 if ( ! in_array( $method, array( 'GET', 'OPTIONS' ), true ) ) { 2424 $method = 'GET'; 2425 } 2426 } 2427 2428 $path_parts = parse_url( $path ); 2429 if ( false === $path_parts ) { 2430 return $memo; 2431 } 2432 2433 $request = new WP_REST_Request( $method, $path_parts['path'] ); 2434 if ( ! empty( $path_parts['query'] ) ) { 2435 parse_str( $path_parts['query'], $query_params ); 2436 $request->set_query_params( $query_params ); 2437 } 2438 2439 $response = rest_do_request( $request ); 2440 if ( 200 === $response->status ) { 2441 $server = rest_get_server(); 2442 $data = (array) $response->get_data(); 2443 $links = $server::get_compact_response_links( $response ); 2444 if ( ! empty( $links ) ) { 2445 $data['_links'] = $links; 2446 } 2447 2448 if ( 'OPTIONS' === $method ) { 2449 $response = rest_send_allow_header( $response, $server, $request ); 2450 2451 $memo[ $method ][ $path ] = array( 2452 'body' => $data, 2453 'headers' => $response->headers, 2454 ); 2455 } else { 2456 $memo[ $path ] = array( 2457 'body' => $data, 2458 'headers' => $response->headers, 2459 ); 2460 } 2461 } 2462 2463 return $memo; 2464 } 2465 2466 /** 2467 * Parses the "_embed" parameter into the list of resources to embed. 2468 * 2469 * @since 5.4.0 2470 * 2471 * @param string|array $embed Raw "_embed" parameter value. 2472 * @return true|string[] Either true to embed all embeds, or a list of relations to embed. 2473 */ 2474 function rest_parse_embed_param( $embed ) { 2475 if ( ! $embed || 'true' === $embed || '1' === $embed ) { 2476 return true; 2477 } 2478 2479 $rels = wp_parse_list( $embed ); 2480 2481 if ( ! $rels ) { 2482 return true; 2483 } 2484 2485 return $rels; 2486 } 2487 2488 /** 2489 * Filters the response to remove any fields not available in the given context. 2490 * 2491 * @since 5.5.0 2492 * @since 5.6.0 Support the "patternProperties" keyword for objects. 2493 * Support the "anyOf" and "oneOf" keywords. 2494 * 2495 * @param array|object $data The response data to modify. 2496 * @param array $schema The schema for the endpoint used to filter the response. 2497 * @param string $context The requested context. 2498 * @return array|object The filtered response data. 2499 */ 2500 function rest_filter_response_by_context( $data, $schema, $context ) { 2501 if ( isset( $schema['anyOf'] ) ) { 2502 $matching_schema = rest_find_any_matching_schema( $data, $schema, '' ); 2503 if ( ! is_wp_error( $matching_schema ) ) { 2504 if ( ! isset( $schema['type'] ) ) { 2505 $schema['type'] = $matching_schema['type']; 2506 } 2507 2508 $data = rest_filter_response_by_context( $data, $matching_schema, $context ); 2509 } 2510 } 2511 2512 if ( isset( $schema['oneOf'] ) ) { 2513 $matching_schema = rest_find_one_matching_schema( $data, $schema, '', true ); 2514 if ( ! is_wp_error( $matching_schema ) ) { 2515 if ( ! isset( $schema['type'] ) ) { 2516 $schema['type'] = $matching_schema['type']; 2517 } 2518 2519 $data = rest_filter_response_by_context( $data, $matching_schema, $context ); 2520 } 2521 } 2522 2523 if ( ! is_array( $data ) && ! is_object( $data ) ) { 2524 return $data; 2525 } 2526 2527 if ( isset( $schema['type'] ) ) { 2528 $type = $schema['type']; 2529 } elseif ( isset( $schema['properties'] ) ) { 2530 $type = 'object'; // Back compat if a developer accidentally omitted the type. 2531 } else { 2532 return $data; 2533 } 2534 2535 $is_array_type = 'array' === $type || ( is_array( $type ) && in_array( 'array', $type, true ) ); 2536 $is_object_type = 'object' === $type || ( is_array( $type ) && in_array( 'object', $type, true ) ); 2537 2538 if ( $is_array_type && $is_object_type ) { 2539 if ( rest_is_array( $data ) ) { 2540 $is_object_type = false; 2541 } else { 2542 $is_array_type = false; 2543 } 2544 } 2545 2546 $has_additional_properties = $is_object_type && isset( $schema['additionalProperties'] ) && is_array( $schema['additionalProperties'] ); 2547 2548 foreach ( $data as $key => $value ) { 2549 $check = array(); 2550 2551 if ( $is_array_type ) { 2552 $check = isset( $schema['items'] ) ? $schema['items'] : array(); 2553 } elseif ( $is_object_type ) { 2554 if ( isset( $schema['properties'][ $key ] ) ) { 2555 $check = $schema['properties'][ $key ]; 2556 } else { 2557 $pattern_property_schema = rest_find_matching_pattern_property_schema( $key, $schema ); 2558 if ( null !== $pattern_property_schema ) { 2559 $check = $pattern_property_schema; 2560 } elseif ( $has_additional_properties ) { 2561 $check = $schema['additionalProperties']; 2562 } 2563 } 2564 } 2565 2566 if ( ! isset( $check['context'] ) ) { 2567 continue; 2568 } 2569 2570 if ( ! in_array( $context, $check['context'], true ) ) { 2571 if ( $is_array_type ) { 2572 // All array items share schema, so there's no need to check each one. 2573 $data = array(); 2574 break; 2575 } 2576 2577 if ( is_object( $data ) ) { 2578 unset( $data->$key ); 2579 } else { 2580 unset( $data[ $key ] ); 2581 } 2582 } elseif ( is_array( $value ) || is_object( $value ) ) { 2583 $new_value = rest_filter_response_by_context( $value, $check, $context ); 2584 2585 if ( is_object( $data ) ) { 2586 $data->$key = $new_value; 2587 } else { 2588 $data[ $key ] = $new_value; 2589 } 2590 } 2591 } 2592 2593 return $data; 2594 } 2595 2596 /** 2597 * Sets the "additionalProperties" to false by default for all object definitions in the schema. 2598 * 2599 * @since 5.5.0 2600 * @since 5.6.0 Support the "patternProperties" keyword. 2601 * 2602 * @param array $schema The schema to modify. 2603 * @return array The modified schema. 2604 */ 2605 function rest_default_additional_properties_to_false( $schema ) { 2606 $type = (array) $schema['type']; 2607 2608 if ( in_array( 'object', $type, true ) ) { 2609 if ( isset( $schema['properties'] ) ) { 2610 foreach ( $schema['properties'] as $key => $child_schema ) { 2611 $schema['properties'][ $key ] = rest_default_additional_properties_to_false( $child_schema ); 2612 } 2613 } 2614 2615 if ( isset( $schema['patternProperties'] ) ) { 2616 foreach ( $schema['patternProperties'] as $key => $child_schema ) { 2617 $schema['patternProperties'][ $key ] = rest_default_additional_properties_to_false( $child_schema ); 2618 } 2619 } 2620 2621 if ( ! isset( $schema['additionalProperties'] ) ) { 2622 $schema['additionalProperties'] = false; 2623 } 2624 } 2625 2626 if ( in_array( 'array', $type, true ) ) { 2627 if ( isset( $schema['items'] ) ) { 2628 $schema['items'] = rest_default_additional_properties_to_false( $schema['items'] ); 2629 } 2630 } 2631 2632 return $schema; 2633 } 2634 2635 /** 2636 * Gets the REST API route for a post. 2637 * 2638 * @since 5.5.0 2639 * 2640 * @param int|WP_Post $post Post ID or post object. 2641 * @return string The route path with a leading slash for the given post, or an empty string if there is not a route. 2642 */ 2643 function rest_get_route_for_post( $post ) { 2644 $post = get_post( $post ); 2645 2646 if ( ! $post instanceof WP_Post ) { 2647 return ''; 2648 } 2649 2650 $post_type = get_post_type_object( $post->post_type ); 2651 if ( ! $post_type ) { 2652 return ''; 2653 } 2654 2655 $controller = $post_type->get_rest_controller(); 2656 if ( ! $controller ) { 2657 return ''; 2658 } 2659 2660 $route = ''; 2661 2662 // The only two controllers that we can detect are the Attachments and Posts controllers. 2663 if ( in_array( get_class( $controller ), array( 'WP_REST_Attachments_Controller', 'WP_REST_Posts_Controller' ), true ) ) { 2664 $namespace = 'wp/v2'; 2665 $rest_base = ! empty( $post_type->rest_base ) ? $post_type->rest_base : $post_type->name; 2666 $route = sprintf( '/%s/%s/%d', $namespace, $rest_base, $post->ID ); 2667 } 2668 2669 /** 2670 * Filters the REST API route for a post. 2671 * 2672 * @since 5.5.0 2673 * 2674 * @param string $route The route path. 2675 * @param WP_Post $post The post object. 2676 */ 2677 return apply_filters( 'rest_route_for_post', $route, $post ); 2678 } 2679 2680 /** 2681 * Gets the REST API route for a term. 2682 * 2683 * @since 5.5.0 2684 * 2685 * @param int|WP_Term $term Term ID or term object. 2686 * @return string The route path with a leading slash for the given term, or an empty string if there is not a route. 2687 */ 2688 function rest_get_route_for_term( $term ) { 2689 $term = get_term( $term ); 2690 2691 if ( ! $term instanceof WP_Term ) { 2692 return ''; 2693 } 2694 2695 $taxonomy = get_taxonomy( $term->taxonomy ); 2696 if ( ! $taxonomy ) { 2697 return ''; 2698 } 2699 2700 $controller = $taxonomy->get_rest_controller(); 2701 if ( ! $controller ) { 2702 return ''; 2703 } 2704 2705 $route = ''; 2706 2707 // The only controller that works is the Terms controller. 2708 if ( $controller instanceof WP_REST_Terms_Controller ) { 2709 $namespace = 'wp/v2'; 2710 $rest_base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name; 2711 $route = sprintf( '/%s/%s/%d', $namespace, $rest_base, $term->term_id ); 2712 } 2713 2714 /** 2715 * Filters the REST API route for a term. 2716 * 2717 * @since 5.5.0 2718 * 2719 * @param string $route The route path. 2720 * @param WP_Term $term The term object. 2721 */ 2722 return apply_filters( 'rest_route_for_term', $route, $term ); 2723 } 2724 2725 /** 2726 * Gets the REST route for the currently queried object. 2727 * 2728 * @since 5.5.0 2729 * 2730 * @return string The REST route of the resource, or an empty string if no resource identified. 2731 */ 2732 function rest_get_queried_resource_route() { 2733 if ( is_singular() ) { 2734 $route = rest_get_route_for_post( get_queried_object() ); 2735 } elseif ( is_category() || is_tag() || is_tax() ) { 2736 $route = rest_get_route_for_term( get_queried_object() ); 2737 } elseif ( is_author() ) { 2738 $route = '/wp/v2/users/' . get_queried_object_id(); 2739 } else { 2740 $route = ''; 2741 } 2742 2743 /** 2744 * Filters the REST route for the currently queried object. 2745 * 2746 * @since 5.5.0 2747 * 2748 * @param string $link The route with a leading slash, or an empty string. 2749 */ 2750 return apply_filters( 'rest_queried_resource_route', $route ); 2751 } 2752 2753 /** 2754 * Retrieves an array of endpoint arguments from the item schema and endpoint method. 1878 * Get all valid JSON schema properties. 2755 1879 * 2756 1880 * @since 5.6.0 2757 1881 * 2758 * @param array $schema The full JSON schema for the endpoint. 2759 * @param string $method Optional. HTTP method of the endpoint. The arguments for `CREATABLE` endpoints are 2760 * checked for required values and may fall-back to a given default, this is not done 2761 * on `EDITABLE` endpoints. Default WP_REST_Server::CREATABLE. 2762 * @return array The endpoint arguments. 2763 */ 2764 function rest_get_endpoint_args_for_schema( $schema, $method = WP_REST_Server::CREATABLE ) { 2765 2766 $schema_properties = ! empty( $schema['properties'] ) ? $schema['properties'] : array(); 2767 $endpoint_args = array(); 2768 $valid_schema_properties = array( 1882 * @return string[] All valid JSON schema properties. 1883 */ 1884 function rest_get_allowed_schema_keywords() { 1885 return array( 1886 'title', 1887 'description', 1888 'default', 2769 1889 'type', 2770 1890 'format', … … 2790 1910 'oneOf', 2791 1911 ); 1912 } 1913 1914 /** 1915 * Validate a value based on a schema. 1916 * 1917 * @since 4.7.0 1918 * @since 4.9.0 Support the "object" type. 1919 * @since 5.2.0 Support validating "additionalProperties" against a schema. 1920 * @since 5.3.0 Support multiple types. 1921 * @since 5.4.0 Convert an empty string to an empty object. 1922 * @since 5.5.0 Add the "uuid" and "hex-color" formats. 1923 * Support the "minLength", "maxLength" and "pattern" keywords for strings. 1924 * Support the "minItems", "maxItems" and "uniqueItems" keywords for arrays. 1925 * Validate required properties. 1926 * @since 5.6.0 Support the "minProperties" and "maxProperties" keywords for objects. 1927 * Support the "multipleOf" keyword for numbers and integers. 1928 * Support the "patternProperties" keyword for objects. 1929 * Support the "anyOf" and "oneOf" keywords. 1930 * 1931 * @param mixed $value The value to validate. 1932 * @param array $args Schema array to use for validation. 1933 * @param string $param The parameter name, used in error messages. 1934 * @return true|WP_Error 1935 */ 1936 function rest_validate_value_from_schema( $value, $args, $param = '' ) { 1937 if ( isset( $args['anyOf'] ) ) { 1938 $matching_schema = rest_find_any_matching_schema( $value, $args, $param ); 1939 if ( is_wp_error( $matching_schema ) ) { 1940 return $matching_schema; 1941 } 1942 1943 if ( ! isset( $args['type'] ) && isset( $matching_schema['type'] ) ) { 1944 $args['type'] = $matching_schema['type']; 1945 } 1946 } 1947 1948 if ( isset( $args['oneOf'] ) ) { 1949 $matching_schema = rest_find_one_matching_schema( $value, $args, $param ); 1950 if ( is_wp_error( $matching_schema ) ) { 1951 return $matching_schema; 1952 } 1953 1954 if ( ! isset( $args['type'] ) && isset( $matching_schema['type'] ) ) { 1955 $args['type'] = $matching_schema['type']; 1956 } 1957 } 1958 1959 $allowed_types = array( 'array', 'object', 'string', 'number', 'integer', 'boolean', 'null' ); 1960 1961 if ( ! isset( $args['type'] ) ) { 1962 /* translators: %s: Parameter. */ 1963 _doing_it_wrong( __FUNCTION__, sprintf( __( 'The "type" schema keyword for %s is required.' ), $param ), '5.5.0' ); 1964 } 1965 1966 if ( is_array( $args['type'] ) ) { 1967 $best_type = rest_handle_multi_type_schema( $value, $args, $param ); 1968 1969 if ( ! $best_type ) { 1970 return new WP_Error( 1971 'rest_invalid_type', 1972 /* translators: 1: Parameter, 2: List of types. */ 1973 sprintf( __( '%1$s is not of type %2$s.' ), $param, implode( ',', $args['type'] ) ), 1974 array( 'param' => $param ) 1975 ); 1976 } 1977 1978 $args['type'] = $best_type; 1979 } 1980 1981 if ( ! in_array( $args['type'], $allowed_types, true ) ) { 1982 _doing_it_wrong( 1983 __FUNCTION__, 1984 /* translators: 1: Parameter, 2: The list of allowed types. */ 1985 wp_sprintf( __( 'The "type" schema keyword for %1$s can only be one of the built-in types: %2$l.' ), $param, $allowed_types ), 1986 '5.5.0' 1987 ); 1988 } 1989 1990 if ( 'array' === $args['type'] ) { 1991 if ( ! rest_is_array( $value ) ) { 1992 return new WP_Error( 1993 'rest_invalid_type', 1994 /* translators: 1: Parameter, 2: Type name. */ 1995 sprintf( __( '%1$s is not of type %2$s.' ), $param, 'array' ), 1996 array( 'param' => $param ) 1997 ); 1998 } 1999 2000 $value = rest_sanitize_array( $value ); 2001 2002 if ( isset( $args['items'] ) ) { 2003 foreach ( $value as $index => $v ) { 2004 $is_valid = rest_validate_value_from_schema( $v, $args['items'], $param . '[' . $index . ']' ); 2005 if ( is_wp_error( $is_valid ) ) { 2006 return $is_valid; 2007 } 2008 } 2009 } 2010 2011 if ( isset( $args['minItems'] ) && count( $value ) < $args['minItems'] ) { 2012 /* translators: 1: Parameter, 2: Number. */ 2013 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must contain at least %2$s items.' ), $param, number_format_i18n( $args['minItems'] ) ) ); 2014 } 2015 2016 if ( isset( $args['maxItems'] ) && count( $value ) > $args['maxItems'] ) { 2017 /* translators: 1: Parameter, 2: Number. */ 2018 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must contain at most %2$s items.' ), $param, number_format_i18n( $args['maxItems'] ) ) ); 2019 } 2020 2021 if ( ! empty( $args['uniqueItems'] ) && ! rest_validate_array_contains_unique_items( $value ) ) { 2022 /* translators: 1: Parameter. */ 2023 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s has duplicate items.' ), $param ) ); 2024 } 2025 } 2026 2027 if ( 'object' === $args['type'] ) { 2028 if ( ! rest_is_object( $value ) ) { 2029 return new WP_Error( 2030 'rest_invalid_type', 2031 /* translators: 1: Parameter, 2: Type name. */ 2032 sprintf( __( '%1$s is not of type %2$s.' ), $param, 'object' ), 2033 array( 'param' => $param ) 2034 ); 2035 } 2036 2037 $value = rest_sanitize_object( $value ); 2038 2039 if ( isset( $args['required'] ) && is_array( $args['required'] ) ) { // schema version 4 2040 foreach ( $args['required'] as $name ) { 2041 if ( ! array_key_exists( $name, $value ) ) { 2042 /* translators: 1: Property of an object, 2: Parameter. */ 2043 return new WP_Error( 'rest_property_required', sprintf( __( '%1$s is a required property of %2$s.' ), $name, $param ) ); 2044 } 2045 } 2046 } elseif ( isset( $args['properties'] ) ) { // schema version 3 2047 foreach ( $args['properties'] as $name => $property ) { 2048 if ( isset( $property['required'] ) && true === $property['required'] && ! array_key_exists( $name, $value ) ) { 2049 /* translators: 1: Property of an object, 2: Parameter. */ 2050 return new WP_Error( 'rest_property_required', sprintf( __( '%1$s is a required property of %2$s.' ), $name, $param ) ); 2051 } 2052 } 2053 } 2054 2055 foreach ( $value as $property => $v ) { 2056 if ( isset( $args['properties'][ $property ] ) ) { 2057 $is_valid = rest_validate_value_from_schema( $v, $args['properties'][ $property ], $param . '[' . $property . ']' ); 2058 if ( is_wp_error( $is_valid ) ) { 2059 return $is_valid; 2060 } 2061 continue; 2062 } 2063 2064 $pattern_property_schema = rest_find_matching_pattern_property_schema( $property, $args ); 2065 if ( null !== $pattern_property_schema ) { 2066 $is_valid = rest_validate_value_from_schema( $v, $pattern_property_schema, $param . '[' . $property . ']' ); 2067 if ( is_wp_error( $is_valid ) ) { 2068 return $is_valid; 2069 } 2070 continue; 2071 } 2072 2073 if ( isset( $args['additionalProperties'] ) ) { 2074 if ( false === $args['additionalProperties'] ) { 2075 /* translators: %s: Property of an object. */ 2076 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s is not a valid property of Object.' ), $property ) ); 2077 } 2078 2079 if ( is_array( $args['additionalProperties'] ) ) { 2080 $is_valid = rest_validate_value_from_schema( $v, $args['additionalProperties'], $param . '[' . $property . ']' ); 2081 if ( is_wp_error( $is_valid ) ) { 2082 return $is_valid; 2083 } 2084 } 2085 } 2086 } 2087 2088 if ( isset( $args['minProperties'] ) && count( $value ) < $args['minProperties'] ) { 2089 /* translators: 1: Parameter, 2: Number. */ 2090 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must contain at least %2$s properties.' ), $param, number_format_i18n( $args['minProperties'] ) ) ); 2091 } 2092 2093 if ( isset( $args['maxProperties'] ) && count( $value ) > $args['maxProperties'] ) { 2094 /* translators: 1: Parameter, 2: Number. */ 2095 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must contain at most %2$s properties.' ), $param, number_format_i18n( $args['maxProperties'] ) ) ); 2096 } 2097 } 2098 2099 if ( 'null' === $args['type'] ) { 2100 if ( null !== $value ) { 2101 return new WP_Error( 2102 'rest_invalid_type', 2103 /* translators: 1: Parameter, 2: Type name. */ 2104 sprintf( __( '%1$s is not of type %2$s.' ), $param, 'null' ), 2105 array( 'param' => $param ) 2106 ); 2107 } 2108 2109 return true; 2110 } 2111 2112 if ( ! empty( $args['enum'] ) ) { 2113 if ( ! in_array( $value, $args['enum'], true ) ) { 2114 /* translators: 1: Parameter, 2: List of valid values. */ 2115 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s is not one of %2$s.' ), $param, implode( ', ', $args['enum'] ) ) ); 2116 } 2117 } 2118 2119 if ( in_array( $args['type'], array( 'integer', 'number' ), true ) ) { 2120 if ( ! is_numeric( $value ) ) { 2121 return new WP_Error( 2122 'rest_invalid_type', 2123 /* translators: 1: Parameter, 2: Type name. */ 2124 sprintf( __( '%1$s is not of type %2$s.' ), $param, $args['type'] ), 2125 array( 'param' => $param ) 2126 ); 2127 } 2128 2129 if ( isset( $args['multipleOf'] ) && fmod( $value, $args['multipleOf'] ) !== 0.0 ) { 2130 /* translators: 1: Parameter, 2: Multiplier. */ 2131 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be a multiple of %2$s.' ), $param, $args['multipleOf'] ) ); 2132 } 2133 } 2134 2135 if ( 'integer' === $args['type'] && ! rest_is_integer( $value ) ) { 2136 return new WP_Error( 2137 'rest_invalid_type', 2138 /* translators: 1: Parameter, 2: Type name. */ 2139 sprintf( __( '%1$s is not of type %2$s.' ), $param, 'integer' ), 2140 array( 'param' => $param ) 2141 ); 2142 } 2143 2144 if ( 'boolean' === $args['type'] && ! rest_is_boolean( $value ) ) { 2145 return new WP_Error( 2146 'rest_invalid_type', 2147 /* translators: 1: Parameter, 2: Type name. */ 2148 sprintf( __( '%1$s is not of type %2$s.' ), $param, 'boolean' ), 2149 array( 'param' => $param ) 2150 ); 2151 } 2152 2153 if ( 'string' === $args['type'] ) { 2154 if ( ! is_string( $value ) ) { 2155 return new WP_Error( 2156 'rest_invalid_type', 2157 /* translators: 1: Parameter, 2: Type name. */ 2158 sprintf( __( '%1$s is not of type %2$s.' ), $param, 'string' ), 2159 array( 'param' => $param ) 2160 ); 2161 } 2162 2163 if ( isset( $args['minLength'] ) && mb_strlen( $value ) < $args['minLength'] ) { 2164 return new WP_Error( 2165 'rest_invalid_param', 2166 sprintf( 2167 /* translators: 1: Parameter, 2: Number of characters. */ 2168 _n( '%1$s must be at least %2$s character long.', '%1$s must be at least %2$s characters long.', $args['minLength'] ), 2169 $param, 2170 number_format_i18n( $args['minLength'] ) 2171 ) 2172 ); 2173 } 2174 2175 if ( isset( $args['maxLength'] ) && mb_strlen( $value ) > $args['maxLength'] ) { 2176 return new WP_Error( 2177 'rest_invalid_param', 2178 sprintf( 2179 /* translators: 1: Parameter, 2: Number of characters. */ 2180 _n( '%1$s must be at most %2$s character long.', '%1$s must be at most %2$s characters long.', $args['maxLength'] ), 2181 $param, 2182 number_format_i18n( $args['maxLength'] ) 2183 ) 2184 ); 2185 } 2186 2187 if ( isset( $args['pattern'] ) && ! rest_validate_json_schema_pattern( $args['pattern'], $value ) ) { 2188 /* translators: 1: Parameter, 2: Pattern. */ 2189 return new WP_Error( 'rest_invalid_pattern', sprintf( __( '%1$s does not match pattern %2$s.' ), $param, $args['pattern'] ) ); 2190 } 2191 } 2192 2193 // The "format" keyword should only be applied to strings. However, for backward compatibility, 2194 // we allow the "format" keyword if the type keyword was not specified, or was set to an invalid value. 2195 if ( isset( $args['format'] ) 2196 && ( ! isset( $args['type'] ) || 'string' === $args['type'] || ! in_array( $args['type'], $allowed_types, true ) ) 2197 ) { 2198 switch ( $args['format'] ) { 2199 case 'hex-color': 2200 if ( ! rest_parse_hex_color( $value ) ) { 2201 return new WP_Error( 'rest_invalid_hex_color', __( 'Invalid hex color.' ) ); 2202 } 2203 break; 2204 2205 case 'date-time': 2206 if ( ! rest_parse_date( $value ) ) { 2207 return new WP_Error( 'rest_invalid_date', __( 'Invalid date.' ) ); 2208 } 2209 break; 2210 2211 case 'email': 2212 if ( ! is_email( $value ) ) { 2213 return new WP_Error( 'rest_invalid_email', __( 'Invalid email address.' ) ); 2214 } 2215 break; 2216 case 'ip': 2217 if ( ! rest_is_ip_address( $value ) ) { 2218 /* translators: %s: IP address. */ 2219 return new WP_Error( 'rest_invalid_param', sprintf( __( '%s is not a valid IP address.' ), $param ) ); 2220 } 2221 break; 2222 case 'uuid': 2223 if ( ! wp_is_uuid( $value ) ) { 2224 /* translators: %s: The name of a JSON field expecting a valid UUID. */ 2225 return new WP_Error( 'rest_invalid_uuid', sprintf( __( '%s is not a valid UUID.' ), $param ) ); 2226 } 2227 break; 2228 } 2229 } 2230 2231 if ( in_array( $args['type'], array( 'number', 'integer' ), true ) && ( isset( $args['minimum'] ) || isset( $args['maximum'] ) ) ) { 2232 if ( isset( $args['minimum'] ) && ! isset( $args['maximum'] ) ) { 2233 if ( ! empty( $args['exclusiveMinimum'] ) && $value <= $args['minimum'] ) { 2234 /* translators: 1: Parameter, 2: Minimum number. */ 2235 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be greater than %2$d' ), $param, $args['minimum'] ) ); 2236 } elseif ( empty( $args['exclusiveMinimum'] ) && $value < $args['minimum'] ) { 2237 /* translators: 1: Parameter, 2: Minimum number. */ 2238 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be greater than or equal to %2$d' ), $param, $args['minimum'] ) ); 2239 } 2240 } elseif ( isset( $args['maximum'] ) && ! isset( $args['minimum'] ) ) { 2241 if ( ! empty( $args['exclusiveMaximum'] ) && $value >= $args['maximum'] ) { 2242 /* translators: 1: Parameter, 2: Maximum number. */ 2243 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be less than %2$d' ), $param, $args['maximum'] ) ); 2244 } elseif ( empty( $args['exclusiveMaximum'] ) && $value > $args['maximum'] ) { 2245 /* translators: 1: Parameter, 2: Maximum number. */ 2246 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be less than or equal to %2$d' ), $param, $args['maximum'] ) ); 2247 } 2248 } elseif ( isset( $args['maximum'] ) && isset( $args['minimum'] ) ) { 2249 if ( ! empty( $args['exclusiveMinimum'] ) && ! empty( $args['exclusiveMaximum'] ) ) { 2250 if ( $value >= $args['maximum'] || $value <= $args['minimum'] ) { 2251 /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */ 2252 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be between %2$d (exclusive) and %3$d (exclusive)' ), $param, $args['minimum'], $args['maximum'] ) ); 2253 } 2254 } elseif ( empty( $args['exclusiveMinimum'] ) && ! empty( $args['exclusiveMaximum'] ) ) { 2255 if ( $value >= $args['maximum'] || $value < $args['minimum'] ) { 2256 /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */ 2257 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be between %2$d (inclusive) and %3$d (exclusive)' ), $param, $args['minimum'], $args['maximum'] ) ); 2258 } 2259 } elseif ( ! empty( $args['exclusiveMinimum'] ) && empty( $args['exclusiveMaximum'] ) ) { 2260 if ( $value > $args['maximum'] || $value <= $args['minimum'] ) { 2261 /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */ 2262 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be between %2$d (exclusive) and %3$d (inclusive)' ), $param, $args['minimum'], $args['maximum'] ) ); 2263 } 2264 } elseif ( empty( $args['exclusiveMinimum'] ) && empty( $args['exclusiveMaximum'] ) ) { 2265 if ( $value > $args['maximum'] || $value < $args['minimum'] ) { 2266 /* translators: 1: Parameter, 2: Minimum number, 3: Maximum number. */ 2267 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s must be between %2$d (inclusive) and %3$d (inclusive)' ), $param, $args['minimum'], $args['maximum'] ) ); 2268 } 2269 } 2270 } 2271 } 2272 2273 return true; 2274 } 2275 2276 /** 2277 * Sanitize a value based on a schema. 2278 * 2279 * @since 4.7.0 2280 * @since 5.5.0 Added the `$param` parameter. 2281 * @since 5.6.0 Support the "anyOf" and "oneOf" keywords. 2282 * 2283 * @param mixed $value The value to sanitize. 2284 * @param array $args Schema array to use for sanitization. 2285 * @param string $param The parameter name, used in error messages. 2286 * @return mixed|WP_Error The sanitized value or a WP_Error instance if the value cannot be safely sanitized. 2287 */ 2288 function rest_sanitize_value_from_schema( $value, $args, $param = '' ) { 2289 if ( isset( $args['anyOf'] ) ) { 2290 $matching_schema = rest_find_any_matching_schema( $value, $args, $param ); 2291 if ( is_wp_error( $matching_schema ) ) { 2292 return $matching_schema; 2293 } 2294 2295 if ( ! isset( $args['type'] ) ) { 2296 $args['type'] = $matching_schema['type']; 2297 } 2298 2299 $value = rest_sanitize_value_from_schema( $value, $matching_schema, $param ); 2300 } 2301 2302 if ( isset( $args['oneOf'] ) ) { 2303 $matching_schema = rest_find_one_matching_schema( $value, $args, $param ); 2304 if ( is_wp_error( $matching_schema ) ) { 2305 return $matching_schema; 2306 } 2307 2308 if ( ! isset( $args['type'] ) ) { 2309 $args['type'] = $matching_schema['type']; 2310 } 2311 2312 $value = rest_sanitize_value_from_schema( $value, $matching_schema, $param ); 2313 } 2314 2315 $allowed_types = array( 'array', 'object', 'string', 'number', 'integer', 'boolean', 'null' ); 2316 2317 if ( ! isset( $args['type'] ) ) { 2318 /* translators: %s: Parameter. */ 2319 _doing_it_wrong( __FUNCTION__, sprintf( __( 'The "type" schema keyword for %s is required.' ), $param ), '5.5.0' ); 2320 } 2321 2322 if ( is_array( $args['type'] ) ) { 2323 $best_type = rest_handle_multi_type_schema( $value, $args, $param ); 2324 2325 if ( ! $best_type ) { 2326 return null; 2327 } 2328 2329 $args['type'] = $best_type; 2330 } 2331 2332 if ( ! in_array( $args['type'], $allowed_types, true ) ) { 2333 _doing_it_wrong( 2334 __FUNCTION__, 2335 /* translators: 1: Parameter, 2: The list of allowed types. */ 2336 wp_sprintf( __( 'The "type" schema keyword for %1$s can only be one of the built-in types: %2$l.' ), $param, $allowed_types ), 2337 '5.5.0' 2338 ); 2339 } 2340 2341 if ( 'array' === $args['type'] ) { 2342 $value = rest_sanitize_array( $value ); 2343 2344 if ( ! empty( $args['items'] ) ) { 2345 foreach ( $value as $index => $v ) { 2346 $value[ $index ] = rest_sanitize_value_from_schema( $v, $args['items'], $param . '[' . $index . ']' ); 2347 } 2348 } 2349 2350 if ( ! empty( $args['uniqueItems'] ) && ! rest_validate_array_contains_unique_items( $value ) ) { 2351 /* translators: 1: Parameter. */ 2352 return new WP_Error( 'rest_invalid_param', sprintf( __( '%1$s has duplicate items.' ), $param ) ); 2353 } 2354 2355 return $value; 2356 } 2357 2358 if ( 'object' === $args['type'] ) { 2359 $value = rest_sanitize_object( $value ); 2360 2361 foreach ( $value as $property => $v ) { 2362 if ( isset( $args['properties'][ $property ] ) ) { 2363 $value[ $property ] = rest_sanitize_value_from_schema( $v, $args['properties'][ $property ], $param . '[' . $property . ']' ); 2364 continue; 2365 } 2366 2367 $pattern_property_schema = rest_find_matching_pattern_property_schema( $property, $args ); 2368 if ( null !== $pattern_property_schema ) { 2369 $value[ $property ] = rest_sanitize_value_from_schema( $v, $pattern_property_schema, $param . '[' . $property . ']' ); 2370 continue; 2371 } 2372 2373 if ( isset( $args['additionalProperties'] ) ) { 2374 if ( false === $args['additionalProperties'] ) { 2375 unset( $value[ $property ] ); 2376 } elseif ( is_array( $args['additionalProperties'] ) ) { 2377 $value[ $property ] = rest_sanitize_value_from_schema( $v, $args['additionalProperties'], $param . '[' . $property . ']' ); 2378 } 2379 } 2380 } 2381 2382 return $value; 2383 } 2384 2385 if ( 'null' === $args['type'] ) { 2386 return null; 2387 } 2388 2389 if ( 'integer' === $args['type'] ) { 2390 return (int) $value; 2391 } 2392 2393 if ( 'number' === $args['type'] ) { 2394 return (float) $value; 2395 } 2396 2397 if ( 'boolean' === $args['type'] ) { 2398 return rest_sanitize_boolean( $value ); 2399 } 2400 2401 // This behavior matches rest_validate_value_from_schema(). 2402 if ( isset( $args['format'] ) 2403 && ( ! isset( $args['type'] ) || 'string' === $args['type'] || ! in_array( $args['type'], $allowed_types, true ) ) 2404 ) { 2405 switch ( $args['format'] ) { 2406 case 'hex-color': 2407 return (string) sanitize_hex_color( $value ); 2408 2409 case 'date-time': 2410 return sanitize_text_field( $value ); 2411 2412 case 'email': 2413 // sanitize_email() validates, which would be unexpected. 2414 return sanitize_text_field( $value ); 2415 2416 case 'uri': 2417 return esc_url_raw( $value ); 2418 2419 case 'ip': 2420 return sanitize_text_field( $value ); 2421 2422 case 'uuid': 2423 return sanitize_text_field( $value ); 2424 } 2425 } 2426 2427 if ( 'string' === $args['type'] ) { 2428 return (string) $value; 2429 } 2430 2431 return $value; 2432 } 2433 2434 /** 2435 * Append result of internal request to REST API for purpose of preloading data to be attached to a page. 2436 * Expected to be called in the context of `array_reduce`. 2437 * 2438 * @since 5.0.0 2439 * 2440 * @param array $memo Reduce accumulator. 2441 * @param string $path REST API path to preload. 2442 * @return array Modified reduce accumulator. 2443 */ 2444 function rest_preload_api_request( $memo, $path ) { 2445 // array_reduce() doesn't support passing an array in PHP 5.2, 2446 // so we need to make sure we start with one. 2447 if ( ! is_array( $memo ) ) { 2448 $memo = array(); 2449 } 2450 2451 if ( empty( $path ) ) { 2452 return $memo; 2453 } 2454 2455 $method = 'GET'; 2456 if ( is_array( $path ) && 2 === count( $path ) ) { 2457 $method = end( $path ); 2458 $path = reset( $path ); 2459 2460 if ( ! in_array( $method, array( 'GET', 'OPTIONS' ), true ) ) { 2461 $method = 'GET'; 2462 } 2463 } 2464 2465 $path_parts = parse_url( $path ); 2466 if ( false === $path_parts ) { 2467 return $memo; 2468 } 2469 2470 $request = new WP_REST_Request( $method, $path_parts['path'] ); 2471 if ( ! empty( $path_parts['query'] ) ) { 2472 parse_str( $path_parts['query'], $query_params ); 2473 $request->set_query_params( $query_params ); 2474 } 2475 2476 $response = rest_do_request( $request ); 2477 if ( 200 === $response->status ) { 2478 $server = rest_get_server(); 2479 $data = (array) $response->get_data(); 2480 $links = $server::get_compact_response_links( $response ); 2481 if ( ! empty( $links ) ) { 2482 $data['_links'] = $links; 2483 } 2484 2485 if ( 'OPTIONS' === $method ) { 2486 $response = rest_send_allow_header( $response, $server, $request ); 2487 2488 $memo[ $method ][ $path ] = array( 2489 'body' => $data, 2490 'headers' => $response->headers, 2491 ); 2492 } else { 2493 $memo[ $path ] = array( 2494 'body' => $data, 2495 'headers' => $response->headers, 2496 ); 2497 } 2498 } 2499 2500 return $memo; 2501 } 2502 2503 /** 2504 * Parses the "_embed" parameter into the list of resources to embed. 2505 * 2506 * @since 5.4.0 2507 * 2508 * @param string|array $embed Raw "_embed" parameter value. 2509 * @return true|string[] Either true to embed all embeds, or a list of relations to embed. 2510 */ 2511 function rest_parse_embed_param( $embed ) { 2512 if ( ! $embed || 'true' === $embed || '1' === $embed ) { 2513 return true; 2514 } 2515 2516 $rels = wp_parse_list( $embed ); 2517 2518 if ( ! $rels ) { 2519 return true; 2520 } 2521 2522 return $rels; 2523 } 2524 2525 /** 2526 * Filters the response to remove any fields not available in the given context. 2527 * 2528 * @since 5.5.0 2529 * @since 5.6.0 Support the "patternProperties" keyword for objects. 2530 * Support the "anyOf" and "oneOf" keywords. 2531 * 2532 * @param array|object $data The response data to modify. 2533 * @param array $schema The schema for the endpoint used to filter the response. 2534 * @param string $context The requested context. 2535 * @return array|object The filtered response data. 2536 */ 2537 function rest_filter_response_by_context( $data, $schema, $context ) { 2538 if ( isset( $schema['anyOf'] ) ) { 2539 $matching_schema = rest_find_any_matching_schema( $data, $schema, '' ); 2540 if ( ! is_wp_error( $matching_schema ) ) { 2541 if ( ! isset( $schema['type'] ) ) { 2542 $schema['type'] = $matching_schema['type']; 2543 } 2544 2545 $data = rest_filter_response_by_context( $data, $matching_schema, $context ); 2546 } 2547 } 2548 2549 if ( isset( $schema['oneOf'] ) ) { 2550 $matching_schema = rest_find_one_matching_schema( $data, $schema, '', true ); 2551 if ( ! is_wp_error( $matching_schema ) ) { 2552 if ( ! isset( $schema['type'] ) ) { 2553 $schema['type'] = $matching_schema['type']; 2554 } 2555 2556 $data = rest_filter_response_by_context( $data, $matching_schema, $context ); 2557 } 2558 } 2559 2560 if ( ! is_array( $data ) && ! is_object( $data ) ) { 2561 return $data; 2562 } 2563 2564 if ( isset( $schema['type'] ) ) { 2565 $type = $schema['type']; 2566 } elseif ( isset( $schema['properties'] ) ) { 2567 $type = 'object'; // Back compat if a developer accidentally omitted the type. 2568 } else { 2569 return $data; 2570 } 2571 2572 $is_array_type = 'array' === $type || ( is_array( $type ) && in_array( 'array', $type, true ) ); 2573 $is_object_type = 'object' === $type || ( is_array( $type ) && in_array( 'object', $type, true ) ); 2574 2575 if ( $is_array_type && $is_object_type ) { 2576 if ( rest_is_array( $data ) ) { 2577 $is_object_type = false; 2578 } else { 2579 $is_array_type = false; 2580 } 2581 } 2582 2583 $has_additional_properties = $is_object_type && isset( $schema['additionalProperties'] ) && is_array( $schema['additionalProperties'] ); 2584 2585 foreach ( $data as $key => $value ) { 2586 $check = array(); 2587 2588 if ( $is_array_type ) { 2589 $check = isset( $schema['items'] ) ? $schema['items'] : array(); 2590 } elseif ( $is_object_type ) { 2591 if ( isset( $schema['properties'][ $key ] ) ) { 2592 $check = $schema['properties'][ $key ]; 2593 } else { 2594 $pattern_property_schema = rest_find_matching_pattern_property_schema( $key, $schema ); 2595 if ( null !== $pattern_property_schema ) { 2596 $check = $pattern_property_schema; 2597 } elseif ( $has_additional_properties ) { 2598 $check = $schema['additionalProperties']; 2599 } 2600 } 2601 } 2602 2603 if ( ! isset( $check['context'] ) ) { 2604 continue; 2605 } 2606 2607 if ( ! in_array( $context, $check['context'], true ) ) { 2608 if ( $is_array_type ) { 2609 // All array items share schema, so there's no need to check each one. 2610 $data = array(); 2611 break; 2612 } 2613 2614 if ( is_object( $data ) ) { 2615 unset( $data->$key ); 2616 } else { 2617 unset( $data[ $key ] ); 2618 } 2619 } elseif ( is_array( $value ) || is_object( $value ) ) { 2620 $new_value = rest_filter_response_by_context( $value, $check, $context ); 2621 2622 if ( is_object( $data ) ) { 2623 $data->$key = $new_value; 2624 } else { 2625 $data[ $key ] = $new_value; 2626 } 2627 } 2628 } 2629 2630 return $data; 2631 } 2632 2633 /** 2634 * Sets the "additionalProperties" to false by default for all object definitions in the schema. 2635 * 2636 * @since 5.5.0 2637 * @since 5.6.0 Support the "patternProperties" keyword. 2638 * 2639 * @param array $schema The schema to modify. 2640 * @return array The modified schema. 2641 */ 2642 function rest_default_additional_properties_to_false( $schema ) { 2643 $type = (array) $schema['type']; 2644 2645 if ( in_array( 'object', $type, true ) ) { 2646 if ( isset( $schema['properties'] ) ) { 2647 foreach ( $schema['properties'] as $key => $child_schema ) { 2648 $schema['properties'][ $key ] = rest_default_additional_properties_to_false( $child_schema ); 2649 } 2650 } 2651 2652 if ( isset( $schema['patternProperties'] ) ) { 2653 foreach ( $schema['patternProperties'] as $key => $child_schema ) { 2654 $schema['patternProperties'][ $key ] = rest_default_additional_properties_to_false( $child_schema ); 2655 } 2656 } 2657 2658 if ( ! isset( $schema['additionalProperties'] ) ) { 2659 $schema['additionalProperties'] = false; 2660 } 2661 } 2662 2663 if ( in_array( 'array', $type, true ) ) { 2664 if ( isset( $schema['items'] ) ) { 2665 $schema['items'] = rest_default_additional_properties_to_false( $schema['items'] ); 2666 } 2667 } 2668 2669 return $schema; 2670 } 2671 2672 /** 2673 * Gets the REST API route for a post. 2674 * 2675 * @since 5.5.0 2676 * 2677 * @param int|WP_Post $post Post ID or post object. 2678 * @return string The route path with a leading slash for the given post, or an empty string if there is not a route. 2679 */ 2680 function rest_get_route_for_post( $post ) { 2681 $post = get_post( $post ); 2682 2683 if ( ! $post instanceof WP_Post ) { 2684 return ''; 2685 } 2686 2687 $post_type = get_post_type_object( $post->post_type ); 2688 if ( ! $post_type ) { 2689 return ''; 2690 } 2691 2692 $controller = $post_type->get_rest_controller(); 2693 if ( ! $controller ) { 2694 return ''; 2695 } 2696 2697 $route = ''; 2698 2699 // The only two controllers that we can detect are the Attachments and Posts controllers. 2700 if ( in_array( get_class( $controller ), array( 'WP_REST_Attachments_Controller', 'WP_REST_Posts_Controller' ), true ) ) { 2701 $namespace = 'wp/v2'; 2702 $rest_base = ! empty( $post_type->rest_base ) ? $post_type->rest_base : $post_type->name; 2703 $route = sprintf( '/%s/%s/%d', $namespace, $rest_base, $post->ID ); 2704 } 2705 2706 /** 2707 * Filters the REST API route for a post. 2708 * 2709 * @since 5.5.0 2710 * 2711 * @param string $route The route path. 2712 * @param WP_Post $post The post object. 2713 */ 2714 return apply_filters( 'rest_route_for_post', $route, $post ); 2715 } 2716 2717 /** 2718 * Gets the REST API route for a term. 2719 * 2720 * @since 5.5.0 2721 * 2722 * @param int|WP_Term $term Term ID or term object. 2723 * @return string The route path with a leading slash for the given term, or an empty string if there is not a route. 2724 */ 2725 function rest_get_route_for_term( $term ) { 2726 $term = get_term( $term ); 2727 2728 if ( ! $term instanceof WP_Term ) { 2729 return ''; 2730 } 2731 2732 $taxonomy = get_taxonomy( $term->taxonomy ); 2733 if ( ! $taxonomy ) { 2734 return ''; 2735 } 2736 2737 $controller = $taxonomy->get_rest_controller(); 2738 if ( ! $controller ) { 2739 return ''; 2740 } 2741 2742 $route = ''; 2743 2744 // The only controller that works is the Terms controller. 2745 if ( $controller instanceof WP_REST_Terms_Controller ) { 2746 $namespace = 'wp/v2'; 2747 $rest_base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name; 2748 $route = sprintf( '/%s/%s/%d', $namespace, $rest_base, $term->term_id ); 2749 } 2750 2751 /** 2752 * Filters the REST API route for a term. 2753 * 2754 * @since 5.5.0 2755 * 2756 * @param string $route The route path. 2757 * @param WP_Term $term The term object. 2758 */ 2759 return apply_filters( 'rest_route_for_term', $route, $term ); 2760 } 2761 2762 /** 2763 * Gets the REST route for the currently queried object. 2764 * 2765 * @since 5.5.0 2766 * 2767 * @return string The REST route of the resource, or an empty string if no resource identified. 2768 */ 2769 function rest_get_queried_resource_route() { 2770 if ( is_singular() ) { 2771 $route = rest_get_route_for_post( get_queried_object() ); 2772 } elseif ( is_category() || is_tag() || is_tax() ) { 2773 $route = rest_get_route_for_term( get_queried_object() ); 2774 } elseif ( is_author() ) { 2775 $route = '/wp/v2/users/' . get_queried_object_id(); 2776 } else { 2777 $route = ''; 2778 } 2779 2780 /** 2781 * Filters the REST route for the currently queried object. 2782 * 2783 * @since 5.5.0 2784 * 2785 * @param string $link The route with a leading slash, or an empty string. 2786 */ 2787 return apply_filters( 'rest_queried_resource_route', $route ); 2788 } 2789 2790 /** 2791 * Retrieves an array of endpoint arguments from the item schema and endpoint method. 2792 * 2793 * @since 5.6.0 2794 * 2795 * @param array $schema The full JSON schema for the endpoint. 2796 * @param string $method Optional. HTTP method of the endpoint. The arguments for `CREATABLE` endpoints are 2797 * checked for required values and may fall-back to a given default, this is not done 2798 * on `EDITABLE` endpoints. Default WP_REST_Server::CREATABLE. 2799 * @return array The endpoint arguments. 2800 */ 2801 function rest_get_endpoint_args_for_schema( $schema, $method = WP_REST_Server::CREATABLE ) { 2802 2803 $schema_properties = ! empty( $schema['properties'] ) ? $schema['properties'] : array(); 2804 $endpoint_args = array(); 2805 $valid_schema_properties = rest_get_allowed_schema_keywords(); 2806 $valid_schema_properties = array_diff( $valid_schema_properties, array( 'default', 'required' ) ); 2792 2807 2793 2808 foreach ( $schema_properties as $field_id => $params ) { … … 2802 2817 'sanitize_callback' => 'rest_sanitize_request_arg', 2803 2818 ); 2804 2805 if ( isset( $params['description'] ) ) {2806 $endpoint_args[ $field_id ]['description'] = $params['description'];2807 }2808 2819 2809 2820 if ( WP_REST_Server::CREATABLE === $method && isset( $params['default'] ) ) { -
trunk/src/wp-includes/rest-api/class-wp-rest-server.php
r49252 r49257 1381 1381 } 1382 1382 1383 $allowed_schema_keywords = array_flip( rest_get_allowed_schema_keywords() ); 1384 1383 1385 $route = preg_replace( '#\(\?P<(\w+?)>.*?\)#', '{$1}', $route ); 1384 1386 … … 1398 1400 1399 1401 foreach ( $callback['args'] as $key => $opts ) { 1400 $arg_data = array( 1401 'required' => ! empty( $opts['required'] ), 1402 ); 1403 if ( isset( $opts['default'] ) ) { 1404 $arg_data['default'] = $opts['default']; 1405 } 1406 if ( isset( $opts['enum'] ) ) { 1407 $arg_data['enum'] = $opts['enum']; 1408 } 1409 if ( isset( $opts['description'] ) ) { 1410 $arg_data['description'] = $opts['description']; 1411 } 1412 if ( isset( $opts['type'] ) ) { 1413 $arg_data['type'] = $opts['type']; 1414 } 1415 if ( isset( $opts['items'] ) ) { 1416 $arg_data['items'] = $opts['items']; 1417 } 1402 $arg_data = array_intersect_key( $opts, $allowed_schema_keywords ); 1403 $arg_data['required'] = ! empty( $opts['required'] ); 1404 1418 1405 $endpoint_data['args'][ $key ] = $arg_data; 1419 1406 } -
trunk/tests/phpunit/tests/rest-api/rest-server.php
r49252 r49257 1932 1932 } 1933 1933 1934 /** 1935 * @ticket 51020 1936 */ 1937 public function test_get_data_for_route_includes_permitted_schema_keywords() { 1938 $keywords = array( 1939 'title' => 'Hi', 1940 'description' => 'World', 1941 'type' => 'string', 1942 'default' => 0, 1943 'format' => 'uri', 1944 'enum' => array( 'https://example.org' ), 1945 'items' => array( 'type' => 'string' ), 1946 'properties' => array( 'a' => array( 'type' => 'string' ) ), 1947 'additionalProperties' => false, 1948 'patternProperties' => array( '\d' => array( 'type' => 'string' ) ), 1949 'minProperties' => 1, 1950 'maxProperties' => 5, 1951 'minimum' => 1, 1952 'maximum' => 5, 1953 'exclusiveMinimum' => true, 1954 'exclusiveMaximum' => false, 1955 'multipleOf' => 2, 1956 'minLength' => 1, 1957 'maxLength' => 5, 1958 'pattern' => '\d', 1959 'minItems' => 1, 1960 'maxItems' => 5, 1961 'uniqueItems' => true, 1962 'anyOf' => array( 1963 array( 'type' => 'string' ), 1964 array( 'type' => 'integer' ), 1965 ), 1966 'oneOf' => array( 1967 array( 'type' => 'string' ), 1968 array( 'type' => 'integer' ), 1969 ), 1970 ); 1971 1972 $param = $keywords; 1973 $param['invalid'] = true; 1974 1975 $expected = $keywords; 1976 $expected['required'] = false; 1977 1978 register_rest_route( 1979 'test-ns/v1', 1980 '/test', 1981 array( 1982 'methods' => 'POST', 1983 'callback' => static function () { 1984 return new WP_REST_Response( 'test' ); 1985 }, 1986 'permission_callback' => '__return_true', 1987 'args' => array( 1988 'param' => $param, 1989 ), 1990 ) 1991 ); 1992 1993 $response = rest_do_request( new WP_REST_Request( 'OPTIONS', '/test-ns/v1/test' ) ); 1994 $args = $response->get_data()['endpoints'][0]['args']; 1995 1996 $this->assertSameSetsWithIndex( $expected, $args['param'] ); 1997 } 1998 1934 1999 public function _validate_as_integer_123( $value, $request, $key ) { 1935 2000 if ( ! is_int( $value ) ) { -
trunk/tests/qunit/fixtures/wp-api-generated.js
r49252 r49257 32 32 "args": { 33 33 "context": { 34 " required": false,35 " default": "view"34 "default": "view", 35 "required": false 36 36 } 37 37 } … … 54 54 "args": { 55 55 "validation": { 56 "required": false, 57 "default": "normal", 56 "type": "string", 58 57 "enum": [ 59 58 "require-all-validate", 60 59 "normal" 61 60 ], 62 "type": "string" 61 "default": "normal", 62 "required": false 63 63 }, 64 64 "requests": { 65 "required": true,66 65 "type": "array", 66 "maxItems": 25, 67 67 "items": { 68 68 "type": "object", … … 101 101 } 102 102 } 103 } 103 }, 104 "required": true 104 105 } 105 106 } … … 126 127 "args": { 127 128 "namespace": { 128 " required": false,129 " default": "oembed/1.0"129 "default": "oembed/1.0", 130 "required": false 130 131 }, 131 132 "context": { 132 " required": false,133 " default": "view"133 "default": "view", 134 "required": false 134 135 } 135 136 } … … 152 153 "args": { 153 154 "url": { 154 "required": true,155 155 "description": "The URL of the resource for which to fetch oEmbed data.", 156 "type": "string" 156 "type": "string", 157 "format": "uri", 158 "required": true 157 159 }, 158 160 "format": { 159 " required": false,160 " default": "json"161 "default": "json", 162 "required": false 161 163 }, 162 164 "maxwidth": { 163 " required": false,164 " default": 600165 "default": 600, 166 "required": false 165 167 } 166 168 } … … 183 185 "args": { 184 186 "url": { 185 "required": true,186 187 "description": "The URL of the resource for which to fetch oEmbed data.", 187 "type": "string" 188 "type": "string", 189 "format": "uri", 190 "required": true 188 191 }, 189 192 "format": { 190 "required": false, 193 "description": "The oEmbed format to use.", 194 "type": "string", 191 195 "default": "json", 192 196 "enum": [ … … 194 198 "xml" 195 199 ], 196 "description": "The oEmbed format to use.", 197 "type": "string" 200 "required": false 198 201 }, 199 202 "maxwidth": { 200 "required": false, 203 "description": "The maximum width of the embed frame in pixels.", 204 "type": "integer", 201 205 "default": 600, 202 "description": "The maximum width of the embed frame in pixels.", 203 "type": "integer" 206 "required": false 204 207 }, 205 208 "maxheight": { 206 "required": false,207 209 "description": "The maximum height of the embed frame in pixels.", 208 "type": "integer" 210 "type": "integer", 211 "required": false 209 212 }, 210 213 "discover": { 211 "required": false, 214 "description": "Whether to perform an oEmbed discovery request for unsanctioned providers.", 215 "type": "boolean", 212 216 "default": true, 213 "description": "Whether to perform an oEmbed discovery request for unsanctioned providers.", 214 "type": "boolean" 217 "required": false 215 218 } 216 219 } … … 233 236 "args": { 234 237 "namespace": { 235 " required": false,236 " default": "wp/v2"238 "default": "wp/v2", 239 "required": false 237 240 }, 238 241 "context": { 239 " required": false,240 " default": "view"242 "default": "view", 243 "required": false 241 244 } 242 245 } … … 260 263 "args": { 261 264 "context": { 262 " required": false,263 " default": "view",265 "description": "Scope under which the request is made; determines fields present in response.", 266 "type": "string", 264 267 "enum": [ 265 268 "view", … … 267 270 "edit" 268 271 ], 269 "de scription": "Scope under which the request is made; determines fields present in response.",270 " type": "string"272 "default": "view", 273 "required": false 271 274 }, 272 275 "page": { 273 "required": false, 276 "description": "Current page of the collection.", 277 "type": "integer", 274 278 "default": 1, 275 " description": "Current page of the collection.",276 " type": "integer"279 "minimum": 1, 280 "required": false 277 281 }, 278 282 "per_page": { 279 "required": false, 283 "description": "Maximum number of items to be returned in result set.", 284 "type": "integer", 280 285 "default": 10, 281 "description": "Maximum number of items to be returned in result set.", 282 "type": "integer" 286 "minimum": 1, 287 "maximum": 100, 288 "required": false 283 289 }, 284 290 "search": { 285 "required": false,286 291 "description": "Limit results to those matching a string.", 287 "type": "string" 292 "type": "string", 293 "required": false 288 294 }, 289 295 "after": { 290 "required": false,291 296 "description": "Limit response to posts published after a given ISO8601 compliant date.", 292 "type": "string" 297 "type": "string", 298 "format": "date-time", 299 "required": false 293 300 }, 294 301 "author": { 295 "required": false,296 "default": [],297 302 "description": "Limit result set to posts assigned to specific authors.", 298 303 "type": "array", 299 304 "items": { 300 305 "type": "integer" 301 } 306 }, 307 "default": [], 308 "required": false 302 309 }, 303 310 "author_exclude": { 304 "required": false,305 "default": [],306 311 "description": "Ensure result set excludes posts assigned to specific authors.", 307 312 "type": "array", 308 313 "items": { 309 314 "type": "integer" 310 } 315 }, 316 "default": [], 317 "required": false 311 318 }, 312 319 "before": { 313 "required": false,314 320 "description": "Limit response to posts published before a given ISO8601 compliant date.", 315 "type": "string" 321 "type": "string", 322 "format": "date-time", 323 "required": false 316 324 }, 317 325 "exclude": { 318 "required": false,319 "default": [],320 326 "description": "Ensure result set excludes specific IDs.", 321 327 "type": "array", 322 328 "items": { 323 329 "type": "integer" 324 } 330 }, 331 "default": [], 332 "required": false 325 333 }, 326 334 "include": { 327 "required": false,328 "default": [],329 335 "description": "Limit result set to specific IDs.", 330 336 "type": "array", 331 337 "items": { 332 338 "type": "integer" 333 } 339 }, 340 "default": [], 341 "required": false 334 342 }, 335 343 "offset": { 336 "required": false,337 344 "description": "Offset the result set by a specific number of items.", 338 "type": "integer" 345 "type": "integer", 346 "required": false 339 347 }, 340 348 "order": { 341 "required": false, 349 "description": "Order sort attribute ascending or descending.", 350 "type": "string", 342 351 "default": "desc", 343 352 "enum": [ … … 345 354 "desc" 346 355 ], 347 "description": "Order sort attribute ascending or descending.", 348 "type": "string" 356 "required": false 349 357 }, 350 358 "orderby": { 351 "required": false, 359 "description": "Sort collection by object attribute.", 360 "type": "string", 352 361 "default": "date", 353 362 "enum": [ … … 363 372 "title" 364 373 ], 365 "description": "Sort collection by object attribute.", 366 "type": "string" 374 "required": false 367 375 }, 368 376 "slug": { 369 "required": false,370 377 "description": "Limit result set to posts with one or more specific slugs.", 371 378 "type": "array", 372 379 "items": { 373 380 "type": "string" 374 } 381 }, 382 "required": false 375 383 }, 376 384 "status": { 377 "required": false,378 385 "default": "publish", 379 386 "description": "Limit result set to posts assigned one or more statuses.", … … 396 403 ], 397 404 "type": "string" 398 } 405 }, 406 "required": false 399 407 }, 400 408 "tax_relation": { 401 "required": false, 409 "description": "Limit result set based on relationship between multiple taxonomies.", 410 "type": "string", 402 411 "enum": [ 403 412 "AND", 404 413 "OR" 405 414 ], 406 "description": "Limit result set based on relationship between multiple taxonomies.", 407 "type": "string" 415 "required": false 408 416 }, 409 417 "categories": { 410 "required": false,411 "default": [],412 418 "description": "Limit result set to all items that have the specified term assigned in the categories taxonomy.", 413 419 "type": "array", 414 420 "items": { 415 421 "type": "integer" 416 } 422 }, 423 "default": [], 424 "required": false 417 425 }, 418 426 "categories_exclude": { 419 "required": false,420 "default": [],421 427 "description": "Limit result set to all items except those that have the specified term assigned in the categories taxonomy.", 422 428 "type": "array", 423 429 "items": { 424 430 "type": "integer" 425 } 431 }, 432 "default": [], 433 "required": false 426 434 }, 427 435 "tags": { 428 "required": false,429 "default": [],430 436 "description": "Limit result set to all items that have the specified term assigned in the tags taxonomy.", 431 437 "type": "array", 432 438 "items": { 433 439 "type": "integer" 434 } 440 }, 441 "default": [], 442 "required": false 435 443 }, 436 444 "tags_exclude": { 437 "required": false,438 "default": [],439 445 "description": "Limit result set to all items except those that have the specified term assigned in the tags taxonomy.", 440 446 "type": "array", 441 447 "items": { 442 448 "type": "integer" 443 } 449 }, 450 "default": [], 451 "required": false 444 452 }, 445 453 "sticky": { 446 "required": false,447 454 "description": "Limit result set to items that are sticky.", 448 "type": "boolean" 455 "type": "boolean", 456 "required": false 449 457 } 450 458 } … … 456 464 "args": { 457 465 "date": { 458 "required": false,459 466 "description": "The date the object was published, in the site's timezone.", 460 467 "type": [ 461 468 "string", 462 469 "null" 463 ] 470 ], 471 "format": "date-time", 472 "required": false 464 473 }, 465 474 "date_gmt": { 466 "required": false,467 475 "description": "The date the object was published, as GMT.", 468 476 "type": [ 469 477 "string", 470 478 "null" 471 ] 479 ], 480 "format": "date-time", 481 "required": false 472 482 }, 473 483 "slug": { 474 "required": false,475 484 "description": "An alphanumeric identifier for the object unique to its type.", 476 "type": "string" 485 "type": "string", 486 "required": false 477 487 }, 478 488 "status": { 479 "required": false, 489 "description": "A named status for the object.", 490 "type": "string", 480 491 "enum": [ 481 492 "publish", … … 485 496 "private" 486 497 ], 487 "description": "A named status for the object.", 488 "type": "string" 498 "required": false 489 499 }, 490 500 "password": { 491 "required": false,492 501 "description": "A password to protect access to the content and excerpt.", 493 "type": "string" 502 "type": "string", 503 "required": false 494 504 }, 495 505 "title": { 496 "required": false,497 506 "description": "The title for the object.", 498 "type": "object" 507 "type": "object", 508 "properties": { 509 "raw": { 510 "description": "Title for the object, as it exists in the database.", 511 "type": "string", 512 "context": [ 513 "edit" 514 ] 515 }, 516 "rendered": { 517 "description": "HTML title for the object, transformed for display.", 518 "type": "string", 519 "context": [ 520 "view", 521 "edit", 522 "embed" 523 ], 524 "readonly": true 525 } 526 }, 527 "required": false 499 528 }, 500 529 "content": { 501 "required": false,502 530 "description": "The content for the object.", 503 "type": "object" 531 "type": "object", 532 "properties": { 533 "raw": { 534 "description": "Content for the object, as it exists in the database.", 535 "type": "string", 536 "context": [ 537 "edit" 538 ] 539 }, 540 "rendered": { 541 "description": "HTML content for the object, transformed for display.", 542 "type": "string", 543 "context": [ 544 "view", 545 "edit" 546 ], 547 "readonly": true 548 }, 549 "block_version": { 550 "description": "Version of the content block format used by the object.", 551 "type": "integer", 552 "context": [ 553 "edit" 554 ], 555 "readonly": true 556 }, 557 "protected": { 558 "description": "Whether the content is protected with a password.", 559 "type": "boolean", 560 "context": [ 561 "view", 562 "edit", 563 "embed" 564 ], 565 "readonly": true 566 } 567 }, 568 "required": false 504 569 }, 505 570 "author": { 506 "required": false,507 571 "description": "The ID for the author of the object.", 508 "type": "integer" 572 "type": "integer", 573 "required": false 509 574 }, 510 575 "excerpt": { 511 "required": false,512 576 "description": "The excerpt for the object.", 513 "type": "object" 577 "type": "object", 578 "properties": { 579 "raw": { 580 "description": "Excerpt for the object, as it exists in the database.", 581 "type": "string", 582 "context": [ 583 "edit" 584 ] 585 }, 586 "rendered": { 587 "description": "HTML excerpt for the object, transformed for display.", 588 "type": "string", 589 "context": [ 590 "view", 591 "edit", 592 "embed" 593 ], 594 "readonly": true 595 }, 596 "protected": { 597 "description": "Whether the excerpt is protected with a password.", 598 "type": "boolean", 599 "context": [ 600 "view", 601 "edit", 602 "embed" 603 ], 604 "readonly": true 605 } 606 }, 607 "required": false 514 608 }, 515 609 "featured_media": { 516 "required": false,517 610 "description": "The ID of the featured media for the object.", 518 "type": "integer" 611 "type": "integer", 612 "required": false 519 613 }, 520 614 "comment_status": { 521 "required": false, 615 "description": "Whether or not comments are open on the object.", 616 "type": "string", 522 617 "enum": [ 523 618 "open", 524 619 "closed" 525 620 ], 526 "description": "Whether or not comments are open on the object.", 527 "type": "string" 621 "required": false 528 622 }, 529 623 "ping_status": { 530 "required": false, 624 "description": "Whether or not the object can be pinged.", 625 "type": "string", 531 626 "enum": [ 532 627 "open", 533 628 "closed" 534 629 ], 535 "description": "Whether or not the object can be pinged.", 536 "type": "string" 630 "required": false 537 631 }, 538 632 "format": { 539 "required": false, 633 "description": "The format for the object.", 634 "type": "string", 540 635 "enum": [ 541 636 "standard", … … 550 645 "audio" 551 646 ], 552 "description": "The format for the object.", 553 "type": "string" 647 "required": false 554 648 }, 555 649 "meta": { 556 "required": false,557 650 "description": "Meta fields.", 558 "type": "object" 651 "type": "object", 652 "properties": [], 653 "required": false 559 654 }, 560 655 "sticky": { 561 "required": false,562 656 "description": "Whether or not the object should be treated as sticky.", 563 "type": "boolean" 657 "type": "boolean", 658 "required": false 564 659 }, 565 660 "template": { 566 "required": false,567 661 "description": "The theme file to use to display the object.", 568 "type": "string" 662 "type": "string", 663 "required": false 569 664 }, 570 665 "categories": { 571 "required": false,572 666 "description": "The terms assigned to the object in the category taxonomy.", 573 667 "type": "array", 574 668 "items": { 575 669 "type": "integer" 576 } 670 }, 671 "required": false 577 672 }, 578 673 "tags": { 579 "required": false,580 674 "description": "The terms assigned to the object in the post_tag taxonomy.", 581 675 "type": "array", 582 676 "items": { 583 677 "type": "integer" 584 } 678 }, 679 "required": false 585 680 } 586 681 } … … 607 702 "args": { 608 703 "id": { 609 "required": false,610 704 "description": "Unique identifier for the object.", 611 "type": "integer" 705 "type": "integer", 706 "required": false 612 707 }, 613 708 "context": { 614 " required": false,615 " default": "view",709 "description": "Scope under which the request is made; determines fields present in response.", 710 "type": "string", 616 711 "enum": [ 617 712 "view", … … 619 714 "edit" 620 715 ], 621 "de scription": "Scope under which the request is made; determines fields present in response.",622 " type": "string"716 "default": "view", 717 "required": false 623 718 }, 624 719 "password": { 625 "required": false,626 720 "description": "The password for the post if it is password protected.", 627 "type": "string" 721 "type": "string", 722 "required": false 628 723 } 629 724 } … … 637 732 "args": { 638 733 "id": { 639 "required": false,640 734 "description": "Unique identifier for the object.", 641 "type": "integer" 735 "type": "integer", 736 "required": false 642 737 }, 643 738 "date": { 644 "required": false,645 739 "description": "The date the object was published, in the site's timezone.", 646 740 "type": [ 647 741 "string", 648 742 "null" 649 ] 743 ], 744 "format": "date-time", 745 "required": false 650 746 }, 651 747 "date_gmt": { 652 "required": false,653 748 "description": "The date the object was published, as GMT.", 654 749 "type": [ 655 750 "string", 656 751 "null" 657 ] 752 ], 753 "format": "date-time", 754 "required": false 658 755 }, 659 756 "slug": { 660 "required": false,661 757 "description": "An alphanumeric identifier for the object unique to its type.", 662 "type": "string" 758 "type": "string", 759 "required": false 663 760 }, 664 761 "status": { 665 "required": false, 762 "description": "A named status for the object.", 763 "type": "string", 666 764 "enum": [ 667 765 "publish", … … 671 769 "private" 672 770 ], 673 "description": "A named status for the object.", 674 "type": "string" 771 "required": false 675 772 }, 676 773 "password": { 677 "required": false,678 774 "description": "A password to protect access to the content and excerpt.", 679 "type": "string" 775 "type": "string", 776 "required": false 680 777 }, 681 778 "title": { 682 "required": false,683 779 "description": "The title for the object.", 684 "type": "object" 780 "type": "object", 781 "properties": { 782 "raw": { 783 "description": "Title for the object, as it exists in the database.", 784 "type": "string", 785 "context": [ 786 "edit" 787 ] 788 }, 789 "rendered": { 790 "description": "HTML title for the object, transformed for display.", 791 "type": "string", 792 "context": [ 793 "view", 794 "edit", 795 "embed" 796 ], 797 "readonly": true 798 } 799 }, 800 "required": false 685 801 }, 686 802 "content": { 687 "required": false,688 803 "description": "The content for the object.", 689 "type": "object" 804 "type": "object", 805 "properties": { 806 "raw": { 807 "description": "Content for the object, as it exists in the database.", 808 "type": "string", 809 "context": [ 810 "edit" 811 ] 812 }, 813 "rendered": { 814 "description": "HTML content for the object, transformed for display.", 815 "type": "string", 816 "context": [ 817 "view", 818 "edit" 819 ], 820 "readonly": true 821 }, 822 "block_version": { 823 "description": "Version of the content block format used by the object.", 824 "type": "integer", 825 "context": [ 826 "edit" 827 ], 828 "readonly": true 829 }, 830 "protected": { 831 "description": "Whether the content is protected with a password.", 832 "type": "boolean", 833 "context": [ 834 "view", 835 "edit", 836 "embed" 837 ], 838 "readonly": true 839 } 840 }, 841 "required": false 690 842 }, 691 843 "author": { 692 "required": false,693 844 "description": "The ID for the author of the object.", 694 "type": "integer" 845 "type": "integer", 846 "required": false 695 847 }, 696 848 "excerpt": { 697 "required": false,698 849 "description": "The excerpt for the object.", 699 "type": "object" 850 "type": "object", 851 "properties": { 852 "raw": { 853 "description": "Excerpt for the object, as it exists in the database.", 854 "type": "string", 855 "context": [ 856 "edit" 857 ] 858 }, 859 "rendered": { 860 "description": "HTML excerpt for the object, transformed for display.", 861 "type": "string", 862 "context": [ 863 "view", 864 "edit", 865 "embed" 866 ], 867 "readonly": true 868 }, 869 "protected": { 870 "description": "Whether the excerpt is protected with a password.", 871 "type": "boolean", 872 "context": [ 873 "view", 874 "edit", 875 "embed" 876 ], 877 "readonly": true 878 } 879 }, 880 "required": false 700 881 }, 701 882 "featured_media": { 702 "required": false,703 883 "description": "The ID of the featured media for the object.", 704 "type": "integer" 884 "type": "integer", 885 "required": false 705 886 }, 706 887 "comment_status": { 707 "required": false, 888 "description": "Whether or not comments are open on the object.", 889 "type": "string", 708 890 "enum": [ 709 891 "open", 710 892 "closed" 711 893 ], 712 "description": "Whether or not comments are open on the object.", 713 "type": "string" 894 "required": false 714 895 }, 715 896 "ping_status": { 716 "required": false, 897 "description": "Whether or not the object can be pinged.", 898 "type": "string", 717 899 "enum": [ 718 900 "open", 719 901 "closed" 720 902 ], 721 "description": "Whether or not the object can be pinged.", 722 "type": "string" 903 "required": false 723 904 }, 724 905 "format": { 725 "required": false, 906 "description": "The format for the object.", 907 "type": "string", 726 908 "enum": [ 727 909 "standard", … … 736 918 "audio" 737 919 ], 738 "description": "The format for the object.", 739 "type": "string" 920 "required": false 740 921 }, 741 922 "meta": { 742 "required": false,743 923 "description": "Meta fields.", 744 "type": "object" 924 "type": "object", 925 "properties": [], 926 "required": false 745 927 }, 746 928 "sticky": { 747 "required": false,748 929 "description": "Whether or not the object should be treated as sticky.", 749 "type": "boolean" 930 "type": "boolean", 931 "required": false 750 932 }, 751 933 "template": { 752 "required": false,753 934 "description": "The theme file to use to display the object.", 754 "type": "string" 935 "type": "string", 936 "required": false 755 937 }, 756 938 "categories": { 757 "required": false,758 939 "description": "The terms assigned to the object in the category taxonomy.", 759 940 "type": "array", 760 941 "items": { 761 942 "type": "integer" 762 } 943 }, 944 "required": false 763 945 }, 764 946 "tags": { 765 "required": false,766 947 "description": "The terms assigned to the object in the post_tag taxonomy.", 767 948 "type": "array", 768 949 "items": { 769 950 "type": "integer" 770 } 951 }, 952 "required": false 771 953 } 772 954 } … … 778 960 "args": { 779 961 "id": { 780 "required": false,781 962 "description": "Unique identifier for the object.", 782 "type": "integer" 963 "type": "integer", 964 "required": false 783 965 }, 784 966 "force": { 785 " required": false,967 "type": "boolean", 786 968 "default": false, 787 969 "description": "Whether to bypass Trash and force deletion.", 788 " type": "boolean"970 "required": false 789 971 } 790 972 } … … 804 986 "args": { 805 987 "parent": { 806 "required": false,807 988 "description": "The ID for the parent of the object.", 808 "type": "integer" 989 "type": "integer", 990 "required": false 809 991 }, 810 992 "context": { 811 " required": false,812 " default": "view",993 "description": "Scope under which the request is made; determines fields present in response.", 994 "type": "string", 813 995 "enum": [ 814 996 "view", … … 816 998 "edit" 817 999 ], 818 "de scription": "Scope under which the request is made; determines fields present in response.",819 " type": "string"1000 "default": "view", 1001 "required": false 820 1002 }, 821 1003 "page": { 822 "required": false, 1004 "description": "Current page of the collection.", 1005 "type": "integer", 823 1006 "default": 1, 824 " description": "Current page of the collection.",825 " type": "integer"1007 "minimum": 1, 1008 "required": false 826 1009 }, 827 1010 "per_page": { 828 "required": false,829 1011 "description": "Maximum number of items to be returned in result set.", 830 "type": "integer" 1012 "type": "integer", 1013 "minimum": 1, 1014 "maximum": 100, 1015 "required": false 831 1016 }, 832 1017 "search": { 833 "required": false,834 1018 "description": "Limit results to those matching a string.", 835 "type": "string" 1019 "type": "string", 1020 "required": false 836 1021 }, 837 1022 "exclude": { 838 "required": false,839 "default": [],840 1023 "description": "Ensure result set excludes specific IDs.", 841 1024 "type": "array", 842 1025 "items": { 843 1026 "type": "integer" 844 } 1027 }, 1028 "default": [], 1029 "required": false 845 1030 }, 846 1031 "include": { 847 "required": false,848 "default": [],849 1032 "description": "Limit result set to specific IDs.", 850 1033 "type": "array", 851 1034 "items": { 852 1035 "type": "integer" 853 } 1036 }, 1037 "default": [], 1038 "required": false 854 1039 }, 855 1040 "offset": { 856 "required": false,857 1041 "description": "Offset the result set by a specific number of items.", 858 "type": "integer" 1042 "type": "integer", 1043 "required": false 859 1044 }, 860 1045 "order": { 861 "required": false, 1046 "description": "Order sort attribute ascending or descending.", 1047 "type": "string", 862 1048 "default": "desc", 863 1049 "enum": [ … … 865 1051 "desc" 866 1052 ], 867 "description": "Order sort attribute ascending or descending.", 868 "type": "string" 1053 "required": false 869 1054 }, 870 1055 "orderby": { 871 "required": false, 1056 "description": "Sort collection by object attribute.", 1057 "type": "string", 872 1058 "default": "date", 873 1059 "enum": [ … … 880 1066 "title" 881 1067 ], 882 "description": "Sort collection by object attribute.", 883 "type": "string" 1068 "required": false 884 1069 } 885 1070 } … … 900 1085 "args": { 901 1086 "parent": { 902 "required": false,903 1087 "description": "The ID for the parent of the object.", 904 "type": "integer" 1088 "type": "integer", 1089 "required": false 905 1090 }, 906 1091 "id": { 907 "required": false,908 1092 "description": "Unique identifier for the object.", 909 "type": "integer" 1093 "type": "integer", 1094 "required": false 910 1095 }, 911 1096 "context": { 912 " required": false,913 " default": "view",1097 "description": "Scope under which the request is made; determines fields present in response.", 1098 "type": "string", 914 1099 "enum": [ 915 1100 "view", … … 917 1102 "edit" 918 1103 ], 919 "de scription": "Scope under which the request is made; determines fields present in response.",920 " type": "string"1104 "default": "view", 1105 "required": false 921 1106 } 922 1107 } … … 928 1113 "args": { 929 1114 "parent": { 930 "required": false,931 1115 "description": "The ID for the parent of the object.", 932 "type": "integer" 1116 "type": "integer", 1117 "required": false 933 1118 }, 934 1119 "id": { 935 "required": false,936 1120 "description": "Unique identifier for the object.", 937 "type": "integer" 1121 "type": "integer", 1122 "required": false 938 1123 }, 939 1124 "force": { 940 " required": false,1125 "type": "boolean", 941 1126 "default": false, 942 1127 "description": "Required to be true, as revisions do not support trashing.", 943 " type": "boolean"1128 "required": false 944 1129 } 945 1130 } … … 960 1145 "args": { 961 1146 "parent": { 962 "required": false,963 1147 "description": "The ID for the parent of the object.", 964 "type": "integer" 1148 "type": "integer", 1149 "required": false 965 1150 }, 966 1151 "context": { 967 " required": false,968 " default": "view",1152 "description": "Scope under which the request is made; determines fields present in response.", 1153 "type": "string", 969 1154 "enum": [ 970 1155 "view", … … 972 1157 "edit" 973 1158 ], 974 "de scription": "Scope under which the request is made; determines fields present in response.",975 " type": "string"1159 "default": "view", 1160 "required": false 976 1161 } 977 1162 } … … 983 1168 "args": { 984 1169 "parent": { 985 "required": false,986 1170 "description": "The ID for the parent of the object.", 987 "type": "integer" 1171 "type": "integer", 1172 "required": false 988 1173 }, 989 1174 "date": { 990 "required": false,991 1175 "description": "The date the object was published, in the site's timezone.", 992 1176 "type": [ 993 1177 "string", 994 1178 "null" 995 ] 1179 ], 1180 "format": "date-time", 1181 "required": false 996 1182 }, 997 1183 "date_gmt": { 998 "required": false,999 1184 "description": "The date the object was published, as GMT.", 1000 1185 "type": [ 1001 1186 "string", 1002 1187 "null" 1003 ] 1188 ], 1189 "format": "date-time", 1190 "required": false 1004 1191 }, 1005 1192 "slug": { 1006 "required": false,1007 1193 "description": "An alphanumeric identifier for the object unique to its type.", 1008 "type": "string" 1194 "type": "string", 1195 "required": false 1009 1196 }, 1010 1197 "status": { 1011 "required": false, 1198 "description": "A named status for the object.", 1199 "type": "string", 1012 1200 "enum": [ 1013 1201 "publish", … … 1017 1205 "private" 1018 1206 ], 1019 "description": "A named status for the object.", 1020 "type": "string" 1207 "required": false 1021 1208 }, 1022 1209 "password": { 1023 "required": false,1024 1210 "description": "A password to protect access to the content and excerpt.", 1025 "type": "string" 1211 "type": "string", 1212 "required": false 1026 1213 }, 1027 1214 "title": { 1028 "required": false,1029 1215 "description": "The title for the object.", 1030 "type": "object" 1216 "type": "object", 1217 "properties": { 1218 "raw": { 1219 "description": "Title for the object, as it exists in the database.", 1220 "type": "string", 1221 "context": [ 1222 "edit" 1223 ] 1224 }, 1225 "rendered": { 1226 "description": "HTML title for the object, transformed for display.", 1227 "type": "string", 1228 "context": [ 1229 "view", 1230 "edit", 1231 "embed" 1232 ], 1233 "readonly": true 1234 } 1235 }, 1236 "required": false 1031 1237 }, 1032 1238 "content": { 1033 "required": false,1034 1239 "description": "The content for the object.", 1035 "type": "object" 1240 "type": "object", 1241 "properties": { 1242 "raw": { 1243 "description": "Content for the object, as it exists in the database.", 1244 "type": "string", 1245 "context": [ 1246 "edit" 1247 ] 1248 }, 1249 "rendered": { 1250 "description": "HTML content for the object, transformed for display.", 1251 "type": "string", 1252 "context": [ 1253 "view", 1254 "edit" 1255 ], 1256 "readonly": true 1257 }, 1258 "block_version": { 1259 "description": "Version of the content block format used by the object.", 1260 "type": "integer", 1261 "context": [ 1262 "edit" 1263 ], 1264 "readonly": true 1265 }, 1266 "protected": { 1267 "description": "Whether the content is protected with a password.", 1268 "type": "boolean", 1269 "context": [ 1270 "view", 1271 "edit", 1272 "embed" 1273 ], 1274 "readonly": true 1275 } 1276 }, 1277 "required": false 1036 1278 }, 1037 1279 "author": { 1038 "required": false,1039 1280 "description": "The ID for the author of the object.", 1040 "type": "integer" 1281 "type": "integer", 1282 "required": false 1041 1283 }, 1042 1284 "excerpt": { 1043 "required": false,1044 1285 "description": "The excerpt for the object.", 1045 "type": "object" 1286 "type": "object", 1287 "properties": { 1288 "raw": { 1289 "description": "Excerpt for the object, as it exists in the database.", 1290 "type": "string", 1291 "context": [ 1292 "edit" 1293 ] 1294 }, 1295 "rendered": { 1296 "description": "HTML excerpt for the object, transformed for display.", 1297 "type": "string", 1298 "context": [ 1299 "view", 1300 "edit", 1301 "embed" 1302 ], 1303 "readonly": true 1304 }, 1305 "protected": { 1306 "description": "Whether the excerpt is protected with a password.", 1307 "type": "boolean", 1308 "context": [ 1309 "view", 1310 "edit", 1311 "embed" 1312 ], 1313 "readonly": true 1314 } 1315 }, 1316 "required": false 1046 1317 }, 1047 1318 "featured_media": { 1048 "required": false,1049 1319 "description": "The ID of the featured media for the object.", 1050 "type": "integer" 1320 "type": "integer", 1321 "required": false 1051 1322 }, 1052 1323 "comment_status": { 1053 "required": false, 1324 "description": "Whether or not comments are open on the object.", 1325 "type": "string", 1054 1326 "enum": [ 1055 1327 "open", 1056 1328 "closed" 1057 1329 ], 1058 "description": "Whether or not comments are open on the object.", 1059 "type": "string" 1330 "required": false 1060 1331 }, 1061 1332 "ping_status": { 1062 "required": false, 1333 "description": "Whether or not the object can be pinged.", 1334 "type": "string", 1063 1335 "enum": [ 1064 1336 "open", 1065 1337 "closed" 1066 1338 ], 1067 "description": "Whether or not the object can be pinged.", 1068 "type": "string" 1339 "required": false 1069 1340 }, 1070 1341 "format": { 1071 "required": false, 1342 "description": "The format for the object.", 1343 "type": "string", 1072 1344 "enum": [ 1073 1345 "standard", … … 1082 1354 "audio" 1083 1355 ], 1084 "description": "The format for the object.", 1085 "type": "string" 1356 "required": false 1086 1357 }, 1087 1358 "meta": { 1088 "required": false,1089 1359 "description": "Meta fields.", 1090 "type": "object" 1360 "type": "object", 1361 "properties": [], 1362 "required": false 1091 1363 }, 1092 1364 "sticky": { 1093 "required": false,1094 1365 "description": "Whether or not the object should be treated as sticky.", 1095 "type": "boolean" 1366 "type": "boolean", 1367 "required": false 1096 1368 }, 1097 1369 "template": { 1098 "required": false,1099 1370 "description": "The theme file to use to display the object.", 1100 "type": "string" 1371 "type": "string", 1372 "required": false 1101 1373 }, 1102 1374 "categories": { 1103 "required": false,1104 1375 "description": "The terms assigned to the object in the category taxonomy.", 1105 1376 "type": "array", 1106 1377 "items": { 1107 1378 "type": "integer" 1108 } 1379 }, 1380 "required": false 1109 1381 }, 1110 1382 "tags": { 1111 "required": false,1112 1383 "description": "The terms assigned to the object in the post_tag taxonomy.", 1113 1384 "type": "array", 1114 1385 "items": { 1115 1386 "type": "integer" 1116 } 1387 }, 1388 "required": false 1117 1389 } 1118 1390 } … … 1132 1404 "args": { 1133 1405 "parent": { 1134 "required": false,1135 1406 "description": "The ID for the parent of the object.", 1136 "type": "integer" 1407 "type": "integer", 1408 "required": false 1137 1409 }, 1138 1410 "id": { 1139 "required": false,1140 1411 "description": "The ID for the object.", 1141 "type": "integer" 1412 "type": "integer", 1413 "required": false 1142 1414 }, 1143 1415 "context": { 1144 " required": false,1145 " default": "view",1416 "description": "Scope under which the request is made; determines fields present in response.", 1417 "type": "string", 1146 1418 "enum": [ 1147 1419 "view", … … 1149 1421 "edit" 1150 1422 ], 1151 "de scription": "Scope under which the request is made; determines fields present in response.",1152 " type": "string"1423 "default": "view", 1424 "required": false 1153 1425 } 1154 1426 } … … 1169 1441 "args": { 1170 1442 "context": { 1171 " required": false,1172 " default": "view",1443 "description": "Scope under which the request is made; determines fields present in response.", 1444 "type": "string", 1173 1445 "enum": [ 1174 1446 "view", … … 1176 1448 "edit" 1177 1449 ], 1178 "de scription": "Scope under which the request is made; determines fields present in response.",1179 " type": "string"1450 "default": "view", 1451 "required": false 1180 1452 }, 1181 1453 "page": { 1182 "required": false, 1454 "description": "Current page of the collection.", 1455 "type": "integer", 1183 1456 "default": 1, 1184 " description": "Current page of the collection.",1185 " type": "integer"1457 "minimum": 1, 1458 "required": false 1186 1459 }, 1187 1460 "per_page": { 1188 "required": false, 1461 "description": "Maximum number of items to be returned in result set.", 1462 "type": "integer", 1189 1463 "default": 10, 1190 "description": "Maximum number of items to be returned in result set.", 1191 "type": "integer" 1464 "minimum": 1, 1465 "maximum": 100, 1466 "required": false 1192 1467 }, 1193 1468 "search": { 1194 "required": false,1195 1469 "description": "Limit results to those matching a string.", 1196 "type": "string" 1470 "type": "string", 1471 "required": false 1197 1472 }, 1198 1473 "after": { 1199 "required": false,1200 1474 "description": "Limit response to posts published after a given ISO8601 compliant date.", 1201 "type": "string" 1475 "type": "string", 1476 "format": "date-time", 1477 "required": false 1202 1478 }, 1203 1479 "author": { 1204 "required": false,1205 "default": [],1206 1480 "description": "Limit result set to posts assigned to specific authors.", 1207 1481 "type": "array", 1208 1482 "items": { 1209 1483 "type": "integer" 1210 } 1484 }, 1485 "default": [], 1486 "required": false 1211 1487 }, 1212 1488 "author_exclude": { 1213 "required": false,1214 "default": [],1215 1489 "description": "Ensure result set excludes posts assigned to specific authors.", 1216 1490 "type": "array", 1217 1491 "items": { 1218 1492 "type": "integer" 1219 } 1493 }, 1494 "default": [], 1495 "required": false 1220 1496 }, 1221 1497 "before": { 1222 "required": false,1223 1498 "description": "Limit response to posts published before a given ISO8601 compliant date.", 1224 "type": "string" 1499 "type": "string", 1500 "format": "date-time", 1501 "required": false 1225 1502 }, 1226 1503 "exclude": { 1227 "required": false,1228 "default": [],1229 1504 "description": "Ensure result set excludes specific IDs.", 1230 1505 "type": "array", 1231 1506 "items": { 1232 1507 "type": "integer" 1233 } 1508 }, 1509 "default": [], 1510 "required": false 1234 1511 }, 1235 1512 "include": { 1236 "required": false,1237 "default": [],1238 1513 "description": "Limit result set to specific IDs.", 1239 1514 "type": "array", 1240 1515 "items": { 1241 1516 "type": "integer" 1242 } 1517 }, 1518 "default": [], 1519 "required": false 1243 1520 }, 1244 1521 "menu_order": { 1245 "required": false,1246 1522 "description": "Limit result set to posts with a specific menu_order value.", 1247 "type": "integer" 1523 "type": "integer", 1524 "required": false 1248 1525 }, 1249 1526 "offset": { 1250 "required": false,1251 1527 "description": "Offset the result set by a specific number of items.", 1252 "type": "integer" 1528 "type": "integer", 1529 "required": false 1253 1530 }, 1254 1531 "order": { 1255 "required": false, 1532 "description": "Order sort attribute ascending or descending.", 1533 "type": "string", 1256 1534 "default": "desc", 1257 1535 "enum": [ … … 1259 1537 "desc" 1260 1538 ], 1261 "description": "Order sort attribute ascending or descending.", 1262 "type": "string" 1539 "required": false 1263 1540 }, 1264 1541 "orderby": { 1265 "required": false, 1542 "description": "Sort collection by object attribute.", 1543 "type": "string", 1266 1544 "default": "date", 1267 1545 "enum": [ … … 1278 1556 "menu_order" 1279 1557 ], 1280 "description": "Sort collection by object attribute.", 1281 "type": "string" 1558 "required": false 1282 1559 }, 1283 1560 "parent": { 1284 "required": false,1285 "default": [],1286 1561 "description": "Limit result set to items with particular parent IDs.", 1287 1562 "type": "array", 1288 1563 "items": { 1289 1564 "type": "integer" 1290 } 1565 }, 1566 "default": [], 1567 "required": false 1291 1568 }, 1292 1569 "parent_exclude": { 1293 "required": false,1294 "default": [],1295 1570 "description": "Limit result set to all items except those of a particular parent ID.", 1296 1571 "type": "array", 1297 1572 "items": { 1298 1573 "type": "integer" 1299 } 1574 }, 1575 "default": [], 1576 "required": false 1300 1577 }, 1301 1578 "slug": { 1302 "required": false,1303 1579 "description": "Limit result set to posts with one or more specific slugs.", 1304 1580 "type": "array", 1305 1581 "items": { 1306 1582 "type": "string" 1307 } 1583 }, 1584 "required": false 1308 1585 }, 1309 1586 "status": { 1310 "required": false,1311 1587 "default": "publish", 1312 1588 "description": "Limit result set to posts assigned one or more statuses.", … … 1329 1605 ], 1330 1606 "type": "string" 1331 } 1607 }, 1608 "required": false 1332 1609 } 1333 1610 } … … 1339 1616 "args": { 1340 1617 "date": { 1341 "required": false,1342 1618 "description": "The date the object was published, in the site's timezone.", 1343 1619 "type": [ 1344 1620 "string", 1345 1621 "null" 1346 ] 1622 ], 1623 "format": "date-time", 1624 "required": false 1347 1625 }, 1348 1626 "date_gmt": { 1349 "required": false,1350 1627 "description": "The date the object was published, as GMT.", 1351 1628 "type": [ 1352 1629 "string", 1353 1630 "null" 1354 ] 1631 ], 1632 "format": "date-time", 1633 "required": false 1355 1634 }, 1356 1635 "slug": { 1357 "required": false,1358 1636 "description": "An alphanumeric identifier for the object unique to its type.", 1359 "type": "string" 1637 "type": "string", 1638 "required": false 1360 1639 }, 1361 1640 "status": { 1362 "required": false, 1641 "description": "A named status for the object.", 1642 "type": "string", 1363 1643 "enum": [ 1364 1644 "publish", … … 1368 1648 "private" 1369 1649 ], 1370 "description": "A named status for the object.", 1371 "type": "string" 1650 "required": false 1372 1651 }, 1373 1652 "password": { 1374 "required": false,1375 1653 "description": "A password to protect access to the content and excerpt.", 1376 "type": "string" 1654 "type": "string", 1655 "required": false 1377 1656 }, 1378 1657 "parent": { 1379 "required": false,1380 1658 "description": "The ID for the parent of the object.", 1381 "type": "integer" 1659 "type": "integer", 1660 "required": false 1382 1661 }, 1383 1662 "title": { 1384 "required": false,1385 1663 "description": "The title for the object.", 1386 "type": "object" 1664 "type": "object", 1665 "properties": { 1666 "raw": { 1667 "description": "Title for the object, as it exists in the database.", 1668 "type": "string", 1669 "context": [ 1670 "edit" 1671 ] 1672 }, 1673 "rendered": { 1674 "description": "HTML title for the object, transformed for display.", 1675 "type": "string", 1676 "context": [ 1677 "view", 1678 "edit", 1679 "embed" 1680 ], 1681 "readonly": true 1682 } 1683 }, 1684 "required": false 1387 1685 }, 1388 1686 "content": { 1389 "required": false,1390 1687 "description": "The content for the object.", 1391 "type": "object" 1688 "type": "object", 1689 "properties": { 1690 "raw": { 1691 "description": "Content for the object, as it exists in the database.", 1692 "type": "string", 1693 "context": [ 1694 "edit" 1695 ] 1696 }, 1697 "rendered": { 1698 "description": "HTML content for the object, transformed for display.", 1699 "type": "string", 1700 "context": [ 1701 "view", 1702 "edit" 1703 ], 1704 "readonly": true 1705 }, 1706 "block_version": { 1707 "description": "Version of the content block format used by the object.", 1708 "type": "integer", 1709 "context": [ 1710 "edit" 1711 ], 1712 "readonly": true 1713 }, 1714 "protected": { 1715 "description": "Whether the content is protected with a password.", 1716 "type": "boolean", 1717 "context": [ 1718 "view", 1719 "edit", 1720 "embed" 1721 ], 1722 "readonly": true 1723 } 1724 }, 1725 "required": false 1392 1726 }, 1393 1727 "author": { 1394 "required": false,1395 1728 "description": "The ID for the author of the object.", 1396 "type": "integer" 1729 "type": "integer", 1730 "required": false 1397 1731 }, 1398 1732 "excerpt": { 1399 "required": false,1400 1733 "description": "The excerpt for the object.", 1401 "type": "object" 1734 "type": "object", 1735 "properties": { 1736 "raw": { 1737 "description": "Excerpt for the object, as it exists in the database.", 1738 "type": "string", 1739 "context": [ 1740 "edit" 1741 ] 1742 }, 1743 "rendered": { 1744 "description": "HTML excerpt for the object, transformed for display.", 1745 "type": "string", 1746 "context": [ 1747 "view", 1748 "edit", 1749 "embed" 1750 ], 1751 "readonly": true 1752 }, 1753 "protected": { 1754 "description": "Whether the excerpt is protected with a password.", 1755 "type": "boolean", 1756 "context": [ 1757 "view", 1758 "edit", 1759 "embed" 1760 ], 1761 "readonly": true 1762 } 1763 }, 1764 "required": false 1402 1765 }, 1403 1766 "featured_media": { 1404 "required": false,1405 1767 "description": "The ID of the featured media for the object.", 1406 "type": "integer" 1768 "type": "integer", 1769 "required": false 1407 1770 }, 1408 1771 "comment_status": { 1409 "required": false, 1772 "description": "Whether or not comments are open on the object.", 1773 "type": "string", 1410 1774 "enum": [ 1411 1775 "open", 1412 1776 "closed" 1413 1777 ], 1414 "description": "Whether or not comments are open on the object.", 1415 "type": "string" 1778 "required": false 1416 1779 }, 1417 1780 "ping_status": { 1418 "required": false, 1781 "description": "Whether or not the object can be pinged.", 1782 "type": "string", 1419 1783 "enum": [ 1420 1784 "open", 1421 1785 "closed" 1422 1786 ], 1423 "description": "Whether or not the object can be pinged.", 1424 "type": "string" 1787 "required": false 1425 1788 }, 1426 1789 "menu_order": { 1427 "required": false,1428 1790 "description": "The order of the object in relation to other object of its type.", 1429 "type": "integer" 1791 "type": "integer", 1792 "required": false 1430 1793 }, 1431 1794 "meta": { 1432 "required": false,1433 1795 "description": "Meta fields.", 1434 "type": "object" 1796 "type": "object", 1797 "properties": [], 1798 "required": false 1435 1799 }, 1436 1800 "template": { 1437 "required": false,1438 1801 "description": "The theme file to use to display the object.", 1439 "type": "string" 1802 "type": "string", 1803 "required": false 1440 1804 } 1441 1805 } … … 1462 1826 "args": { 1463 1827 "id": { 1464 "required": false,1465 1828 "description": "Unique identifier for the object.", 1466 "type": "integer" 1829 "type": "integer", 1830 "required": false 1467 1831 }, 1468 1832 "context": { 1469 " required": false,1470 " default": "view",1833 "description": "Scope under which the request is made; determines fields present in response.", 1834 "type": "string", 1471 1835 "enum": [ 1472 1836 "view", … … 1474 1838 "edit" 1475 1839 ], 1476 "de scription": "Scope under which the request is made; determines fields present in response.",1477 " type": "string"1840 "default": "view", 1841 "required": false 1478 1842 }, 1479 1843 "password": { 1480 "required": false,1481 1844 "description": "The password for the post if it is password protected.", 1482 "type": "string" 1845 "type": "string", 1846 "required": false 1483 1847 } 1484 1848 } … … 1492 1856 "args": { 1493 1857 "id": { 1494 "required": false,1495 1858 "description": "Unique identifier for the object.", 1496 "type": "integer" 1859 "type": "integer", 1860 "required": false 1497 1861 }, 1498 1862 "date": { 1499 "required": false,1500 1863 "description": "The date the object was published, in the site's timezone.", 1501 1864 "type": [ 1502 1865 "string", 1503 1866 "null" 1504 ] 1867 ], 1868 "format": "date-time", 1869 "required": false 1505 1870 }, 1506 1871 "date_gmt": { 1507 "required": false,1508 1872 "description": "The date the object was published, as GMT.", 1509 1873 "type": [ 1510 1874 "string", 1511 1875 "null" 1512 ] 1876 ], 1877 "format": "date-time", 1878 "required": false 1513 1879 }, 1514 1880 "slug": { 1515 "required": false,1516 1881 "description": "An alphanumeric identifier for the object unique to its type.", 1517 "type": "string" 1882 "type": "string", 1883 "required": false 1518 1884 }, 1519 1885 "status": { 1520 "required": false, 1886 "description": "A named status for the object.", 1887 "type": "string", 1521 1888 "enum": [ 1522 1889 "publish", … … 1526 1893 "private" 1527 1894 ], 1528 "description": "A named status for the object.", 1529 "type": "string" 1895 "required": false 1530 1896 }, 1531 1897 "password": { 1532 "required": false,1533 1898 "description": "A password to protect access to the content and excerpt.", 1534 "type": "string" 1899 "type": "string", 1900 "required": false 1535 1901 }, 1536 1902 "parent": { 1537 "required": false,1538 1903 "description": "The ID for the parent of the object.", 1539 "type": "integer" 1904 "type": "integer", 1905 "required": false 1540 1906 }, 1541 1907 "title": { 1542 "required": false,1543 1908 "description": "The title for the object.", 1544 "type": "object" 1909 "type": "object", 1910 "properties": { 1911 "raw": { 1912 "description": "Title for the object, as it exists in the database.", 1913 "type": "string", 1914 "context": [ 1915 "edit" 1916 ] 1917 }, 1918 "rendered": { 1919 "description": "HTML title for the object, transformed for display.", 1920 "type": "string", 1921 "context": [ 1922 "view", 1923 "edit", 1924 "embed" 1925 ], 1926 "readonly": true 1927 } 1928 }, 1929 "required": false 1545 1930 }, 1546 1931 "content": { 1547 "required": false,1548 1932 "description": "The content for the object.", 1549 "type": "object" 1933 "type": "object", 1934 "properties": { 1935 "raw": { 1936 "description": "Content for the object, as it exists in the database.", 1937 "type": "string", 1938 "context": [ 1939 "edit" 1940 ] 1941 }, 1942 "rendered": { 1943 "description": "HTML content for the object, transformed for display.", 1944 "type": "string", 1945 "context": [ 1946 "view", 1947 "edit" 1948 ], 1949 "readonly": true 1950 }, 1951 "block_version": { 1952 "description": "Version of the content block format used by the object.", 1953 "type": "integer", 1954 "context": [ 1955 "edit" 1956 ], 1957 "readonly": true 1958 }, 1959 "protected": { 1960 "description": "Whether the content is protected with a password.", 1961 "type": "boolean", 1962 "context": [ 1963 "view", 1964 "edit", 1965 "embed" 1966 ], 1967 "readonly": true 1968 } 1969 }, 1970 "required": false 1550 1971 }, 1551 1972 "author": { 1552 "required": false,1553 1973 "description": "The ID for the author of the object.", 1554 "type": "integer" 1974 "type": "integer", 1975 "required": false 1555 1976 }, 1556 1977 "excerpt": { 1557 "required": false,1558 1978 "description": "The excerpt for the object.", 1559 "type": "object" 1979 "type": "object", 1980 "properties": { 1981 "raw": { 1982 "description": "Excerpt for the object, as it exists in the database.", 1983 "type": "string", 1984 "context": [ 1985 "edit" 1986 ] 1987 }, 1988 "rendered": { 1989 "description": "HTML excerpt for the object, transformed for display.", 1990 "type": "string", 1991 "context": [ 1992 "view", 1993 "edit", 1994 "embed" 1995 ], 1996 "readonly": true 1997 }, 1998 "protected": { 1999 "description": "Whether the excerpt is protected with a password.", 2000 "type": "boolean", 2001 "context": [ 2002 "view", 2003 "edit", 2004 "embed" 2005 ], 2006 "readonly": true 2007 } 2008 }, 2009 "required": false 1560 2010 }, 1561 2011 "featured_media": { 1562 "required": false,1563 2012 "description": "The ID of the featured media for the object.", 1564 "type": "integer" 2013 "type": "integer", 2014 "required": false 1565 2015 }, 1566 2016 "comment_status": { 1567 "required": false, 2017 "description": "Whether or not comments are open on the object.", 2018 "type": "string", 1568 2019 "enum": [ 1569 2020 "open", 1570 2021 "closed" 1571 2022 ], 1572 "description": "Whether or not comments are open on the object.", 1573 "type": "string" 2023 "required": false 1574 2024 }, 1575 2025 "ping_status": { 1576 "required": false, 2026 "description": "Whether or not the object can be pinged.", 2027 "type": "string", 1577 2028 "enum": [ 1578 2029 "open", 1579 2030 "closed" 1580 2031 ], 1581 "description": "Whether or not the object can be pinged.", 1582 "type": "string" 2032 "required": false 1583 2033 }, 1584 2034 "menu_order": { 1585 "required": false,1586 2035 "description": "The order of the object in relation to other object of its type.", 1587 "type": "integer" 2036 "type": "integer", 2037 "required": false 1588 2038 }, 1589 2039 "meta": { 1590 "required": false,1591 2040 "description": "Meta fields.", 1592 "type": "object" 2041 "type": "object", 2042 "properties": [], 2043 "required": false 1593 2044 }, 1594 2045 "template": { 1595 "required": false,1596 2046 "description": "The theme file to use to display the object.", 1597 "type": "string" 2047 "type": "string", 2048 "required": false 1598 2049 } 1599 2050 } … … 1605 2056 "args": { 1606 2057 "id": { 1607 "required": false,1608 2058 "description": "Unique identifier for the object.", 1609 "type": "integer" 2059 "type": "integer", 2060 "required": false 1610 2061 }, 1611 2062 "force": { 1612 " required": false,2063 "type": "boolean", 1613 2064 "default": false, 1614 2065 "description": "Whether to bypass Trash and force deletion.", 1615 " type": "boolean"2066 "required": false 1616 2067 } 1617 2068 } … … 1631 2082 "args": { 1632 2083 "parent": { 1633 "required": false,1634 2084 "description": "The ID for the parent of the object.", 1635 "type": "integer" 2085 "type": "integer", 2086 "required": false 1636 2087 }, 1637 2088 "context": { 1638 " required": false,1639 " default": "view",2089 "description": "Scope under which the request is made; determines fields present in response.", 2090 "type": "string", 1640 2091 "enum": [ 1641 2092 "view", … … 1643 2094 "edit" 1644 2095 ], 1645 "de scription": "Scope under which the request is made; determines fields present in response.",1646 " type": "string"2096 "default": "view", 2097 "required": false 1647 2098 }, 1648 2099 "page": { 1649 "required": false, 2100 "description": "Current page of the collection.", 2101 "type": "integer", 1650 2102 "default": 1, 1651 " description": "Current page of the collection.",1652 " type": "integer"2103 "minimum": 1, 2104 "required": false 1653 2105 }, 1654 2106 "per_page": { 1655 "required": false,1656 2107 "description": "Maximum number of items to be returned in result set.", 1657 "type": "integer" 2108 "type": "integer", 2109 "minimum": 1, 2110 "maximum": 100, 2111 "required": false 1658 2112 }, 1659 2113 "search": { 1660 "required": false,1661 2114 "description": "Limit results to those matching a string.", 1662 "type": "string" 2115 "type": "string", 2116 "required": false 1663 2117 }, 1664 2118 "exclude": { 1665 "required": false,1666 "default": [],1667 2119 "description": "Ensure result set excludes specific IDs.", 1668 2120 "type": "array", 1669 2121 "items": { 1670 2122 "type": "integer" 1671 } 2123 }, 2124 "default": [], 2125 "required": false 1672 2126 }, 1673 2127 "include": { 1674 "required": false,1675 "default": [],1676 2128 "description": "Limit result set to specific IDs.", 1677 2129 "type": "array", 1678 2130 "items": { 1679 2131 "type": "integer" 1680 } 2132 }, 2133 "default": [], 2134 "required": false 1681 2135 }, 1682 2136 "offset": { 1683 "required": false,1684 2137 "description": "Offset the result set by a specific number of items.", 1685 "type": "integer" 2138 "type": "integer", 2139 "required": false 1686 2140 }, 1687 2141 "order": { 1688 "required": false, 2142 "description": "Order sort attribute ascending or descending.", 2143 "type": "string", 1689 2144 "default": "desc", 1690 2145 "enum": [ … … 1692 2147 "desc" 1693 2148 ], 1694 "description": "Order sort attribute ascending or descending.", 1695 "type": "string" 2149 "required": false 1696 2150 }, 1697 2151 "orderby": { 1698 "required": false, 2152 "description": "Sort collection by object attribute.", 2153 "type": "string", 1699 2154 "default": "date", 1700 2155 "enum": [ … … 1707 2162 "title" 1708 2163 ], 1709 "description": "Sort collection by object attribute.", 1710 "type": "string" 2164 "required": false 1711 2165 } 1712 2166 } … … 1727 2181 "args": { 1728 2182 "parent": { 1729 "required": false,1730 2183 "description": "The ID for the parent of the object.", 1731 "type": "integer" 2184 "type": "integer", 2185 "required": false 1732 2186 }, 1733 2187 "id": { 1734 "required": false,1735 2188 "description": "Unique identifier for the object.", 1736 "type": "integer" 2189 "type": "integer", 2190 "required": false 1737 2191 }, 1738 2192 "context": { 1739 " required": false,1740 " default": "view",2193 "description": "Scope under which the request is made; determines fields present in response.", 2194 "type": "string", 1741 2195 "enum": [ 1742 2196 "view", … … 1744 2198 "edit" 1745 2199 ], 1746 "de scription": "Scope under which the request is made; determines fields present in response.",1747 " type": "string"2200 "default": "view", 2201 "required": false 1748 2202 } 1749 2203 } … … 1755 2209 "args": { 1756 2210 "parent": { 1757 "required": false,1758 2211 "description": "The ID for the parent of the object.", 1759 "type": "integer" 2212 "type": "integer", 2213 "required": false 1760 2214 }, 1761 2215 "id": { 1762 "required": false,1763 2216 "description": "Unique identifier for the object.", 1764 "type": "integer" 2217 "type": "integer", 2218 "required": false 1765 2219 }, 1766 2220 "force": { 1767 " required": false,2221 "type": "boolean", 1768 2222 "default": false, 1769 2223 "description": "Required to be true, as revisions do not support trashing.", 1770 " type": "boolean"2224 "required": false 1771 2225 } 1772 2226 } … … 1787 2241 "args": { 1788 2242 "parent": { 1789 "required": false,1790 2243 "description": "The ID for the parent of the object.", 1791 "type": "integer" 2244 "type": "integer", 2245 "required": false 1792 2246 }, 1793 2247 "context": { 1794 " required": false,1795 " default": "view",2248 "description": "Scope under which the request is made; determines fields present in response.", 2249 "type": "string", 1796 2250 "enum": [ 1797 2251 "view", … … 1799 2253 "edit" 1800 2254 ], 1801 "de scription": "Scope under which the request is made; determines fields present in response.",1802 " type": "string"2255 "default": "view", 2256 "required": false 1803 2257 } 1804 2258 } … … 1810 2264 "args": { 1811 2265 "parent": { 1812 "required": false,1813 2266 "description": "The ID for the parent of the object.", 1814 "type": "integer" 2267 "type": "integer", 2268 "required": false 1815 2269 }, 1816 2270 "date": { 1817 "required": false,1818 2271 "description": "The date the object was published, in the site's timezone.", 1819 2272 "type": [ 1820 2273 "string", 1821 2274 "null" 1822 ] 2275 ], 2276 "format": "date-time", 2277 "required": false 1823 2278 }, 1824 2279 "date_gmt": { 1825 "required": false,1826 2280 "description": "The date the object was published, as GMT.", 1827 2281 "type": [ 1828 2282 "string", 1829 2283 "null" 1830 ] 2284 ], 2285 "format": "date-time", 2286 "required": false 1831 2287 }, 1832 2288 "slug": { 1833 "required": false,1834 2289 "description": "An alphanumeric identifier for the object unique to its type.", 1835 "type": "string" 2290 "type": "string", 2291 "required": false 1836 2292 }, 1837 2293 "status": { 1838 "required": false, 2294 "description": "A named status for the object.", 2295 "type": "string", 1839 2296 "enum": [ 1840 2297 "publish", … … 1844 2301 "private" 1845 2302 ], 1846 "description": "A named status for the object.", 1847 &nbs