Ask your WordPress questions! Pay money and get answers fast! (more info)

How do you return all posts by a custom order_by for the rest API WordPress

  • SOLVED

I am looking to extend the WordPress API to force it to list posts that are "featured" first and then the rest of the posts.

Basically, I have 2 plugins on my site, one is "NS Featured Posts" (https://wordpress.org/plugins/ns-featured-posts/) and "Post Type Order" (https://wordpress.org/plugins/post-types-order/).

The featured post plugin creates a meta_key of "_is_ns_featured_post" with a value of "Yes" when you flag a post as featured. The "Post Type Order" has a field you can use to order by called "menu_order".

I know how to create a custom endpoint, but I can't figure out how to do the custom order? Can someone help me on that?
John

Answers (4)

2016-08-11

Luis Abarca answers:

Maybe you can try adding a new endpoint like http://yourdomain.com/wp-json/myapi/featured




add_action('rest_api_init', 'register_myapi_endpoints');

function register_myapi_endpoints()
{
register_rest_route('myapi', '/featured', array(
'methods' => 'GET',
'callback' => 'featured_post_callback'
));
}

function featured_post_callback()
{
// Use WP_Query to get posts
$featured = WP_Query($your_arguments);

$posts = array();
$i = 0;

while ($featured->have_posts()) {
$featured->the_post();

// You can get only the data you need
$posts[$i] = array(
'ID' => $post->ID;
'title' => $post->post_title;
// ....
);

$i++;
}

wp_send_json($posts);
}


Luis Abarca comments:

Hi otherjohn, i put an example to add a custom endpoint

2016-08-11

Rempty answers:

Hello otherjohn

By default if you have installed Post Type Order, the api return the posts ordered by the your custom order
/wp-json/wp/v2/posts

If you want to order by a custom meta field (NS Featured Posts), you can add this to your functions.php

function my_allow_meta_query( $valid_vars ) {
$valid_vars = array_merge( $valid_vars, array( 'meta_key', 'meta_value' ) );
return $valid_vars;
}
add_filter( 'rest_query_vars', 'my_allow_meta_query' );


And query like this
/wp-json/wp/v2/posts?filter[meta_key]=_is_ns_featured_post&filter[order]=DESC&filter[orderby]=meta_value

Now you have the list of the featured posts,

For get the other posts without the featured
/wp-json/wp/v2/posts?exclude=id1,id2,id3
(id1,id2,id3 the id of the featured posts)


otherjohn comments:

The suggestion returns the featured at top as expected BUT not in the post type order.
john


Rempty comments:

You can change the url to
/wp-json/wp/v2/posts?filter[meta_key]=_is_ns_featured_post&filter[meta_value]=yes&filter[order]=ASC&filter[orderby]=menu_order

2016-08-11

dimadin answers:

This is not tested, but you should get the idea:


function md_featured_and_ordered( $args ) {
$feauterd_args = $not_featured_args = $args;

// First get featured posts
$feauterd_args['meta_query'] = array(
array(
'key' => '_is_ns_featured_post',
'value' => 'yes',
),
);
$feauterd_args['orderby'] = 'menu_order';
$feauterd_args['fields'] = 'ids';

$featured = get_post( $featured_args );

// Then we get rest of posts
$not_featured_args['meta_query'] = array(
array(
'key' => '_is_ns_featured_post',
'value' => 'yes',
'compare' => 'NOT LIKE',
),
);
$not_featured_args['orderby'] = 'menu_order';
$not_featured_args['fields'] = 'ids';

$not_featured = get_post( $not_featured_args );

$args['post__in'] = array_merge( $featured, $not_featured );
$args['orderby'] = 'post__in'

return $args;
}
add_filter( 'rest_post_query', 'md_featured_and_ordered' );


dimadin comments:

I had some spelling errors there so here are changes:


function md_featured_and_ordered( $args ) {
$featured_args = $not_featured_args = $args;

// First get featured posts
$featured_args['meta_query'] = array(
array(
'key' => '_is_ns_featured_post',
'value' => 'yes',
),
);
$featured_args['orderby'] = 'menu_order';
$featured_args['fields'] = 'ids';

$featured = get_post( $featured_args );

// Then we get rest of posts
$not_featured_args['meta_query'] = array(
array(
'key' => '_is_ns_featured_post',
'value' => 'yes',
'compare' => 'NOT LIKE',
),
);
$not_featured_args['orderby'] = 'menu_order';
$not_featured_args['fields'] = 'ids';

$not_featured = get_post( $not_featured_args );

$args['post__in'] = array_merge( $featured, $not_featured );
$args['orderby'] = 'post__in';

return $args;
}
add_filter( 'rest_post_query', 'md_featured_and_ordered' );


otherjohn comments:

Im going to test these first. Thanks


dimadin comments:

Oops, my IDE wrote get_post instead of get_posts. Sorry for that.


otherjohn comments:

How do I add this on a Custom Endpoint


dimadin comments:

So do you use /wp-json/wp/v2/posts endpoint or have a custom one? Do you use WP API plugin at all or just support built-in WordPress? If you use custom endpoint, what response do you expect?


dimadin comments:

I added some quick code for custom endpoint, no plugin required. I tested it and it works, but I don't know would you pass some parameters, what number of posts, and what you need in response. Here is workable code:


function md_custom_endpoint() {
register_rest_route( 'custom/v1', '/posts', array(
'callback' => 'md_custom_endpoint_callback',
'methods' => WP_REST_Server::READABLE,
) );
}
add_action( 'rest_api_init', 'md_custom_endpoint' );

function md_custom_endpoint_callback( $request ) {
$featured_args = $not_featured_args = $args = array();

// First get featured posts
$featured_args['meta_query'] = array(
array(
'key' => '_is_ns_featured_post',
'value' => 'yes',
),
);
$featured_args['orderby'] = 'menu_order';
$featured_args['fields'] = 'ids';

$featured = get_posts( $featured_args );

// Then we get rest of posts
$not_featured_args['meta_query'] = array(
'relation' => 'OR',
array(
'key' => '_is_ns_featured_post',
'value' => 'yes',
'compare' => 'NOT LIKE',
),
array(
'key' => '_is_ns_featured_post',
'compare' => 'NOT EXISTS',
),
);
$not_featured_args['orderby'] = 'menu_order';
$not_featured_args['fields'] = 'ids';

$not_featured = get_posts( $not_featured_args );

$args['post__in'] = array_merge( $featured, $not_featured );
$args['orderby'] = 'post__in';

$posts = get_posts( $args );

$response = rest_ensure_response( $posts );
return $response;
}


otherjohn comments:

Yes, I would pass page, per_page, and categories


dimadin comments:

Here is your code. It works on /wp-json/custom/v1/posts endpoint and accepts arguments you need just like /wp-json/wp/v2/posts.


function md_custom_endpoint() {
register_rest_route( 'custom/v1', '/posts', array(
'callback' => 'md_custom_endpoint_callback',
'methods' => WP_REST_Server::READABLE,
) );
}
add_action( 'rest_api_init', 'md_custom_endpoint' );

function md_custom_endpoint_callback( $request ) {
$featured_args = $not_featured_args = $args = array();

// Get featured posts
$featured_args['meta_query'] = array(
array(
'key' => '_is_ns_featured_post',
'value' => 'yes',
),
);
$featured_args['orderby'] = 'menu_order';
$featured_args['fields'] = 'ids';
$featured_args['posts_per_page'] = -1;

$featured = get_posts( $featured_args );

// Get not featured posts
$not_featured_args['meta_query'] = array(
'relation' => 'OR',
array(
'key' => '_is_ns_featured_post',
'value' => 'yes',
'compare' => 'NOT LIKE',
),
array(
'key' => '_is_ns_featured_post',
'compare' => 'NOT EXISTS',
),
);
$not_featured_args['orderby'] = 'menu_order';
$not_featured_args['fields'] = 'ids';
$not_featured_args['posts_per_page'] = -1;

$not_featured = get_posts( $not_featured_args );

// Get all posts
$args['paged'] = $request['page'];
$args['posts_per_page'] = $request['per_page'];

$taxonomies = wp_list_filter( get_object_taxonomies( 'post', 'objects' ), array( 'show_in_rest' => true ) );
foreach ( $taxonomies as $taxonomy ) {
$base = ! empty( $taxonomy->rest_base ) ? $taxonomy->rest_base : $taxonomy->name;
if ( ! empty( $request[ $base ] ) ) {
$args['tax_query'][] = array(
'taxonomy' => $taxonomy->name,
'field' => 'term_id',
'terms' => $request[ $base ],
'include_children' => false,
);
}
}

$args['post__in'] = array_merge( $featured, $not_featured );
$args['orderby'] = 'post__in';

$posts = get_posts( $args );

$response = rest_ensure_response( $posts );
return $response;
}

2016-08-11

webGP answers:

Hello otherjon!

As I understand you try to show all posts ordered by two parameters - fetaure (first posts) and menu_order. Try to add the code below into your functions.php


add_action('rest_api_init', 'register_myapi_endpoints');
function register_myapi_endpoints() {
register_rest_route('custom-api', '/posts-ordered', array(
'methods' => 'GET',
'callback' => 'posts_ordered'
));
}

function posts_ordered() {

$args = array (
'post_type' => 'post',
'post_status'=> 'publish',
'posts_per_page'=> -1,
'orderby' => array( 'meta_value' => 'DESC', 'menu_order' => 'ASC' ),
'meta_query' => array(
'relation' => 'OR',
array(
'key' => '_is_ns_featured_post',
'compare' => 'EXISTS'
),
),
);

$posts = get_posts($args);

wp_send_json($posts);

}

add_action( 'save_post', 'override_feature_meta', 999 );
function override_feature_meta($post_id) {
$featured_value = '';
if ( isset( $_POST['nsfp_settings']['make_this_featured'] ) && 'yes' == $_POST['nsfp_settings']['make_this_featured'] ) {
$featured_value = 'yes';
}
if ( 'yes' !== $featured_value ) {
update_post_meta( $post_id, '_is_ns_featured_post', 'no' );
}
return $post_id;
}


Your posts will be available at http://yourdomain.com/wp-json/custom-api/posts-ordered. Of course if you need use category or page params add standard args to $args array.

<strong>IMPORTANT!</strong>
"NS Featured Posts" plugin doesn't set meta for non-featured posts, which brokes sorting, so you have to update all posts in admin. I've added action which save meta with 'no' value.