setup_hooks(); } /** * Set up hooks for various purposes. * * This method adds filters to handle rendering & REST requests for the block. * * @since 1.0.0 * * @return void */ protected function setup_hooks(): void { add_filter( 'pre_render_block', array( $this, 'pre_render_block' ), 10, 2 ); // Updates the query vars for the Query Loop block in the block editor. add_filter( sprintf( 'rest_%s_query', Event::POST_TYPE ), array( $this, 'rest_query' ), 10, 2 ); // We need more sortBy options. add_filter( sprintf( 'rest_%s_collection_params', Event::POST_TYPE ), array( $this, 'rest_collection_params' ) ); } /** * Allows render_block() to be short-circuited, by returning a non-null value. * * Updates the query on the front end based on custom query attributes. * * @since 1.0.0 * * @param string|null $pre_render The pre-rendered content. Default null. * @param array $parsed_block The block being rendered. * @return string|null The pre-rendered content. Default null. */ public function pre_render_block( ?string $pre_render, array $parsed_block ): ?string { // Check if this is our event query block by verifying the namespace attribute. if ( isset( $parsed_block['attrs']['namespace'] ) && self::BLOCK_NAME === $parsed_block['attrs']['namespace'] ) { if ( isset( $parsed_block['attrs']['query']['inherit'] ) && true === $parsed_block['attrs']['query']['inherit'] ) { global $wp_query; $query_args = array_merge( $wp_query->query_vars, array( 'posts_per_page' => $parsed_block['attrs']['query']['perPage'], 'order' => $parsed_block['attrs']['query']['order'], 'orderby' => $parsed_block['attrs']['query']['orderBy'], ) ); /** * Filter the query vars. * * Allows filtering query params when the query is being inherited. * * @since 1.0.0 * * @param array $query_args Arguments to be passed to WP_Query. * @param array $block_query The query attribute retrieved from the block. * @param boolean $inherited Whether the query is being inherited. * * @return array $filtered_query_args Final arguments list. */ $filtered_query_args = apply_filters( 'gatherpress_query_vars', $query_args, $parsed_block['attrs']['query'], true, ); // "Hijack the global query. It's a hack, but it works." Ryan Welcher. // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited $wp_query = new WP_Query( $filtered_query_args ); } else { add_filter( 'query_loop_block_query_vars', array( $this, 'query_loop_block_query_vars' ), 10, 2 ); } } return $pre_render; } /** * Returns an array with Post IDs that should be excluded from the Query. * * @since 1.0.0 * * @param array $attributes Event Query block attributes. * @return int[] Array of post IDs to exclude. */ protected function get_exclude_ids( array $attributes ): array { $exclude_ids = array(); // Exclude Current Post. if ( isset( $attributes['exclude_current'] ) && boolval( $attributes['exclude_current'] ) ) { array_push( $exclude_ids, $attributes['exclude_current'] ); } return $exclude_ids; } /** * Filters the arguments which will be passed to `WP_Query` for the Query Loop Block. * * @since 1.0.0 * * @param array $query Array containing parameters for WP_Query as parsed by the block context. * @param WP_Block $block Block instance. * @return array Array containing parameters for WP_Query as parsed by the block context. */ public function query_loop_block_query_vars( array $query, WP_Block $block ): array { // Retrieve the query from the passed block context. $block_query = $block->context['query']; if ( ! is_array( $block_query ) || ! isset( $block_query['gatherpress_event_query'] ) ) { return $query; } // Generate a new custom query with all potential query vars. $query_args = array(); // Post Related. $query_args['post_type'] = array( Event::POST_TYPE ); // Type of event list: 'upcoming' or 'past', // @see wp-content/plugins/gatherpress/includes/core/classes/class-event-query.php. $query_args['gatherpress_event_query'] = $block_query['gatherpress_event_query']; // Exclude Posts. $exclude_ids = $this->get_exclude_ids( $block_query ); if ( ! empty( $exclude_ids ) ) { // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in $query_args['post__not_in'] = $exclude_ids; } if ( isset( $block_query['include_unfinished'] ) ) { $query_args['include_unfinished'] = $block_query['include_unfinished']; } // Order By. $query_args['orderby'] = array( $block_query['orderBy'] ); // Order // can be NULL, when ASC. $query_args['order'] = strtoupper( $block_query['order'] ?? 'ASC' ); /** This filter is documented in includes/query-loop.php */ $filtered_query_args = apply_filters( 'gatherpress_query_vars', $query_args, $block_query, false ); // Return the merged query. return array_merge( $query, $filtered_query_args ); } /** * Callback to handle the custom query params. Updates the block editor. * * Filters WP_Query arguments when querying posts via the REST API. * * @since 1.0.0 * * @param array $args Array of arguments for WP_Query. * @param WP_REST_Request $request The REST API request object. * @return array Array of arguments for WP_Query. */ public function rest_query( array $args, WP_REST_Request $request ): array { // Generate a new custom query will all potential query vars. $custom_args = array(); // Type of event list: 'upcoming' or 'past', // @see wp-content/plugins/gatherpress/includes/core/classes/class-event-query.php . $custom_args['gatherpress_event_query'] = $request->get_param( 'gatherpress_event_query' ); // Exclusion Related. $exclude_current = $request->get_param( 'exclude_current' ); if ( $exclude_current ) { $attributes = array( 'exclude_current' => $exclude_current, ); // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in $custom_args['post__not_in'] = $this->get_exclude_ids( $attributes ); } $include_unfinished = $request->get_param( 'include_unfinished' ); if ( null !== $include_unfinished ) { $custom_args['include_unfinished'] = $include_unfinished; } $custom_args['orderby'] = $request->get_param( 'orderby' ); /** This filter is documented in includes/query-loop.php */ $filtered_query_args = apply_filters( 'gatherpress_query_vars', $custom_args, $request->get_params(), false, ); // Merge all queries. // Use array_filter with callback to preserve 0 values while filtering out null/empty. return array_merge( $args, array_filter( $filtered_query_args, static function ( $value ): bool { return null !== $value && '' !== $value; } ) ); } /** * Filters collection parameters for the posts controller. * * Override the allowed items. * * @since 1.0.0 * * @see https://developer.wordpress.org/reference/classes/wp_rest_posts_controller/get_collection_params/ * * @param array $query_params JSON Schema-formatted collection parameters. * @return array JSON Schema-formatted collection parameters. */ public function rest_collection_params( array $query_params ): array { // Add GatherPress-specific orderby options. $query_params['orderby']['enum'][] = 'rand'; $query_params['orderby']['enum'][] = 'datetime'; // Add custom GatherPress query parameters. $query_params['gatherpress_event_query'] = array( 'description' => __( 'Type of events to query: upcoming or past', 'gatherpress' ), 'type' => 'string', 'enum' => array( 'upcoming', 'past' ), 'default' => 'upcoming', ); $query_params['include_unfinished'] = array( 'description' => __( 'Whether to include events that have started but not finished', 'gatherpress' ), 'type' => 'integer', 'enum' => array( 0, 1 ), ); $query_params['exclude_current'] = array( 'description' => __( 'Post ID to exclude from results', 'gatherpress' ), 'type' => 'integer', ); return $query_params; } }