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 `