WP-API / node-wpapi

An isomorphic JavaScript client for the WordPress REST API
http://wp-api.org/node-wpapi/
MIT License
1.68k stars 191 forks source link

Add a guide for "how to work with meta" #280

Open nezzard opened 7 years ago

nezzard commented 7 years ago

Hi, i tried to update post meta, when i created posts, but nothing happened It's possible with node-wpapi? wp.song().create({ title: '1', content: 'Your post content', status: 'publish', meta: {key: 'youtube', value: '12'}, }).then(function( response ) { console.log( response.id ); })

bigandy commented 7 years ago

On the WordPress side of things you'll need to set things up so that you can read and post meta. See http://v2.wp-api.org/extending/modifying/#read-and-write-a-post-meta-field-in-post-responses

kadamwhite commented 7 years ago

A better option these days is to use first-party meta support, introduced in 4.6, detailed here in this API status update post and further explained in the README from the pull request for meta handling

chattes commented 7 years ago

@kadamwhite is there some change I have a meta field upvote for my custom post and I have registered using register_meta() , as suggested and when I use a get request , I am getting the meta values like..

  "meta": {
    "upvote": "4",
    "downvote": "0"
  }

When I try to update it works via postman if I pass the body as

{ "meta": {
    "upvote": "5"
} }

But the node-wpapi does not take this, if I pass it as

{
meta:{
key:'upvote'
value: '4'
}}

It does not update the values.

kadamwhite commented 7 years ago

Merging #286 into this issue; documenting how to work with custom meta is currently our top-priority docs issue

dimadin commented 6 years ago

When you create/update post, you pass meta object, for example:

wpapi.posts().create( {
    title: 'Your Title',
    content: ' Your content',
    status: 'publish',
    meta: {
        custom_meta_key: 'something'
    }
} ).then( function( response ) {
    // whatever
} );

On the server side, you must use register_meta(). If you are using custom post type, the post type must have custom-fields support (see documentation for $args['supports'] of register_post_type(). That is documented for REST API.

But if you are using meta with custom role, your role should also have edit_post_meta (and delete_post_meta if you are deleting) capability. See code for WP_REST_Meta_Fields::update_meta_value() and WP_REST_Meta_Fields::delete_meta_value(). I haven't seen that this is documented anywhere so I figured it out during debugging.

sculpt0r commented 6 years ago

@dimadin Sorry, but could You be more specific, where exactly on server side I should change something to get meta work?

dmdb commented 6 years ago

Messed with the same problem, being total noob in wordpress infrastructure. Solved by putting

register_meta('post', 'duration', [
  'type' => 'integer',
  'description' => 'duration',
  'single' => true,
  'show_in_rest' => true,
]);

into functions.php of theme. This unlocked me:

meta: { duration: 123 }
kadamwhite commented 6 years ago

@Calemb @dmdb In WordPress 5.0 note that this will change to register_post_meta( 'post', ... -- the snippet you have here will register "duration" for all custom post types. (You'd change 'post' to 'my_cpt' if you want duration to apply to a custom post type). We will be releasing a comprehensive update to our meta handling documentation on the REST API handbook in conjunction with 5.0.

b02902032 commented 6 years ago

I've been struggling for a few days and finally found how to deal with it. I added two meta fields to comment meta, which are "likes" and "pin". To enable POST request from frontend like reactjs, I need to add "likes" and "pin" to REST API. This is how I add and update data: _Since I am very new to Wordpress and PHP, I spent most of the time finding out why comment meta is not updating through update_comment_meta. It turns out that I need to access the comment id through $comment_object->comment_ID not $comment_object->ID. So, make sure you are familiar with the type you are working on._

function slug_register_comment_meta() {
    register_rest_field( 'comment',
        'likes',
        array(
            'get_callback'    => 'slug_get_comment_meta',
            'update_callback' => 'slug_update_comment_meta',
            'schema'          => array('likes' => 'The number of likes received in this comment.'),
        )
    );
    register_rest_field( 'comment',
        'pin',
        array(
            'get_callback'    => 'slug_get_comment_meta',
            'update_callback' => 'slug_update_comment_meta',
            'schema'          => array('pin' => 'If this comment is pinned or not.'),
        )
    );
}

function slug_get_comment_meta( $comment_object, $field_name, $request ) {
  return get_comment_meta( $comment_object['id'], $field_name , true );
}

function slug_update_comment_meta( $value, $comment_object, $field_name ) {
  return update_comment_meta( $comment_object->comment_ID, $field_name, wp_slash( $value ) );
}
add_action( 'rest_api_init', 'slug_register_comment_meta' );

I only test the code with curl in my terminal:

curl -X POST http://website.com/wp-json/wp/v2/comments -H 'content-type: application/json' -d '{"post": 1, "content":"comment meta test", "author_name":"name", "author_email":"email@gmail.com", "likes":"1000", "pin":"1"}'
kadamwhite commented 4 years ago

Responding to some prior questions in this thread, @chattes you should be using the same structure in Postman as in this library, so I'm unclear on why you believed you needed to separate the key and value. If you have registered meta, you'd update it as,

.update( {
    meta: {
        upvote: 5,
    }
} )

@b02902032 What you have there looks like it works (and I assure you, even seasoned contributors get confused by the inconsistent property naming!) For a post, page, or other custom post type resource though I'd stick with register_post_meta over register_rest_field unless you need to derive the data from something other than post meta.

tomatrow commented 4 years ago

Here's how to add a boolean meta field to tags and posts.

function prefix_register_meta_fields()
{
    $term_types = ['post_tag'];
    $post_types = ['post'];

    $key = 'the_example_key';
    $args = [
        'type' => 'boolean',
        'description' =>
            'An the_example_key boolean value.',
        'single' => true,
        'show_in_rest' => true
    ];

    foreach ($post_types as $type) {
        register_post_meta($type, $key, $args);
    }
    foreach ($term_types as $type) {
        register_term_meta($type, $key, $args);
    }
}

add_action('rest_api_init', 'prefix_register_meta_fields');

And then update it on some post of your choosing.


wp.tags()
        .id(TAG_ID)
        .update({
            meta: {
               the_example_key : true
            }
        })

wp.posts()
        .id(POST_ID)
        .update({
            meta: {
               the_example_key : true
            }
        })
CyberCyclone commented 4 years ago

How do you add multiple meta values with the same key? Using a single object only allows attaching of 1 meta key.

ProvokatorDark commented 3 years ago

I did not find an example of what to do if you need to add several values for one key. I try in wp register_meta( 'post', 'reader', array( 'show_in_rest' => true, 'single' => false, 'type' => 'string', )); i add meta in wp-api wp.posts().id( 32477 ).update({ title: 'A Better Title', slug:"kukusik-100", status: 'draft', meta:{ reader:'Anton Petrov,Oleg Arno', } }).then(function( response ) { console.log( response.id ); }) And I get in the post meta fields the following reader:'Anton' reader:'Petrov' reader:'Oleg' reader:'Arno' I would like to see there reader:'Anton Petrov' reader:'Oleg Arno'