setup_hooks(); } /** * Set up hooks for various purposes. * * This method adds hooks for different purposes as needed. * * @since 1.0.0 * * @return void */ protected function setup_hooks(): void { add_action( 'rest_api_init', array( $this, 'register_endpoints' ) ); add_action( 'gatherpress_send_emails', array( $this, 'handle_email_send_action' ), 10, 3 ); add_filter( sprintf( 'rest_prepare_%s', Event::POST_TYPE ), array( $this, 'prepare_event_data' ) ); } /** * Registers REST API endpoints for GatherPress events. * * Registers various REST API endpoints for interacting with GatherPress events. * The registered routes include endpoints for event creation, retrieval, updating, and deletion. * * @since 1.0.0 * * @return void */ public function register_endpoints(): void { // All event routes. $routes = $this->get_event_routes(); foreach ( $routes as $route ) { register_rest_route( sprintf( '%s/event', GATHERPRESS_REST_NAMESPACE ), sprintf( '/%s', $route['route'] ), $route['args'] ); } } /** * Get the event routes. * * Retrieves an array of REST API routes for GatherPress events. * * @since 1.0.0 * * @return array[] An array of route definitions for GatherPress events. */ protected function get_event_routes(): array { return array( $this->email_route(), $this->rsvp_route(), $this->rsvp_form_route(), $this->rsvp_status_html_route(), $this->rsvp_responses_route(), $this->events_list_route(), $this->nonce_route(), ); } /** * Define the REST route for sending event-related emails. * * This method sets up the REST route for sending emails related to an event. * * @since 1.0.0 * * @return array The REST route configuration. */ protected function email_route(): array { return array( 'route' => 'email', 'args' => array( 'methods' => WP_REST_Server::EDITABLE, 'callback' => array( $this, 'email' ), 'permission_callback' => static function (): bool { return current_user_can( 'edit_posts' ); }, 'args' => array( 'post_id' => array( 'required' => true, 'validate_callback' => array( Validate::class, 'event_post_id' ), ), 'message' => array( 'required' => false, 'validate_callback' => 'sanitize_text_field', ), 'send' => array( 'required' => true, 'validate_callback' => array( Validate::class, 'send' ), ), ), ), ); } /** * Define REST API route for generating nonce. * * Creates a publicly accessible endpoint that generates a fresh nonce * for authenticated REST API requests. * * @since 1.0.0 * * @return array Route configuration array. */ protected function nonce_route(): array { return array( 'route' => 'nonce', 'args' => array( 'methods' => WP_REST_Server::READABLE, 'callback' => static function () { // Short-term caching (30 seconds) to prevent endpoint hammering while maintaining security. // WordPress nonces are valid for ~12 hours, so 30 seconds of caching has no UX impact // but protects against rapid successive requests that could overwhelm the server. header( 'Cache-Control: private, max-age=30' ); header( 'Expires: ' . gmdate( 'D, d M Y H:i:s', time() + 30 ) . ' GMT' ); // Ensure proper user authentication for nonce generation. Utility::ensure_user_authentication(); $response = array( 'nonce' => wp_create_nonce( 'wp_rest' ), ); return new WP_REST_Response( $response ); }, 'permission_callback' => '__return_true', ), ); } /** * Define the REST route for updating event RSVP status. * * This method sets up the REST route for updating the RSVP status of an event. * * @since 1.0.0 * * @return array The REST route configuration. */ protected function rsvp_route(): array { return array( 'route' => 'rsvp', 'args' => array( 'methods' => WP_REST_Server::EDITABLE, 'callback' => array( $this, 'update_rsvp' ), 'permission_callback' => static function ( WP_Rest_Request $request ): bool { $unparsed_token = $request->get_param( Rsvp_Token::NAME ); $rsvp_token = Rsvp_Token::from_token_string( $unparsed_token ); if ( $rsvp_token ) { return true; } return is_user_logged_in(); }, 'args' => array( 'post_id' => array( 'required' => true, 'validate_callback' => array( Validate::class, 'event_post_id' ), ), 'rsvp_token' => array( 'required' => false, 'validate_callback' => static function ( $param ): bool { return ! empty( Rsvp_Token::parse_token_string( $param ) ); }, ), 'status' => array( 'required' => true, 'validate_callback' => array( Validate::class, 'rsvp_status' ), ), ), ), ); } /** * Define the REST route for handling RSVP form submissions via Ajax. * * This method sets up the REST route for processing RSVP form submissions * dynamically via Ajax while maintaining the same functionality as the * traditional comment-based form submission system. * * @since 1.0.0 * * @return array The REST route configuration. */ protected function rsvp_form_route(): array { return array( 'route' => 'rsvp-form', 'args' => array( 'methods' => WP_REST_Server::EDITABLE, 'callback' => array( $this, 'handle_rsvp_form_submission' ), 'permission_callback' => '__return_true', 'args' => array( 'comment_post_ID' => array( 'required' => true, 'validate_callback' => array( Validate::class, 'event_post_id' ), ), 'author' => array( 'required' => true, 'validate_callback' => function ( $param ) { return ! empty( sanitize_text_field( $param ) ); }, ), 'email' => array( 'required' => true, 'validate_callback' => function ( $param ) { return is_email( $param ); }, ), 'gatherpress_form_schema_id' => array( 'required' => false, 'validate_callback' => function ( $param ) { return is_string( $param ) && preg_match( '/^form_\d+$/', $param ); }, ), 'gatherpress_event_updates_opt_in' => array( 'required' => false, 'validate_callback' => array( Validate::class, 'boolean' ), ), 'gatherpress_rsvp_form_guests' => array( 'required' => false, 'validate_callback' => array( Validate::class, 'non_negative_number' ), ), 'gatherpress_rsvp_form_anonymous' => array( 'required' => false, 'validate_callback' => array( Validate::class, 'boolean' ), ), ), ), ); } /** * Define the REST route for rendering RSVP block HTML. * * This method registers a REST API route for dynamically generating HTML markup * for RSVP blocks based on the provided block data and post ID. * The generated HTML reflects the current RSVP status and can be used * to re-render block content when status changes occur. * * @since 1.0.0 * * @return array The REST route configuration. */ protected function rsvp_status_html_route(): array { return array( 'route' => 'rsvp-status-html', 'args' => array( 'methods' => WP_REST_Server::EDITABLE, 'callback' => array( $this, 'rsvp_status_html' ), 'permission_callback' => '__return_true', 'args' => array( 'post_id' => array( 'required' => true, 'validate_callback' => array( Validate::class, 'event_post_id' ), ), 'status' => array( 'required' => true, 'validate_callback' => array( Validate::class, 'rsvp_status' ), ), 'block_data' => array( 'required' => true, 'validate_callback' => array( Validate::class, 'block_data' ), ), 'limit_enabled' => array( 'required' => false, 'validate_callback' => array( Validate::class, 'boolean' ), ), 'limit' => array( 'required' => false, 'validate_callback' => array( Validate::class, 'positive_number' ), ), ), ), ); } /** * Get route configuration for RSVP responses endpoint. * * Defines REST route configuration to fetch RSVP response data for an event post. * Endpoint requires post_id parameter which must validate as an event post type. * * @since 1.0.0 * * @return array Route configuration with path, methods, callback and arguments. */ protected function rsvp_responses_route(): array { return array( 'route' => 'rsvp-responses', 'args' => array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'rsvp_responses' ), 'permission_callback' => '__return_true', 'args' => array( 'post_id' => array( 'required' => true, 'validate_callback' => array( Validate::class, 'event_post_id' ), ), ), ), ); } /** * Define the REST route for retrieving a list of events. * * This method sets up the REST route for retrieving a list of events based on specified parameters. * * @since 1.0.0 * * @return array The REST route configuration. */ protected function events_list_route(): array { return array( 'route' => 'events-list', 'args' => array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'events_list' ), 'permission_callback' => '__return_true', 'args' => array( 'event_list_type' => array( 'required' => true, 'validate_callback' => array( Validate::class, 'event_list_type' ), ), 'max_number' => array( 'required' => true, 'validate_callback' => array( Validate::class, 'positive_number' ), ), 'datetime_format' => array( 'required' => false, ), 'topics' => array( 'required' => false, ), ), ), ); } /** * Send an event email notification to members. * * This method allows sending an email notification about a specific event to members. * It checks the user's capability to edit posts before initiating the email sending process. * If the user doesn't have the required capability, the method returns a response with 'success' set to false. * * @since 1.0.0 * * @param WP_REST_Request $request Contains data from the request. * @return WP_REST_Response The response indicating the success of the email scheduling process. */ public function email( WP_REST_Request $request ): WP_REST_Response { $params = $request->get_params(); $post_id = intval( $params['post_id'] ); $message = $params['message'] ?? ''; $send = $params['send']; $success = wp_schedule_single_event( time(), 'gatherpress_send_emails', array( $post_id, $send, $message ) ); $response = array( 'success' => $success, ); return new WP_REST_Response( $response ); } /** * Hooked method to trigger the sending of related emails. * * This method hooks into a WordPress action, triggering the `send_emails` method * to send emails to selected members. It doesn't return any value, * as it's intended to be called by an action hook. * * @since 1.0.0 * * @param int $post_id Post ID. * @param array $send Members to send the email to. * @param string $message Optional message to include in the email. * @return void */ public function handle_email_send_action( int $post_id, array $send, string $message ): void { $this->send_emails( $post_id, $send, $message ); } /** * Send emails to selected members. * * This method is responsible for sending emails to specific members. It checks if the given * `$post_id` corresponds to a specific post type, retrieves the list of members to email, and sends the email with * the appropriate subject, body, and headers. * * @since 1.0.0 * * @param int $post_id Post ID. * @param array $send Members to send the email to. * @param string $message Optional message to include in the email. * @return bool True if emails were successfully sent, false otherwise. */ public function send_emails( int $post_id, array $send, string $message ): bool { if ( Event::POST_TYPE !== get_post_type( $post_id ) ) { return false; } // Keep the currently logged-in user. $current_user = wp_get_current_user(); $recipients = $this->get_recipients( $send, $post_id ); foreach ( $recipients as $recipient ) { // Check opt-in preference based on recipient type. if ( $recipient['is_user'] ) { // For WordPress users, use the centralized helper method. $user = User::get_instance(); if ( ! $user->has_event_updates_opt_in( $recipient['user_id'] ) ) { continue; } } elseif ( '0' === get_comment_meta( $recipient['comment_id'], 'gatherpress_event_updates_opt_in', true ) ) { // For non-user RSVPs, check comment meta. continue; } if ( $recipient['email'] ) { $to = $recipient['email']; $switched_locale = false; // Set the current user context for templating. if ( $recipient['is_user'] ) { $switched_locale = switch_to_user_locale( $recipient['user_id'] ); // Set the current user to the actual member to mail to, // to make sure the GatherPress filters for date- and time- format, as well as the users timezone, // are recognized by the functions inside render_template(). wp_set_current_user( $recipient['user_id'] ); } $subject = sprintf( // translators: %s: event title. _x( '📅 %s', 'Email notification subject with event title', 'gatherpress' ), get_the_title( $post_id ) ); $body = Utility::render_template( sprintf( '%s/includes/templates/admin/emails/event-email.php', GATHERPRESS_CORE_PATH ), array( 'event_id' => $post_id, 'message' => $message, ), ); $headers = array( 'Content-Type: text/html; charset=UTF-8' ); $subject = stripslashes_deep( html_entity_decode( $subject, ENT_QUOTES, 'UTF-8' ) ); // Reset the current user to the editor sending the email. wp_set_current_user( $current_user->ID ); wp_mail( $to, $subject, $body, $headers ); if ( $switched_locale ) { restore_previous_locale(); } } } return true; } /** * Get the list of recipients to send event-related emails to. * * This method retrieves the list of recipients to whom event-related emails should be sent * based on the given `$send` parameter and the specified event `$post_id`. * It checks the `$send` array for specific email recipient categories, * such as 'all,' 'attending,' 'waiting_list,' and 'not_attending,' and compiles a unified list of recipients * that includes both WordPress users and non-user RSVPs with their email addresses and metadata. * * @since 1.0.0 * * @param array $send An array specifying who to send emails to. * @param int $post_id The Event Post ID. * @return array An array containing unified recipient data for both users and non-users. */ public function get_recipients( array $send, int $post_id ): array { $recipients = array(); $rsvp = new Rsvp( $post_id ); $all_responses = $rsvp->responses(); $rsvp_query = Rsvp_Query::get_instance(); // Handle 'all' members (WordPress users only). if ( ! empty( $send['all'] ) ) { $users = get_users(); foreach ( $users as $user ) { $recipients[] = array( 'is_user' => true, 'user_id' => $user->ID, 'comment_id' => 0, 'email' => $user->user_email, 'name' => $user->display_name, ); } } // Collect comment IDs for RSVP statuses. $comment_ids = array(); foreach ( array( 'attending', 'waiting_list', 'not_attending' ) as $status ) { if ( ! empty( $send[ $status ] ) ) { foreach ( $all_responses[ $status ]['records'] as $record ) { $comment_ids[] = $record['commentId']; } } } if ( empty( $comment_ids ) ) { return $recipients; } // Get full comment data for the RSVPs. $comments = $rsvp_query->get_rsvps( array( 'post_id' => $post_id, 'status' => 'approve', 'comment__in' => $comment_ids, ) ); foreach ( $comments as $comment ) { $user_id = intval( $comment->user_id ); $user = false; $email = $comment->comment_author_email; $name = $comment->comment_author; if ( $user_id ) { $user = get_userdata( $user_id ); if ( $user ) { $email = $user->user_email; $name = $user->display_name; } } // Skip if no email address. if ( empty( $email ) ) { continue; } $recipients[] = array( 'is_user' => (bool) $user_id, 'user_id' => $user_id, 'comment_id' => $comment->comment_ID, 'email' => $email, 'name' => $name, ); } return $recipients; } /** * Retrieve a list of events based on specified criteria. * * This method handles the retrieval of a list of events based on the parameters provided in the REST API request. * It takes the `event_list_type` to determine whether to fetch upcoming or past events, the `max_number` to * limit the number of events in the response, and optional `topics` and `venues` to filter events by specific * topic and venue slugs. * * @since 1.0.0 * * @param WP_REST_Request $request Contains data from the REST API request. * @return WP_REST_Response The REST API response containing an array of event data. * * @throws Exception If there is an issue while retrieving the list of events. */ public function events_list( WP_REST_Request $request ): WP_REST_Response { $params = $request->get_params(); $event_list_type = $params['event_list_type']; $max_number = $this->max_number( (int) $params['max_number'], 5 ); $datetime_format = ! empty( $params['datetime_format'] ) ? $params['datetime_format'] : 'D, M j, Y, g:i a T'; $posts = array(); $topics = array(); $venues = array(); if ( ! empty( $params['topics'] ) ) { $topics = array_map( static function ( $slug ): string { return sanitize_key( $slug ); }, explode( ',', $params['topics'] ) ); } if ( ! empty( $params['venues'] ) ) { $venues = array_map( static function ( $slug ): string { return sanitize_key( $slug ); }, explode( ',', $params['venues'] ) ); } $query = Event_Query::get_instance()->get_events_list( $event_list_type, $max_number, $topics, $venues ); if ( $query->have_posts() ) { foreach ( $query->posts as $post_id ) { $event = new Event( $post_id ); $venue_information = $event->get_venue_information(); $user_identifier = Rsvp_Setup::get_instance()->get_user_identifier(); $current_user_rsvp = ( $event->rsvp ) ? $event->rsvp->get( $user_identifier ) : ''; $posts[] = array( 'ID' => $post_id, 'datetime_start' => $event->get_datetime_start( $datetime_format ), 'datetime_end' => $event->get_datetime_end( $datetime_format ), 'permalink' => get_the_permalink( $post_id ), 'title' => get_the_title( $post_id ), 'excerpt' => get_the_excerpt( $post_id ), 'featured_image' => get_the_post_thumbnail( $post_id, 'medium' ), 'featured_image_large' => get_the_post_thumbnail( $post_id, 'large' ), 'featured_image_thumbnail' => get_the_post_thumbnail( $post_id, 'thumbnail' ), 'enable_anonymous_rsvp' => (bool) get_post_meta( $post_id, 'gatherpress_enable_anonymous_rsvp', true ), 'responses' => ( $event->rsvp ) ? $event->rsvp->responses() : array(), 'current_user' => ( $current_user_rsvp ) ? $current_user_rsvp : '', 'venue' => ( $venue_information['name'] ) ? $event->get_venue_information() : null, ); } } wp_reset_postdata(); return new WP_REST_Response( $posts ); } /** * Ensure that the provided number does not exceed the maximum number allowed. * * This method checks if the provided `$number` is greater than the specified `$max_number` and * returns the lower of the two values to ensure it does not exceed the maximum limit. * * @since 1.0.0 * * @param int $number The actual number. * @param int $max_number The maximum number allowed. * @return int The sanitized number, ensuring it does not exceed the maximum limit. */ protected function max_number( int $number, int $max_number ): int { if ( $max_number < $number ) { $number = $max_number; } return $number; } /** * Update the RSVP status for a user to an event. * * This method handles the update of the RSVP status for a user to an event, including handling guest count. * It checks the user's permissions and the event's status to ensure a valid update. If the update is successful, * it returns relevant information, including the updated status, guest count, and responses. * * @since 1.0.0 * * @param WP_REST_Request $request Contains data from the request. * @return WP_REST_Response An instance of WP_REST_Response containing the response data. */ public function update_rsvp( WP_REST_Request $request ): WP_REST_Response { // Prevent caching of RSVP updates. nocache_headers(); $params = $request->get_params(); $success = false; $current_user_id = get_current_user_id(); $blog_id = get_current_blog_id(); $user_id = isset( $params['user_id'] ) ? intval( $params['user_id'] ) : $current_user_id; $post_id = intval( $params['post_id'] ); $status = sanitize_key( $params['status'] ); $guests = intval( $params['guests'] ?? 0 ); $anonymous = intval( $params['anonymous'] ?? 0 ); $unparsed_token = sanitize_text_field( $params['rsvp_token'] ?? '' ); $event = new Event( $post_id ); // If managing user is adding someone to an event. if ( $current_user_id && $user_id && $current_user_id !== $user_id ) { if ( ! current_user_can( 'edit_posts' ) ) { $user_id = 0; } } else { $user_id = $current_user_id; } if ( intval( $user_id ) && ! is_user_member_of_blog( $user_id ) ) { add_user_to_blog( $blog_id, $user_id, 'subscriber' ); } $user_identifier = $user_id; if ( ! empty( $unparsed_token ) ) { $rsvp_token = Rsvp_Token::from_token_string( $unparsed_token ); if ( $rsvp_token ) { $user_identifier = $rsvp_token->get_email(); } } if ( $user_identifier && ( is_user_member_of_blog( $user_identifier ) || is_email( $user_identifier ) ) && ! $event->has_event_past() ) { if ( 'attending' !== $status ) { $guests = 0; } $user_record = $event->rsvp->save( $user_identifier, $status, $anonymous, $guests ); $status = $user_record['status']; $guests = $user_record['guests']; if ( in_array( $status, $event->rsvp->statuses, true ) ) { $success = true; } } $response = array( 'event_id' => $post_id, 'success' => $success, 'status' => $status, 'guests' => $guests, 'anonymous' => $anonymous, 'responses' => $event->rsvp->responses(), 'online_link' => $event->maybe_get_online_event_link(), ); return new WP_REST_Response( $response ); } /** * Handles rendering RSVP block HTML via a REST API endpoint. * * This method dynamically generates HTML markup for RSVP blocks based on the * provided block data and the responses for a given post ID. It processes the * RSVP responses and renders the corresponding content using the block template. * Each response is wrapped in its own container with data attributes to facilitate * interactivity and styling. * * @since 1.0.0 * * @param WP_REST_Request $request The REST API request object containing parameters: * - post_id (int): The ID of the post associated with the RSVP. * - block_data (string): JSON-encoded block data used to render the RSVP content. * * @return WP_REST_Response The REST API response containing: * - success (bool): Whether the content was successfully generated. * - content (string): The dynamically rendered HTML markup for the RSVP responses. */ public function rsvp_status_html( WP_REST_Request $request ): WP_REST_Response { // Prevent caching for logged-in users or users with valid RSVP tokens. $unparsed_token = $request->get_param( Rsvp_Token::NAME ); $rsvp_token = Rsvp_Token::from_token_string( $unparsed_token ); if ( is_user_logged_in() || $rsvp_token ) { nocache_headers(); } $rsvp_template = Rsvp_Template::get_instance(); $params = $request->get_params(); $post_id = intval( $params['post_id'] ); $status = $params['status']; $block_data = $params['block_data']; $block_data = json_decode( $block_data, true ); $rsvp = new Rsvp( $post_id ); $responses = $rsvp->responses(); $content = ''; // @todo set this up... $args = array( 'limit_enabled' => (bool) $params['limit_enabled'], 'limit' => (int) $params['limit'], ); if ( ! empty( $responses[ $status ] ) ) { foreach ( $responses[ $status ]['records'] as $key => $record ) { $args['index'] = $key; $content .= $rsvp_template->get_block_content( $block_data, $record['commentId'], $args ); } } $success = true; $response = array( 'success' => $success, 'content' => $content, 'responses' => $responses, ); return new WP_REST_Response( $response ); } /** * Handle RSVP form submission via Ajax. * * This method processes RSVP form submissions received via Ajax, * using the centralized Rsvp_Form class for consistency. * * @since 1.0.0 * * @param WP_REST_Request $request The REST API request object. * @return WP_REST_Response The response indicating success or failure. */ public function handle_rsvp_form_submission( WP_REST_Request $request ): WP_REST_Response { // Prevent caching of RSVP form submission responses. nocache_headers(); $params = $request->get_params(); // Prepare data for the RSVP processor. $data = array( 'post_id' => intval( $params['comment_post_ID'] ), 'author' => $params['author'] ?? '', 'email' => $params['email'] ?? '', 'gatherpress_event_updates_opt_in' => $request->get_param( 'gatherpress_event_updates_opt_in' ), 'gatherpress_rsvp_guests' => $request->get_param( 'gatherpress_rsvp_form_guests' ), 'gatherpress_rsvp_anonymous' => $request->get_param( 'gatherpress_rsvp_form_anonymous' ), 'gatherpress_form_schema_id' => $request->get_param( 'gatherpress_form_schema_id' ), ); // Add custom fields to data. foreach ( $params as $key => $value ) { if ( 0 === strpos( $key, 'gatherpress_custom_' ) ) { $data[ $key ] = $value; } } // Also include custom fields defined in form schema. $form_schema_id = $data['gatherpress_form_schema_id'] ?? ''; if ( ! empty( $form_schema_id ) ) { $post_id = $data['post_id']; $schemas = get_post_meta( $post_id, 'gatherpress_rsvp_form_schemas', true ); if ( is_array( $schemas ) && isset( $schemas[ $form_schema_id ]['fields'] ) ) { $fields = $schemas[ $form_schema_id ]['fields']; foreach ( $fields as $field_name => $field_config ) { if ( isset( $params[ $field_name ] ) ) { $data[ $field_name ] = $params[ $field_name ]; } } } } // Check if event has passed - prevent RSVPs to past events. $event = new Event( $data['post_id'] ); if ( $event->has_event_past() ) { $response = array( 'success' => false, 'message' => __( 'Registration for this event is now closed.', 'gatherpress' ), ); return new WP_REST_Response( $response, 400 ); } // Process the RSVP using the centralized processor. $rsvp_form = Rsvp_Form_Core::get_instance(); $result = $rsvp_form->process_rsvp( $data ); // Handle success case - get updated responses. if ( $result['success'] ) { $event = new Event( $data['post_id'] ); $responses = $event->rsvp->responses(); $response = array( 'success' => true, 'message' => $result['message'], 'comment_id' => $result['comment_id'], 'responses' => $responses, ); return new WP_REST_Response( $response ); } // Handle error case. $error_code = $result['error_code'] ?? 500; $response = array( 'success' => false, 'message' => $result['message'], ); return new WP_REST_Response( $response, $error_code ); } /** * Handle RSVP responses REST endpoint request. * * Retrieves RSVP response data for a given event post ID. Validates that the post * is an event type before returning response data. * * @since 1.0.0 * * @param WP_REST_Request $request REST API request object containing post_id parameter. * @return WP_REST_Response Response containing success status and RSVP data. */ public function rsvp_responses( WP_REST_Request $request ): WP_REST_Response { // Prevent caching for logged-in users or users with valid RSVP tokens. $unparsed_token = $request->get_param( Rsvp_Token::NAME ); $rsvp_token = Rsvp_Token::from_token_string( $unparsed_token ); if ( is_user_logged_in() || $rsvp_token ) { nocache_headers(); } $params = $request->get_params(); $post_id = intval( $params['post_id'] ); $success = false; $responses = array(); if ( Event::POST_TYPE === get_post_type( $post_id ) ) { $success = true; $rsvp = new Rsvp( $post_id ); $responses = $rsvp->responses(); } $response = array( 'success' => $success, 'data' => $responses, ); return new WP_REST_Response( $response ); } /** * Prepare event data for the response. * * This method prepares and enhances the event data for the response object. * It retrieves additional meta information, such as the online event link, based on specific conditions. * The enhanced data is then added to the response. * * @since 1.0.0 * * @param WP_REST_Response $response The response object containing event data. * @return WP_REST_Response The response object with enhanced event data. */ public function prepare_event_data( WP_REST_Response $response ): WP_REST_Response { $event = new Event( $response->data['id'] ); // Retrieve the online event link only if: // - The user is attending the event. // - The event is in the future. // - The code is not in an admin context. $response->data['meta']['online_event_link'] = $event->maybe_get_online_event_link(); return $response; } }