Home > Mobile >  Customize returned object by WP_Query or similiar
Customize returned object by WP_Query or similiar

Time:11-05

I'm trying to query posts, but I'm only interested in certain fields and want to limit the fields that are being returned. In the end I want to return an array of posts with limited fields to pass it to a rest-api endpoint, so I can fetch it in another project.

I managed to query exactly the posts that I want (meta key geo_latitude exists) and pass it to the api endpoint, but the query does return an array of WP_Post objects which don't include the geodata I'm looking for. My big headache is how to customize the return value.

For the return value, I'm trying to achieve this: Array of queried posts Each post only contains:

  • Post Title
  • Post Link
  • geo_latitude
  • geo_longitude

Geodata: https://codex.wordpress.org/Geodata (the values are being copied from the plugin geo mashup)

Working code for querying the posts:

// Query the posts
function get_posts_with_geo( $data ) {
  $posts = get_posts( array(
    'numberposts'   => -1,
    'post_type'     => 'post',
    'meta_query' => [
            [
                'key'     => 'geo_latitude',
                'compare' => 'EXISTS',
            ]
        ],
  ) );

  if ( empty( $posts ) ) {
    return null;
  }

  return $posts;
}

// Register api endpoint and pass the query post function to it.
add_action( 'rest_api_init', function () {
  register_rest_route( 'endpoint', '/posts', array(
    'methods' => 'GET',
    'callback' => 'get_posts_with_geo',
  ) );
} );

It returns an array of following wp posts object:

WP_Post Object
(
    [ID] =>
    [post_author] =>
    [post_date] => 
    [post_date_gmt] => 
    [post_content] => 
    [post_title] => 
    [post_excerpt] => 
    [post_status] =>
    [comment_status] =>
    [ping_status] => 
    [post_password] => 
    [post_name] =>
    [to_ping] => 
    [pinged] => 
    [post_modified] => 
    [post_modified_gmt] =>
    [post_content_filtered] => 
    [post_parent] => 
    [guid] => 
    [menu_order] =>
    [post_type] =>
    [post_mime_type] => 
    [comment_count] =>
    [filter] =>
)

Before I tried to use the already available rest-api endpoints, especially /wp-json/wp/v2/posts. We're talking about around 250 posts which have geodata, but over 500 posts overall. Limit per page is 100. I can't query for posts with geodata only in this endpoint, so I would have to receive all posts, loop through pagination and then filter all posts without geodata out. That's pretty wasteful and the reason I'm trying to build my own endpoint which gives me exactly the data that I want.

/edit:

Likely a lot of room of improvement, but working solution so far:

Right before returning the $posts in function get_posts_with_geo, following foreach loop was added:

foreach ( $posts as $key => $post ) {
    $posts[ $key ]->title = get_the_title( $post->ID );
    $posts[ $key ]->link = get_permalink( $post->ID );
    $posts[ $key ]->latitude = get_post_meta( $post->ID, 'geo_latitude', true );
    $posts[ $key ]->longitude = get_post_meta( $post->ID, 'geo_longitude', true );
  }

It adds the keys to the end of each returned $post, but still returns every other field as well from the WP_Object.

CodePudding user response:

You can use the posts_fields filter to alter what fields get returned.

you need to pass 'suppress_filters => false in the get_posts() arguments in order to get that filter to run.

example :-

function alter_fields_zillion($fields) {
  return 'ID,post_title'; // etc
}
add_filter('posts_fields','alter_fields_zillion');

Or you can loop through the posts then add meta_data with the post.

foreach ( $posts as $key => $post ) {
    $posts[ $key ]->key1 = get_post_meta( $post->ID, 'key1', true );
    $posts[ $key ]->key2 = get_post_meta( $post->ID, 'key2', true );
}

I hope it helps.

  • Related