3

I made a custom REST API endpoint for the front page of an app we're making so that it will return 3 custom queries based on post type instead of making 3 different HTTP requests for each post type, but can't figure out how to get the custom fields for each post to display. Not sure where to go next:

    class Home_Custom_Route extends WP_REST_Controller {
        /**
         * Register the routes for the objects of the controller.
         */
        public function my_register_routes() {
            $version = 'v2';
            $namespace = 'wp/' . $version;
            $base = 'home';
            register_rest_route( $namespace, '/' . $base, array(
                array(
                    'methods'         => WP_REST_Server::READABLE,
                    'callback'        => array( $this, 'get_items' ),
                    'permission_callback' => array( $this, 'get_items_permissions_check' ),
                    'args'            => array(

                    ),
                ),
            ) );
            register_rest_route( $namespace, '/' . $base . '/schema', array(
                'methods'         => WP_REST_Server::READABLE,
                'callback'        => array( $this, 'get_public_item_schema' ),
            ) );
        }

        /**
         * Get a collection of items
         *
         * @param WP_REST_Request $request Full data about the request.
         * @return WP_Error|WP_REST_Response
         */
        public function get_items( $request ) {
                $eventargs = array(
                    'post_type'      => 'event',
                    'posts_per_page' => 3,
                    'meta_key'       => 'wpcf-event-start',
                    'meta_value'     => current_time( 'timestamp', 1 ),
                    'meta_compare'   => '<=',
                );
                $main_events = new WP_Query( $eventargs );

                $listingargs = array(
                    'post_type'      => 'listings',
                    'posts_per_page' => 3,
                    'orderby'        => 'date',
                    'order'          => 'DESC',
                );
                $main_listings = new WP_Query( $listingargs );

                $ticketsargs = array(
                    'post_type'      => 'product',
                    'posts_per_page' => 3,
                    'orderby'        => 'date',
                    'order'          => 'DESC',
                    'tax_query'      => array(
                        array(
                            'taxonomy'  => 'product_cat',
                            'field'     => 'slug',
                            'terms'     => 'tickets',
                        )
                    ),

                );
                $main_tickets = new WP_Query( $ticketsargs );

                $data = array(
                    'events'    =>  $main_events->posts,
                    'listings'  =>  $main_listings->posts,
                    'tickets'   =>  $main_tickets->posts,
                );
                return new WP_REST_Response( $data, 200 );
        }

        /**
         * Get one item from the collection
         *
         * @param WP_REST_Request $request Full data about the request.
         * @return WP_Error|WP_REST_Response
         */
        public function get_item( $request ) {
            //get parameters from request
            $params = $request->get_params();
            $item = array();//do a query, call another class, etc
            $data = $this->prepare_item_for_response( $item, $request );

            //return a response or error based on some conditional
            if ( 1 == 1 ) {
                return new WP_REST_Response( $data, 200 );
            }else{
                return new WP_Error( 'code', __( 'Couldnt find it', 'xxx' ) );
            }
        }
        /**
         * Check if a given request has access to get items
         *
         * @param WP_REST_Request $request Full data about the request.
         * @return WP_Error|bool
         */
        public function get_items_permissions_check( $request ) {
            return true; //<--use to make readable by all
        }
        /**
         * Check if a given request has access to get a specific item
         *
         * @param WP_REST_Request $request Full data about the request.
         * @return WP_Error|bool
         */
        public function get_item_permissions_check( $request ) {
            return $this->get_items_permissions_check( $request );
        }

        /**
         * Prepare the item for the REST response
         *
         * @param mixed $item WordPress representation of the item.
         * @param WP_REST_Request $request Request object.
         * @return mixed
         */
        public function prepare_item_for_response( $item, $request ) {
/*pretty sure this is where custom fields are enabled, but not sure how to do that*/
        }
    }

2 Answers 2

2

I found out how to solve this by using get_post_meta, but my answer performs multiple calls in each query, so it could probably be optimized to first pull all post meta and then only grab the fields I need.

