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( 'pre_get_comments', array( $this, 'exclude_rsvp_from_comment_query' ) ); add_filter( 'comments_clauses', array( $this, 'taxonomy_query' ), 10, 2 ); add_action( 'wp_insert_comment', array( $this, 'maybe_invalidate_comment_types_cache' ), 10, 2 ); } /** * Modify comment query clauses to include taxonomy query. * * This method adds the necessary SQL join and where clauses to a comment query * based on a taxonomy query if one is present in the query variables. * * @since 1.0.0 * * @param array $clauses The clauses for the query. * @param WP_Comment_Query $comment_query Current instance of WP_Comment_Query (passed by reference). * @return array Modified query clauses. */ public function taxonomy_query( array $clauses, WP_Comment_Query $comment_query ): array { global $wpdb; if ( ! empty( $comment_query->query_vars['tax_query'] ) ) { $comment_tax_query = new WP_Tax_Query( $comment_query->query_vars['tax_query'] ); $pieces = $comment_tax_query->get_sql( $wpdb->comments, 'comment_ID' ); $clauses['join'] .= $pieces['join']; $clauses['where'] .= $pieces['where']; } return $clauses; } /** * Retrieve RSVP comments or count based on specified arguments. * * This method fetches RSVP comments by merging the provided arguments with default * values specific to RSVPs. Can return either an array of comments or integer count * based on the 'count' parameter. * * @since 1.0.0 * * @param array $args Arguments for retrieving RSVPs. * @return mixed Array of RSVP comments or integer count when count parameter is true. */ public function get_rsvps( array $args ) { $args['type'] = Rsvp::COMMENT_TYPE; $args['post_type'] = Event::POST_TYPE; $args['type__in'] = array(); $args['type__not_in'] = array(); remove_action( 'pre_get_comments', array( $this, 'exclude_rsvp_from_comment_query' ) ); $rsvps = get_comments( $args ); add_action( 'pre_get_comments', array( $this, 'exclude_rsvp_from_comment_query' ) ); if ( ! empty( $args['count'] ) ) { return (int) $rsvps; } return (array) $rsvps; } /** * Retrieve a single RSVP comment based on specified arguments. * * This method fetches a single RSVP comment by setting the number limit to 1 * and calling get_rsvps(). Returns the first RSVP found or null if none exist. * * @since 1.0.0 * * @param array $args Arguments for retrieving the RSVP. * @return WP_Comment|null The RSVP comment or null if not found. */ public function get_rsvp( array $args ): ?WP_Comment { $args['number'] = 1; $args['count'] = false; $rsvp = $this->get_rsvps( $args ); if ( empty( $rsvp ) ) { return null; } return $rsvp[0]; } /** * Get all comment types registered in the database. * * This method queries the database for all distinct comment types * and caches the result for performance. * * @since 1.0.0 * * @return array Array of all comment types in the database. */ protected function get_all_comment_types(): array { $default_types = array( 'comment', 'pingback', 'trackback' ); $types = get_transient( self::COMMENT_TYPES_CACHE_KEY ); if ( false === $types ) { global $wpdb; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $types = $wpdb->get_col( $wpdb->prepare( 'SELECT DISTINCT comment_type FROM %i WHERE comment_type != %s', $wpdb->comments, '' ) ); // If no types found or database error, use WordPress defaults. if ( empty( $types ) || ! is_array( $types ) ) { $types = $default_types; } // Cache for 24 hours. set_transient( self::COMMENT_TYPES_CACHE_KEY, $types, self::CACHE_EXPIRATION ); } // Ensure we always return an array. return is_array( $types ) ? $types : $default_types; } /** * Invalidate comment types cache when a new comment type is added. * * This method checks if a newly inserted comment has a type that's not * already in our cached types, and if so, invalidates the cache. * * @since 1.0.0 * * @param int $id The comment ID. * @param WP_Comment $comment The comment object. * @return void */ public function maybe_invalidate_comment_types_cache( int $id, WP_Comment $comment ): void { // Skip if it's an empty comment type (regular comment). if ( empty( $comment->comment_type ) ) { return; } $cached_types = get_transient( self::COMMENT_TYPES_CACHE_KEY ); // If cache exists and this type isn't in it, invalidate the cache. if ( false !== $cached_types && ! in_array( $comment->comment_type, $cached_types, true ) ) { delete_transient( self::COMMENT_TYPES_CACHE_KEY ); } } /** * Exclude RSVP comments from a query. * * This method modifies the comment query to exclude comments of the RSVP type. It * ensures that RSVP comments are not included in the query results by adjusting the * comment types in the query variables. * * Note: The comment_type field is not currently indexed in WordPress core, * which may impact query performance. See https://core.trac.wordpress.org/ticket/59488 * * @since 1.0.0 * * @param WP_Comment_Query $query Current instance of WP_Comment_Query (passed by reference). * @return void */ public function exclude_rsvp_from_comment_query( WP_Comment_Query $query ) { // Process 'type' query var. $current_comment_types = $query->query_vars['type']; if ( ! empty( $current_comment_types ) ) { if ( is_array( $current_comment_types ) ) { $current_comment_types = array_values( array_diff( $current_comment_types, array( Rsvp::COMMENT_TYPE ) ) ); } elseif ( Rsvp::COMMENT_TYPE === $current_comment_types ) { $current_comment_types = ''; } } else { // Get all registered comment types from the database (cached). $current_comment_types = $this->get_all_comment_types(); $current_comment_types = array_values( array_diff( $current_comment_types, array( Rsvp::COMMENT_TYPE ) ) ); } $query->query_vars['type'] = $current_comment_types; // Process 'type__in' query var. $current_comment_types_in = $query->query_vars['type__in']; if ( ! empty( $current_comment_types_in ) ) { if ( is_array( $current_comment_types_in ) ) { $current_comment_types_in = array_values( array_diff( $current_comment_types_in, array( Rsvp::COMMENT_TYPE ) ) ); } elseif ( Rsvp::COMMENT_TYPE === $current_comment_types_in ) { $current_comment_types_in = ''; } $query->query_vars['type__in'] = $current_comment_types_in; } } }