While the docs state:
Note that the API cannot prevent you from changing responses, but the code is structured to strongly discourage this. Internally, field registration is powered by filters, and these can be used if you absolutely have no other choice.
there IS another choice for most cases, namely: custom endpoints/routes.
You can even assign a rest controller class to the CPT. So you can extend WP_Rest_Posts_Controller and set custom endpoints, their routes, parameters, and the corresponding callbacks to respond with whatever you need.
The steps involved are:
- set
rest_controller_class
for custom post type (CPT) Extend WP_REST_Controller
orWP_REST_Posts_Controller
- Register routes and define methods
- Possibly control response format with Schema
NOTE: WP_REST_Posts_Controller
itself is extending WP_REST_Controller
.
Setting rest_controller_class
argument for CPT:
1) In $args
array while registering:
$labels = array( ... );
$args = array(
'labels' => $labels,
...
...
'show_in_rest' => true,
'rest_base' => 'my_rest_base',
//'rest_controller_class' => 'WP_REST_Posts_Controller',
'rest_controller_class' => 'My_CPT_Controller_Class'
);
register_post_type( 'my-post-type', $args );
2) To add after CPT is registered, use the filter hook: register_post_type_args
function add_rest_stuff( $args, $post_type ) {
$custom_post_type="my-post-type";
if ( $post_type !== $custom_post_type ) {
return $args;
}
$args['show_in_rest'] = true;
$args['rest_base'] = 'my_rest_base';
$args['rest_controller_class'] = 'My_CPT_Controller_Class';
return $args;
}
add_filter('register_post_type_args', 'make_it_public' );
Extending WP_REST_Controller
for Custom endpoint(s)/route(s):
A quick partial example as a starting point (from a previous answer)
class My_CPT_Controller_Class extends WP_REST_Controller {
public function __construct() {
add_action( 'rest_api_init', array( $this, 'register_routes' ) );
}//end __construct
public function register_routes() {
$version = '1';
$namespace="my-fancy-namespace/v" . $version;
$base="my-route-base";
// so, site.com/wp-json/my-fancy-namespace/v1/my-route-base/
register_rest_route( $namespace, "https://wordpress.stackexchange.com/". $base, array(
array(
'methods' => 'GET',
'callback' => array( $this, 'my_get_callback' ),
'permission_callback' => array( $this, 'key_permissions_check' ),
),
array(
'methods' => 'POST',
'callback' => array( $this, 'my_post_callback' ),
'permission_callback' => array( $this, 'key_permissions_check' ),
),)
);
$base2 = 'my-second-base';
// so, site.com/wp-json/my-fancy-namespace/v1/my-second-base/
register_rest_route( $namespace, "https://wordpress.stackexchange.com/". $base2, array(
array(
'methods' => 'GET',
'callback' => array( $this, 'my_get_callback_two' ),
'permission_callback' => array( $this, 'key_permissions_check' ),
),
array(
'methods' => 'POST',
'callback' => array( $this, 'my_post_callback_two' ),
'permission_callback' => array( $this, 'key_permissions_check' ),
),)
);
}//register_routes
public function key_permissions_check() {
//do permissions check stuff
}
public function my_get_callback( WP_REST_Request $request ) {
//do stuff with $request
//see the methods mentioned below
}//end
}//end class
The WP_Rest_Request class provides several methods for dealing with $request
.
Schema
Look into Schema as well for building the responses.
I’ve added the prefix_get_comment()
example from the bottom of that page since it is a straightforward example:
function prefix_register_my_comment_route() {
register_rest_route( 'my-namespace/v1', '/comments', array(
// Notice how we are registering multiple endpoints the 'schema' equates to an OPTIONS request.
array(
'methods' => 'GET',
'callback' => 'prefix_get_comment_sample',
),
// Register our schema callback.
'schema' => 'prefix_get_comment_schema',
) );
}
/**
* Get our sample schema for comments.
*/
function prefix_get_comment_schema() {
$schema = array(
// This tells the spec of JSON Schema we are using which is draft 4.
'$schema' => 'http://json-schema.org/draft-04/schema#',
// The title property marks the identity of the resource.
'title' => 'comment',
'type' => 'object',
// In JSON Schema you can specify object properties in the properties attribute.
'properties' => array(
'id' => array(
'description' => esc_html__( 'Unique identifier for the object.', 'my-textdomain' ),
'type' => 'integer',
'context' => array( 'view', 'edit', 'embed' ),
'readonly' => true,
),
'author' => array(
'description' => esc_html__( 'The id of the user object, if author was a user.', 'my-textdomain' ),
'type' => 'integer',
),
'content' => array(
'description' => esc_html__( 'The content for the object.', 'my-textdomain' ),
'type' => 'string',
),
),
);
return $schema;
}