public function get_items( $request ) {
        $eventargs = array(
            'post_type'      => 'event',
            'posts_per_page' => 3,
            'meta_key'       => 'wpcf-event-start',
            'meta_value'     => current_time( 'timestamp', 1 ),
            'meta_compare'   => '<=',
        );
        $main_events = new WP_Query( $eventargs );
        $events = $main_events->posts;
        foreach($events as $event) {
            foreach( array( 'wpcf-event-start', 'wpcf-event-end', 'wpcf-event-website' ) as $field ){
                $event->$field = get_post_meta( $event->ID, $field, true );
            }
        }

        $listingargs = array(
            'post_type'      => 'listings',
            'posts_per_page' => 3,
            'orderby'        => 'date',
            'order'          => 'DESC',
        );
        $main_listings = new WP_Query( $listingargs );
        $listings = $main_listings->posts;
        foreach($listings as $listing) {
            foreach( array( 'wpcf-listing-hours', 'wpcf-correct-address', 'wpcf-total-ratings', 'wpcf-average-rating' ) as $field ){
                $listing->$field = get_post_meta( $listing->ID, $field, true );
            }
        }

        $ticketsargs = array(
            'post_type'      => 'product',
            'posts_per_page' => 3,
            'orderby'        => 'date',
            'order'          => 'DESC',
            'tax_query'      => array(
                array(
                    'taxonomy'  => 'product_cat',
                    'field'     => 'slug',
                    'terms'     => 'tickets',
                )
            ),

        );
        $main_tickets = new WP_Query( $ticketsargs );
        $tickets = $main_tickets->posts;
        foreach($tickets as $ticket) {
            foreach( array( '_price', '_stock', '_stock_status' ) as $field ){
                $ticket->$field = get_post_meta( $ticket->ID, $field, true );
            }
        }

        $data = array(
            'events'    =>  $events,
            'listings'  =>  $listings,
            'tickets'   =>  $tickets,
        );
        return new WP_REST_Response( $data, 200 );
}
Sign up to request clarification or add additional context in comments.

Comments

0

The post query data doesn't pull custom fields it just pulls the original post data. You would have to use get_post_meta()

However because you are creating a REST API endpoint it would probably be best to do a custom $wpdb query.

<?php 
   $querystr = "
      SELECT $wpdb->posts.*, $wpdb->postmeta.* 
      FROM $wpdb->posts, $wpdb->postmeta
      WHERE $wpdb->posts.ID = $wpdb->postmeta.post_id
      AND $wpdb->posts.post_status = 'publish' 
      AND $wpdb->posts.post_type = 'event'
      ORDER BY $wpdb->posts.post_date DESC 
   ";

   $events = $wpdb->get_results($querystr, OBJECT);
?>

You just have to replace 'event' with whatever post_type you want to use.

5 Comments

I tried this and it returned 38,000 lines of code with a lot of repeating posts. How would we do this with using get_post_meta to simply add on to the query response? I'm a bit more familiar with that
<?php $querystr = " SELECT $wpdb->posts.*, $wpdb->postmeta.* FROM $wpdb->posts LEFT JOIN $WPDB->postsmeta ON $wpdb->posts.ID = $wpdb->postmeta.post_id WHERE $wpdb->posts.post_status = 'publish' AND $wpdb->posts.post_type = 'event' ORDER BY $wpdb->posts.post_date DESC "; $events = $wpdb->get_results($querystr, OBJECT); ?>
Left joining should stop the repeating.
This time it seems to have just dumped a bunch of transient data like "There is a new update available for Wordpress", instead of the post data. I really appreciate the help so far! I have found how to make the custom fields available for each post, but the way I am doing it only makes those fields available, and not the regular fields such as Post ID, etc., unless I add all of those fields to the array, which seems inefficient
After the args code $main_events = new WP_Query( $eventargs ); $events = $main_events->get_posts(); $return = array(); foreach($events as $event) { $newPost = array(); foreach( array( 'wpcf-event-start', 'wpcf-event-end', 'wpcf-event-website' ) as $field ){ $newPost[str_replace('-', '_', $field)] = get_post_meta( $event->ID, $field, true ); } $return[] = $newPost; }

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.