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 { $render_block_hook = sprintf( 'render_block_%s', self::BLOCK_NAME ); add_filter( $render_block_hook, array( $this, 'transform_block_content' ), 10, 2 ); add_filter( $render_block_hook, array( $this, 'apply_rsvp_button_interactivity' ) ); // Priority 11 ensures this runs after transform_block_content which modifies the block structure. add_filter( $render_block_hook, array( $this, 'apply_guest_count_watch' ), 11 ); // Priority 9 ensures this runs before transform_block_content to properly register form field hooks. add_filter( $render_block_hook, array( $this, 'apply_guests_input_interactivity' ), 9 ); // Add hooks for conditional form field processing. $general_block = General_Block::get_instance(); add_filter( $render_block_hook, array( $general_block, 'process_guests_field' ), 10, 2 ); add_filter( $render_block_hook, array( $general_block, 'process_anonymous_field' ), 10, 2 ); } /** * Dynamically transforms and renders the content of the RSVP block and its inner blocks. * * This method processes the RSVP block content, applying dynamic attributes and interactivity * settings. It also handles the rendering of inner blocks based on the current RSVP status * and ensures proper serialization of inner block states for persistence. The method * dynamically adjusts the block content based on the event's status (e.g., past or active). * * Key functionalities: * - Adds `data-wp-interactive` attributes for interactivity. * - Dynamically renders and serializes inner blocks for each RSVP status. * - Ensures proper markup updates based on the RSVP status and event state. * * @since 1.0.0 * * @param string $block_content The original HTML content of the block. * @param array $block An associative array containing block data, including `blockName` and `attrs`. * * @return string The updated block content with dynamically rendered inner blocks and attributes. */ public function transform_block_content( string $block_content, array $block ): string { $block_instance = Block::get_instance(); $post_id = $block_instance->get_post_id( $block ); // Validate that the post ID is an actual event post type. // Only check publish status if not in preview mode. if ( Event::POST_TYPE !== get_post_type( $post_id ) || ( ! is_preview() && 'publish' !== get_post_status( $post_id ) ) ) { return ''; } $event = new Event( $post_id ); $inner_blocks = isset( $block['innerBlocks'] ) ? $block['innerBlocks'] : array(); $tag = new WP_HTML_Tag_Processor( $block_content ); $attributes = isset( $block['attrs'] ) ? $block['attrs'] : array(); if ( $tag->next_tag() ) { /** * Dynamically render inner blocks based on the saved RSVP status. * * This ensures that the block correctly renders the inner blocks * for the currently selected RSVP status and updates the serialized * inner blocks attribute. It addresses the issue of inner blocks * not persisting properly when switching between statuses. * * The method generates dynamic markup for all statuses, wrapping each * rendered inner block set in a container with a `data-rsvp-status` * attribute. */ $saved_status = $attributes['selectedStatus'] ?? 'no_status'; // Decode serialized inner blocks from attributes. $serialized_inner_blocks = $attributes['serializedInnerBlocks'] ?? ''; $serialized_inner_blocks = json_decode( $serialized_inner_blocks, true ); if ( ! is_array( $serialized_inner_blocks ) ) { $serialized_inner_blocks = array(); } // Serialize the current inner blocks for the saved status. $serialized_inner_blocks[ $saved_status ] = serialize_blocks( $inner_blocks ); $user_data = array(); if ( $event->rsvp ) { $user_identifier = Rsvp_Setup::get_instance()->get_user_identifier(); $user_data = $event->rsvp->get( $user_identifier ); } $filtered_data = array_intersect_key( $user_data, array_flip( array( 'status', 'guests', 'anonymous' ) ) ); $filtered_status = ! empty( $filtered_data['status'] ) ? $filtered_data['status'] : 'no_status'; if ( $event->has_event_past() ) { $inner_blocks_markup = do_blocks( $serialized_inner_blocks['past'] ?? '' ); } else { unset( $serialized_inner_blocks['past'] ); // Render inner blocks for all statuses. $inner_blocks_markup = ''; foreach ( $serialized_inner_blocks as $status => $serialized_inner_block ) { $class = $status !== $filtered_status ? 'gatherpress--is-hidden' : ''; $inner_blocks_markup .= sprintf( '
%s
', esc_attr( $class ), esc_attr( $status ), do_blocks( $serialized_inner_block ) ); } // Set dynamic attributes for interactivity. $tag->set_attribute( 'data-wp-interactive', 'gatherpress' ); $tag->set_attribute( 'data-wp-context', wp_json_encode( array( 'postId' => $post_id ) ) ); $tag->set_attribute( 'data-user-details', wp_json_encode( $filtered_data ) ); $tag->set_attribute( 'data-wp-watch', 'callbacks.renderRsvpBlock' ); } // Get the updated block content. $block_content = $tag->get_updated_html(); // @todo: Replace this workaround with a method to properly update inner blocks // when https://github.com/WordPress/gutenberg/issues/60397 is resolved. preg_match( '/]*>/i', $block_content, $matches ); // Use the matched opening
tag or fallback to a generic
. $opening_div = $matches[0] ?? '
'; // Close the block with a standard
. $closing_div = '
'; // Construct the updated block content with the new inner blocks markup. $block_content = $opening_div . $inner_blocks_markup . $closing_div; } return $block_content; } /** * Adds interactivity to RSVP buttons within the block content. * * This method scans the block content for elements with the class * `gatherpress-rsvp--trigger-update`. If such an element is found, it checks for a * nested `` or `