I have been searching for the proper way to modify the returned responses for a custom post type. I have found a way to do it but the official documentation discourages this method.
I personally don’t think it would matter since it’s a custom post type that only the part of the application that I built interacts with it but I’d still like to do it the proper way.
WordPress suggests that a custom context is created before removing the any data from the response, but I can’t find any documentation that shows how to do this. Can someone point me in the right direction to doing this.
I know they strongly discourage this practice but I am getting over 20 fields which includes arrays and objects when I only need like 5/6 of these. I’m sure it will make a big difference in the speed and responsiveness of the application.
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
or WP_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;
}