I'm pretty new to the REST API so please excuse any stupid questions. I'm currently trying to develop a plugin and therefore I need to register a custom post type including a custom field. This is all done and seems to work. The problem is that the callback functions aren't working. I'm not sure about the get_post_meta_cb but the update callback simply does nothing! I've tried pretty much everyting I could find but nothing worked.

Here's the code:

// Define the CPT labels
private function define_cpt_labels()
    $labels = [
        'name'               => _x( 'Variable Offers', 'post type general name', $this->cptTextDomain ),
        'singular_name'      => _x( 'Varaible Offer', 'post type singular name', $this->cptTextDomain ),
        'menu_name'          => _x( 'Variable Offers', 'admin menu',             $this->cptTextDomain ),
        'name_admin_bar'     => _x( 'Variable Offer', 'add new on admin bar',    $this->cptTextDomain ),
        'add_new'            => _x( 'Add New', 'book',                           $this->cptTextDomain ),
        'add_new_item'       => __( 'Add New Variale Offer',                     $this->cptTextDomain ),
        'new_item'           => __( 'New Variable Offer',                        $this->cptTextDomain ),
        'edit_item'          => __( 'Edit Variable Offer',                       $this->cptTextDomain ),
        'view_item'          => __( 'View Variable Offer',                       $this->cptTextDomain ),
        'all_items'          => __( 'All Variable Offers',                       $this->cptTextDomain ),
        'search_items'       => __( 'Search Variable Offers',                    $this->cptTextDomain ),
        'parent_item_colon'  => __( 'Parent Variable Offers:',                   $this->cptTextDomain ),
        'not_found'          => __( 'No Variable Offers found.',                 $this->cptTextDomain ),
        'not_found_in_trash' => __( 'No Variable Offers found in Trash.',        $this->cptTextDomain )

    return $labels;

// Define CPT arguments
private function define_cpt_agruments()
    $args = [
        'labels'                => $this->define_cpt_labels(),
        'description'           => __( 'Description.', $this->cptTextDomain ),
        'public'                => true,
        'publicly_queryable'    => true,
        'show_ui'               => true,
        'show_in_menu'          => true,
        'query_var'             => true,
        'rewrite'               => ['slug' => self::CPT_SLUG],
        'capability_type'       => 'post',
        'has_archive'           => true,
        'hierarchical'          => false,
        'menu_position'         => null,
        'show_in_rest'          => true,
        'rest_base'             => self::CPT_SLUG,
        'rest_controller_class' => 'WP_REST_Posts_Controller'

    return $args;

public function registerCpt()
    add_action( 'init', [$this, 'register_cpt'] );
    add_action( 'rest_api_init', [$this, 'register_cpt_fields'] );

public function register_cpt()
    register_post_type( self::CPT_SLUG, $this->define_cpt_agruments());

public function register_cpt_fields() {

    register_rest_field( self::CPT_SLUG, 'cpt_meta_fields', array(
        'get_callback'    => [$this, 'get_post_meta_cb'],
        'update_callback' => [$this, 'update_post_meta_cb'],
        'schema' => null

public function get_post_meta_cb( $object, $field_name, $request ) {
    return get_post_meta( $object->ID, $field_name );

public function update_post_meta_cb( $value, $object, $field_name ) {
    return update_post_meta( $object->ID, $field_name, $value );

All that is defined in a class. The constant is defined as CPT_SLUG = 'variable_offer'. I use Postman to test the requests. When I do

  • http://local.dev/wp-json/wp/v2/variable_offer or
  • http://local.dev/wp-json/wp/v2/variable_offer/5

I get the CPT with ID 5 in both cases. When I put any other number I get the corresponding post (guess that is how it is supposed to be). Here's a Postman output:

Screenshot Postman response GET

As you can see the custom field is there. Whenever I try someting like http://loca.dev/wp-json/wp/v2/variable_offer/5/cpt_meta_fields (which I assumed to be the request in order to get the meta field only) it says there is no such route registered.

When I try to update the field nothing happens! The POST request is http://loca.dev/wp-json/wp/v2/variable_offer/7?cpt_meta_fields=9.

Can anyone tell me what I'm doing wrong?


  • If you're sending the request from an external app, like postman, the request needs to be authenticated. Is it? Commented Feb 22, 2019 at 6:56
  • Yes the request is authenticated. I’m using a plugin called JSON basic authentication and have the Postman request authenticated with basic authentification plus the admin user and password. Commented Feb 22, 2019 at 6:59


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.