setup_hooks(); } /** * Gets the per page option name for RSVP list table. * * @since 1.0.0 * * @return string The per page option name. */ private function get_per_page_option(): string { return sprintf( '%s_per_page', Rsvp::COMMENT_TYPE ); } /** * 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( 'init', array( $this, 'register_taxonomy' ) ); add_action( 'init', array( $this, 'handle_rsvp_token' ) ); add_action( 'wp_after_insert_post', array( $this, 'maybe_process_waiting_list' ) ); add_action( 'admin_menu', array( $this, 'add_rsvp_submenu_page' ) ); add_filter( 'comment_notification_recipients', array( $this, 'remove_rsvp_notification_emails' ), 10, 2 ); add_filter( sprintf( 'set_screen_option_%s_per_page', Rsvp::COMMENT_TYPE ), array( $this, 'set_rsvp_screen_options' ), 10, 3 ); add_filter( 'parent_file', array( $this, 'highlight_admin_menu' ) ); add_filter( 'get_comments_number', array( $this, 'adjust_comments_number' ), 10, 2 ); add_filter( 'comment_text', array( $this, 'maybe_hide_rsvp_comment_content' ), 10, 2 ); } /** * Register custom comment taxonomy for RSVPs. * * Registers a custom taxonomy 'gatherpress_rsvp' for managing RSVP related functionalities * specifically for comments. * * @since 1.0.0 * * @return void */ public function register_taxonomy(): void { register_taxonomy( Rsvp::TAXONOMY, 'comment', array( 'labels' => array(), 'hierarchical' => false, 'public' => true, 'show_ui' => false, 'show_admin_column' => false, 'query_var' => true, 'publicly_queryable' => false, 'show_in_rest' => true, ) ); } /** * Get user identifier for RSVP operations. * * Returns the current user ID if logged in, or email address from * a valid RSVP token if accessing via magic link. * * @since 1.0.0 * * @return string|int User ID if logged in, email address if via token, or 0 if neither. */ public function get_user_identifier() { $user_identifier = get_current_user_id(); $rsvp_token = Rsvp_Token::from_url_parameter(); if ( $rsvp_token && ! empty( $rsvp_token->get_comment() ) ) { $user_identifier = $rsvp_token->get_email(); } return $user_identifier; } /** * Adjusts the number of comments displayed for event posts. * * Retrieves and returns the count of approved RSVP comments for event posts. * * @since 1.0.0 * * @param int $comments_number The original number of comments. * @param int $post_id The ID of the post. * * @return int Adjusted number of comments. */ public function adjust_comments_number( int $comments_number, int $post_id ): int { if ( Event::POST_TYPE !== get_post_type( $post_id ) ) { return $comments_number; } $comment_count = get_comment_count( $post_id ); return $comment_count['approved']; } /** * Process the waiting list for an event after it has been saved. * * Checks if the saved post is an event and not an autosave, * then processes any waiting list entries if applicable. * * @since 1.0.0 * * @param int $post_id The ID of the post being saved. * * @return void */ public function maybe_process_waiting_list( int $post_id ): void { if ( Event::POST_TYPE !== get_post_type( $post_id ) ) { return; } $rsvp = new Rsvp( $post_id ); $rsvp->check_waiting_list(); } /** * Adds a submenu page for managing GatherPress RSVPs. * * This method adds a submenu page under the Events menu in the WordPress admin. * The page provides a dedicated interface for viewing and managing RSVPs * to GatherPress events, with capabilities similar to the WordPress comments * page but specifically tailored for RSVPs. * * @since 1.0.0 * * @return void */ public function add_rsvp_submenu_page(): void { $hook = add_submenu_page( sprintf( 'edit.php?post_type=%s', Event::POST_TYPE ), __( 'RSVPs', 'gatherpress' ), __( 'RSVPs', 'gatherpress' ), Rsvp::CAPABILITY, Rsvp::COMMENT_TYPE, array( $this, 'render_rsvp_admin_page' ), 2 ); $this->list_table = new RSVP_List_Table(); add_action( sprintf( 'load-%s', $hook ), array( $this, 'setup_rsvp_list_table_screen_options' ) ); } /** * Sets up screen options for the RSVP list table. * * This method registers the per-page screen option and column options * for the RSVP list table in the WordPress admin. * * @since 1.0.0 * * @return void */ public function setup_rsvp_list_table_screen_options(): void { add_screen_option( 'per_page', array( 'label' => __( 'RSVPs per page', 'gatherpress' ), 'default' => RSVP_List_Table::DEFAULT_PER_PAGE, 'option' => $this->get_per_page_option(), ) ); $this->list_table->register_column_options(); } /** * Renders the RSVP admin page in the WordPress dashboard. * * This method displays the custom admin interface for managing GatherPress RSVPs. * It initializes and displays the RSVP_List_Table which contains all RSVPs * with options for filtering, bulk actions, and individual RSVP management. * * @since 1.0.0 * * @return void */ public function render_rsvp_admin_page(): void { // phpcs:disable WordPress.Security.NonceVerification.Recommended if ( ! current_user_can( Rsvp::CAPABILITY ) ) { wp_die( esc_html__( 'Sorry, you are not allowed to manage RSVPs.', 'gatherpress' ), 403 ); } $rsvp_table = new RSVP_List_Table(); $search_term = isset( $_REQUEST['s'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['s'] ) ) : ''; $status = isset( $_REQUEST['status'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['status'] ) ) : ''; $event = isset( $_REQUEST['event'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['event'] ) ) : ''; Utility::render_template( sprintf( '%s/includes/templates/admin/rsvp/list-table.php', GATHERPRESS_CORE_PATH ), array( 'rsvp_table' => $rsvp_table, 'search_term' => $search_term, 'status' => $status, 'event' => $event, ), true ); // phpcs:enable WordPress.Security.NonceVerification.Recommended } /** * Filters the comment content to hide private notes for non-moderators. * * Checks if the comment is a GatherPress RSVP comment and applies visibility * rules based on user permissions. Returns empty string for non-moderators * to protect private RSVP information. * * @since 1.0.0 * * @param string $comment_content Text of the comment. * @param WP_Comment|null $comment The comment object. * * @return string Filtered comment text. */ public function maybe_hide_rsvp_comment_content( string $comment_content, ?WP_Comment $comment ): string { if ( null === $comment || Rsvp::COMMENT_TYPE !== $comment->comment_type ) { return $comment_content; } if ( ! current_user_can( Rsvp::CAPABILITY ) ) { return ''; } return $comment_content; } /** * Registers screen options for the RSVP administration page. * * Adds options to control the number of RSVPs displayed per page and * which columns are visible in the table. These settings are accessible * via the Screen Options tab on the RSVP admin page. * * @since 1.0.0 * * @return void */ public function add_rsvp_screen_options(): void { // phpcs:disable WordPress.Security.NonceVerification.Recommended if ( ! isset( $_GET['page'] ) || Rsvp::COMMENT_TYPE !== $_GET['page'] ) { return; } add_screen_option( 'per_page', array( 'label' => __( 'RSVPs per page', 'gatherpress' ), 'default' => RSVP_List_Table::DEFAULT_PER_PAGE, 'option' => $this->get_per_page_option(), ) ); $screen = get_current_screen(); if ( $screen ) { $screen->add_option( 'columns', array() ); } // phpcs:enable WordPress.Security.NonceVerification.Recommended } /** * Saves user preferences for per-page display options. * * Processes and saves the screen options for controlling how many RSVPs * display per page in the admin table. Only processes options relevant * to the RSVP listing page. * * @since 1.0.0 * * @param mixed $status Screen option value. Default false to skip. * @param string $option The option name. * @param mixed $value The option value. * * @return mixed The screen option value or false to use default. */ public function set_rsvp_screen_options( $status, $option, $value ) { if ( $this->get_per_page_option() === $option ) { return $value; } return $status; } /** * Ensures the correct parent menu item is highlighted for the RSVP admin page. * * When viewing the RSVP admin page, this function sets the appropriate parent * menu item to be highlighted in the admin menu. It also adds a filter to * set the correct submenu item. * * @since 1.0.0 * * @param string $parent_file The current parent file. * * @return string Modified parent file path to highlight the correct menu item. */ public function highlight_admin_menu( string $parent_file ): string { global $plugin_page; if ( isset( $plugin_page ) && Rsvp::COMMENT_TYPE === $plugin_page ) { add_filter( 'submenu_file', array( $this, 'set_submenu_file' ) ); return sprintf( 'edit.php?post_type=%s', Event::POST_TYPE ); } return $parent_file; } /** * Sets the active submenu file for the RSVP admin page. * * Ensures the RSVP submenu item is correctly highlighted when viewing * the RSVP admin page. Works with WordPress admin menu highlighting * system to indicate the current active page. * * @since 1.0.0 * * @return string The submenu file slug to mark as active. */ public function set_submenu_file(): string { return Rsvp::COMMENT_TYPE; } /** * Removes email notifications for RSVP comments. * * Prevents WordPress from sending standard comment notification emails for RSVP submissions. * RSVPs should not trigger the same notifications as regular comments since they are * specialized interactions with events rather than commentary. This avoids confusing * event authors with irrelevant comment notifications. * * @todo Implement custom RSVP notification emails for event organizers with relevant * information about new RSVPs and changes to existing RSVPs. * * @since 1.0.0 * * @param array $emails Array of email addresses to notify. * @param string $comment_id The comment ID. * * @return array Empty array for RSVP comments, original array otherwise. */ public function remove_rsvp_notification_emails( array $emails, string $comment_id ): array { if ( get_comment_type( (int) $comment_id ) !== Rsvp::COMMENT_TYPE ) { return $emails; } return array(); } /** * Handle RSVP token from URL and approve associated comment. * * Validates the RSVP token from the URL parameter and automatically * approves the corresponding comment if the token is valid. * * @since 1.0.0 * * @return void */ public function handle_rsvp_token(): void { $rsvp_token = Rsvp_Token::from_url_parameter(); if ( $rsvp_token ) { $rsvp_token->approve_comment(); } } }