1

I'm creating a theme based on the underscore theme with Backbone.js integration. I am struggling to find any clear examples/documentation on the WP-API plugin's capabilities, and starting to find it fairly frustrating.

I am pulling in a basic list of posts using the following code:

var posts = new wp.api.collections.Posts(),
posts.fetch(options).done(function(){
    console.log( 'we now have 10 posts');
}

This works fine. The problem is I wish to retrieve some post_meta at the same time, without making multiple fetch calls asynchronously (one per post). There are some post_meta fields I wish to use, as well as getting the post thumbnail.

Any direction is appreciated.

1

4 Answers 4

1

I haven't used the WP-API/JSON REST client plugin so far, but this is what I can see in source: The ~/js/models.js is the entry point for all requests, it seems. And every of the wp.api.models (to name a few: Page, Post, Media, Revision, etc.) is just an extension of Backbone.Model.

And looking into the actual Post model, I see that there seems to be a way to fetch post meta data as well:

    defaults: function() {
        return {
            ID: null,
            title: '',
            status: 'draft',
            type: 'post',
            author: new wp.api.models.User(),
            content: '',
            link: '',
            'parent': 0,
            date: new Date(),
            date_gmt: new Date(),
            modified: new Date(),
            modified_gmt: new Date(),
            format: 'standard',
            slug: '',
            guid: '',
            excerpt: '',
            menu_order: 0,
            comment_status: 'open',
            ping_status: 'open',
            sticky: false,
            date_tz: 'Etc/UTC',
            modified_tz: 'Etc/UTC',
            terms: {},
            post_meta: {}, // <---- USE THIS OBJECT
            meta: {
                links: {}
            }
        };
    },

Link to Source

I don't know what exact object definition you used for

posts.fetch( options )

but you should give { post_meta : {} } a try.


To (maybe) debug what you have access to, you could dump the arguments in a callback attached to

var beforeSend = options.beforeSend;

which runs, of course, before the actual request gets fired. The "maybe" has its origin in that I was first looking at the gh-pages branch per accident. There's nowhere stated what branch is used for what, so I assume that master is the development and shipping branch (but who knows) and above might in that case not work.

10
  • Thanks for the response @Kaiser. I've played with the options (was currently {}), and tried changing it to various things like {post_meta: ['video_url']}, {post_meta: 'video_url'}, and several others, but it appears that the defaults mentioned above are strictly the default returned values. Nov 5, 2014 at 16:17
  • Currently in the PHP side of this, post_meta and post_thumbnail are not mentioned at all within the class-wp-json-posts.php class. There is a json_prepare_post filter which passes reference to the post object returned, so I am going to see if utilizing this will allow me to populate the post_thumbnail and post_meta attributes of the response. Nov 5, 2014 at 16:19
  • @EricHolmes Links to source please.
    – kaiser
    Nov 5, 2014 at 16:19
  • Also, beforeSend fires, but the object returned to it already has the JSON response output. Very strange. Nov 5, 2014 at 16:20
1

Inside the PHP side of things, there is a json_prepare_post filter, which allows you to alter the loose Post object returned. Here you can attach meta data and other things, such as post thumbnails.

add_filter( 'json_prepare_post', 'eh_json_prepare_post' );
function eh_json_prepare_post( $_post ) {
    $_post['post_meta']['some-value'] = get_post_meta( $_post['ID'], 'some-value', true );
    return $_post;
}
1

When I use the posts API, it fetches information include the meta automatically, and you should look to see what is returned using Rest Console or similar to see what should be removed. Also, there is a nice answer on here already which shows how to do that.

If you have a custom post type, that is not the same! You need to create a special handler for that.

There is an example in the pages file (class-wp-json-pages.php)

<?php
/**
 * Page post type handlers
 *
 * @package WordPress
 * @subpackage JSON API
 */

/**
 * Page post type handlers
 *
 * This class serves as a small addition on top of the basic post handlers to
 * add small functionality on top of the existing API.
 *
 * In addition, this class serves as a sample implementation of building on top
 * of the existing APIs for custom post types.
 *
 * @package WordPress
 * @subpackage JSON API
 */
class WP_JSON_Pages extends WP_JSON_CustomPostType {
    /**
     * Base route
     *
     * @var string
     */
    protected $base = '/pages';

    /**
     * Post type
     *
     * @var string
     */
    protected $type = 'page';

    /**
     * Register the page-related routes
     *
     * @param array $routes Existing routes
     * @return array Modified routes
     */
    public function register_routes( $routes ) {
        $routes = parent::register_routes( $routes );
        $routes = parent::register_revision_routes( $routes );
        $routes = parent::register_comment_routes( $routes );

        // Add post-by-path routes
        $routes[ $this->base . '/(?P<path>.+)'] = array(
            array( array( $this, 'get_post_by_path' ),    WP_JSON_Server::READABLE ),
            array( array( $this, 'edit_post_by_path' ),   WP_JSON_Server::EDITABLE | WP_JSON_Server::ACCEPT_JSON ),
            array( array( $this, 'delete_post_by_path' ), WP_JSON_Server::DELETABLE ),
        );

        return $routes;
    }

    /**
     * Retrieve a page by path name
     *
     * @param string $path
     * @param string $context
     *
     * @return array|WP_Error
     */
    public function get_post_by_path( $path, $context = 'view' ) {
        $post = get_page_by_path( $path, ARRAY_A );

        if ( empty( $post ) ) {
            return new WP_Error( 'json_post_invalid_id', __( 'Invalid post ID.' ), array( 'status' => 404 ) );
        }

        return $this->get_post( $post['ID'], $context );
    }

    /**
     * Edit a page by path name
     *
     * @param $path
     * @param $data
     * @param array $_headers
     *
     * @return true|WP_Error
     */
    public function edit_post_by_path( $path, $data, $_headers = array() ) {
        $post = get_page_by_path( $path, ARRAY_A );

        if ( empty( $post ) ) {
            return new WP_Error( 'json_post_invalid_id', __( 'Invalid post ID.' ), array( 'status' => 404 ) );
        }

        return $this->edit_post( $post['ID'], $data, $_headers );
    }

    /**
     * Delete a page by path name
     *
     * @param $path
     * @param bool $force
     *
     * @return true|WP_Error
     */
    public function delete_post_by_path( $path, $force = false ) {
        $post = get_page_by_path( $path, ARRAY_A );

        if ( empty( $post ) ) {
            return new WP_Error( 'json_post_invalid_id', __( 'Invalid post ID.' ), array( 'status' => 404 ) );
        }

        return $this->delete_post( $post['ID'], $force );
    }

    /**
     * Prepare post data
     *
     * @param array $post The unprepared post data
     * @param string $context The context for the prepared post. (view|view-revision|edit|embed|single-parent)
     * @return array The prepared post data
     */
    protected function prepare_post( $post, $context = 'view' ) {
        $_post = parent::prepare_post( $post, $context );

        // Override entity meta keys with the correct links
        $_post['meta']['links']['self'] = json_url( $this->base . '/' . get_page_uri( $post['ID'] ) );

        if ( ! empty( $post['post_parent'] ) ) {
            $_post['meta']['links']['up'] = json_url( $this->base . '/' . get_page_uri( (int) $post['post_parent'] ) );
        }

        return apply_filters( 'json_prepare_page', $_post, $post, $context );
    }
}

Replace "Pages" with "MyCustomPostTypes" and page with "mycustomposttype". Just be careful not to rename internal WordPress code that also uses the term page

Note: probably best to add this as a plugin rather than change the JSON-WP-API plugin

/**
 * Plugin Name: MyCustom JSON App API
 * Description: MyCustomPost handler for the JSON API
 * Dependency:  This plugin requires JSON-WP-API Plugin!!!! 
 * Author: 
 * Author URI: 
 * Version: 
 * Plugin URI: 
 */
1

with v2 of the API, there is now a hook to add additional fields to the response of an object, you need to use the register_rest_field() function,

add_action( 'rest_api_init', 'create_api_posts_meta_field' ); 
function create_api_posts_meta_field() {
    register_rest_field( array('post','page'), 'language-menu', array(
           'get_callback'    => 'get_custom_field_for_api',
           'schema'          => null,
        )
    );
}
function get_custom_field_for_api($object){
    return get_post_meta( $object['id'], 'some-value', true );
}

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.