namespace, '/' . $this->rest_base, array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_items' ), 'permission_callback' => array( $this, 'public_permission' ), 'args' => $this->get_collection_params(), ), ) ); // GET /buildings/{id} - Get single building. register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)', array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_item' ), 'permission_callback' => array( $this, 'public_permission' ), 'args' => array( 'id' => array( 'description' => __( 'Building ID.', 'wp-bnb' ), 'type' => 'integer', 'required' => true, 'sanitize_callback' => 'absint', ), ), ), ) ); // GET /buildings/{id}/rooms - Get rooms in building. register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P[\d]+)/rooms', array( array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'get_building_rooms' ), 'permission_callback' => array( $this, 'public_permission' ), 'args' => array( 'id' => array( 'description' => __( 'Building ID.', 'wp-bnb' ), 'type' => 'integer', 'required' => true, 'sanitize_callback' => 'absint', ), 'status' => array( 'description' => __( 'Filter by room status.', 'wp-bnb' ), 'type' => 'string', 'enum' => array( 'available', 'occupied', 'maintenance', 'blocked' ), 'sanitize_callback' => 'sanitize_text_field', ), ), ), ) ); } /** * Get collection of buildings. * * @param WP_REST_Request $request Current request. * @return WP_REST_Response|WP_Error Response object or error. */ public function get_items( $request ) { // Check rate limit. $rate_limit_error = $this->check_rate_limit( $request ); if ( $rate_limit_error ) { return $rate_limit_error; } $pagination = $this->get_pagination_params( $request ); $sorting = $this->get_sorting_params( $request, array( 'title', 'date' ), 'title' ); $args = array( 'post_type' => Building::POST_TYPE, 'post_status' => 'publish', 'posts_per_page' => $pagination['per_page'], 'offset' => $pagination['offset'], 'orderby' => $sorting['orderby'], 'order' => $sorting['order'], ); // Search filter. $search = $request->get_param( 'search' ); if ( $search ) { $args['s'] = $search; } $query = new \WP_Query( $args ); $items = array(); foreach ( $query->posts as $post ) { $items[] = $this->prepare_building_response( $post ); } $response = $this->formatter->collection( $items, $query->found_posts, $pagination['page'], $pagination['per_page'] ); return $this->add_rate_limit_headers( $response, $request ); } /** * Get single building. * * @param WP_REST_Request $request Current request. * @return WP_REST_Response|WP_Error Response object or error. */ public function get_item( $request ) { // Check rate limit. $rate_limit_error = $this->check_rate_limit( $request ); if ( $rate_limit_error ) { return $rate_limit_error; } $id = $request->get_param( 'id' ); $post = get_post( $id ); if ( ! $post || Building::POST_TYPE !== $post->post_type || 'publish' !== $post->post_status ) { return $this->formatter->not_found( __( 'Building', 'wp-bnb' ) ); } $data = $this->prepare_building_response( $post, true ); $response = $this->formatter->success( $data ); return $this->add_rate_limit_headers( $response, $request ); } /** * Get rooms in a building. * * @param WP_REST_Request $request Current request. * @return WP_REST_Response|WP_Error Response object or error. */ public function get_building_rooms( $request ) { // Check rate limit. $rate_limit_error = $this->check_rate_limit( $request ); if ( $rate_limit_error ) { return $rate_limit_error; } $building_id = $request->get_param( 'id' ); $building = get_post( $building_id ); if ( ! $building || Building::POST_TYPE !== $building->post_type || 'publish' !== $building->post_status ) { return $this->formatter->not_found( __( 'Building', 'wp-bnb' ) ); } $args = array( 'post_type' => Room::POST_TYPE, 'post_status' => 'publish', 'posts_per_page' => -1, 'meta_query' => array( array( 'key' => '_bnb_room_building_id', 'value' => $building_id, ), ), 'orderby' => 'meta_value', 'meta_key' => '_bnb_room_room_number', 'order' => 'ASC', ); // Filter by status. $status = $request->get_param( 'status' ); if ( $status ) { $args['meta_query'][] = array( 'key' => '_bnb_room_status', 'value' => $status, ); } $rooms = get_posts( $args ); $items = array(); foreach ( $rooms as $room ) { $items[] = $this->prepare_room_summary( $room ); } $response = $this->formatter->success( $items ); return $this->add_rate_limit_headers( $response, $request ); } /** * Prepare building data for response. * * @param \WP_Post $post Building post object. * @param bool $full Include full details. * @return array Building data. */ private function prepare_building_response( \WP_Post $post, bool $full = false ): array { $data = $this->format_post_base( $post ); // Featured image. $data['featured_image'] = $this->format_featured_image( $post->ID ); $data['permalink'] = get_permalink( $post->ID ); // Address. $data['address'] = array( 'street' => get_post_meta( $post->ID, '_bnb_building_street', true ), 'street2' => get_post_meta( $post->ID, '_bnb_building_street2', true ), 'city' => get_post_meta( $post->ID, '_bnb_building_city', true ), 'state' => get_post_meta( $post->ID, '_bnb_building_state', true ), 'postal_code' => get_post_meta( $post->ID, '_bnb_building_zip', true ), 'country' => get_post_meta( $post->ID, '_bnb_building_country', true ), ); // Contact. $data['contact'] = array( 'phone' => get_post_meta( $post->ID, '_bnb_building_phone', true ), 'email' => get_post_meta( $post->ID, '_bnb_building_email', true ), 'website' => get_post_meta( $post->ID, '_bnb_building_website', true ), ); // Details. $data['details'] = array( 'rooms_count' => (int) get_post_meta( $post->ID, '_bnb_building_total_rooms', true ), 'floors' => (int) get_post_meta( $post->ID, '_bnb_building_floors', true ), 'year_built' => (int) get_post_meta( $post->ID, '_bnb_building_year_built', true ), 'check_in_time' => get_post_meta( $post->ID, '_bnb_building_check_in_time', true ) ?: '14:00', 'check_out_time' => get_post_meta( $post->ID, '_bnb_building_check_out_time', true ) ?: '11:00', ); // Count actual rooms. $actual_rooms = Room::get_rooms_for_building( $post->ID ); $data['details']['actual_rooms_count'] = count( $actual_rooms ); // Full address formatted. if ( $full ) { $data['address']['formatted'] = Building::get_formatted_address( $post->ID ); // Country name. $countries = Building::get_countries(); $country_code = $data['address']['country']; $data['address']['country_name'] = $countries[ $country_code ] ?? $country_code; } // Add HATEOAS links. $data['_links'] = array( 'self' => array( array( 'href' => rest_url( $this->namespace . '/buildings/' . $post->ID ) ), ), 'rooms' => array( array( 'href' => rest_url( $this->namespace . '/buildings/' . $post->ID . '/rooms' ) ), ), ); return $data; } /** * Prepare room summary for building rooms list. * * @param \WP_Post $room Room post object. * @return array Room summary data. */ private function prepare_room_summary( \WP_Post $room ): array { return array( 'id' => $room->ID, 'title' => get_the_title( $room ), 'slug' => $room->post_name, 'permalink' => get_permalink( $room->ID ), 'room_number' => get_post_meta( $room->ID, '_bnb_room_room_number', true ), 'floor' => (int) get_post_meta( $room->ID, '_bnb_room_floor', true ), 'capacity' => (int) get_post_meta( $room->ID, '_bnb_room_capacity', true ), 'status' => get_post_meta( $room->ID, '_bnb_room_status', true ) ?: 'available', 'thumbnail' => get_the_post_thumbnail_url( $room->ID, 'thumbnail' ) ?: null, '_links' => array( 'self' => array( array( 'href' => rest_url( $this->namespace . '/rooms/' . $room->ID ) ), ), ), ); } }