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:

  1. set rest_controller_class for custom post type (CPT)
  2. Extend WP_REST_Controller or WP_REST_Posts_Controller
  3. Register routes and define methods
  4. 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, '/'. $base, array(
                        'methods'  => 'GET',
                        'callback' => array( $this, 'my_get_callback' ),
                        'permission_callback' => array( $this, 'key_permissions_check' ),
                        '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, '/'. $base2, array(
                        'methods'  => 'GET',
                        'callback' => array( $this, 'my_get_callback_two' ),
                        'permission_callback' => array( $this, 'key_permissions_check' ),
                        'methods'  => 'POST',
                        'callback' => array( $this, 'my_post_callback_two' ),
                        'permission_callback' => array( $this, 'key_permissions_check' ),


       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 class

The WP_Rest_Request class provides several methods for dealing with $request.


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.
            '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;

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.