null, 'displayStyle' => $default_display_style, 'showActions' => false, ) ); /* @var \WP_Block $block Current block. */ $block = $block ?? ''; /* @var string $content Block content. */ $content = $content ?? ''; if ( empty( $content ) ) { // Fallback for v1.0.0 blocks. $_title = $attributes['title'] ?? __( 'Fediverse Reactions', 'activitypub' ); $content = '
' . esc_html( $_title ) . '
'; unset( $attributes['title'] ); } else { $content = implode( PHP_EOL, wp_list_pluck( $block->parsed_block['innerBlocks'], 'innerHTML' ) ); // Hide empty headings. if ( empty( wp_strip_all_tags( $content ) ) ) { $content = ''; } } // Get the Post ID from attributes or use the current post. $_post_id = $attributes['postId'] ?? get_the_ID(); // Don't leak reaction metadata for posts that are not currently publicly queryable. if ( ! is_post_publicly_queryable( $_post_id ) ) { return; } // Generate a unique ID for the block. $block_id = 'activitypub-reactions-block-' . wp_unique_id(); /* * Determine display style - compact style hides avatars. * For auto-hooked blocks without explicit style, use avatar setting to determine style. */ $has_style_class = isset( $attributes['className'] ) && strpos( $attributes['className'], 'is-style-' ) !== false; if ( ! $has_style_class ) { $attributes['className'] = trim( ( $attributes['className'] ?? '' ) . ' is-style-' . $default_display_style ); $attributes['displayStyle'] = $default_display_style; } $show_avatars = 'facepile' === $attributes['displayStyle']; // Fetch reactions. $reactions = array(); foreach ( Comment::get_comment_types() as $_type => $type_object ) { $_comments = get_comments( array( 'post_id' => $_post_id, 'type' => $_type, 'status' => 'approve', 'parent' => 0, ) ); if ( empty( $_comments ) ) { continue; } $count = count( $_comments ); // phpcs:disable WordPress.WP.I18n $label = sprintf( _n( $type_object['count_single'], $type_object['count_plural'], $count, 'activitypub' ), number_format_i18n( $count ) ); // phpcs:enable WordPress.WP.I18n $reactions[ $_type ] = array( 'label' => $label, 'count' => $count, 'items' => array_map( static function ( $comment ) { return array( 'name' => html_entity_decode( $comment->comment_author ), 'url' => $comment->comment_author_url, 'avatar' => get_avatar_url( $comment ), ); }, $_comments ), ); } if ( empty( $reactions ) && ! $attributes['showActions'] ) { echo ''; return; } // Set up the Interactivity API config. $config = array( 'defaultAvatarUrl' => ACTIVITYPUB_PLUGIN_URL . 'assets/img/mp.jpg', 'namespace' => ACTIVITYPUB_REST_NAMESPACE, ); if ( $attributes['showActions'] ) { $config['i18n'] = array( 'copied' => __( 'Copied!', 'activitypub' ), 'copy' => __( 'Copy', 'activitypub' ), 'emptyProfileError' => __( 'Please enter a profile URL or handle.', 'activitypub' ), 'genericError' => __( 'An error occurred. Please try again.', 'activitypub' ), 'intentLabelLike' => __( 'Like this post', 'activitypub' ), 'intentLabelAnnounce' => __( 'Boost this post', 'activitypub' ), 'invalidProfileError' => __( 'Please enter a valid profile URL or handle.', 'activitypub' ), ); } wp_interactivity_config( 'activitypub/reactions', $config ); // Set up the Interactivity API state. wp_interactivity_state( 'activitypub/reactions', array( 'reactions' => array( $_post_id => $reactions ) ) ); // Render a subset of the most recent reactions for facepile. $reactions = array_map( static function ( $reaction ) use ( $attributes ) { $count = 20; if ( 'wide' === $attributes['align'] ) { $count = 40; } elseif ( 'full' === $attributes['align'] ) { $count = 60; } $reaction['items'] = array_slice( array_reverse( $reaction['items'] ), 0, $count ); return $reaction; }, $reactions ); // Initialize the context for the block. $context = array( 'blockId' => $block_id, 'modal' => array( 'isCompact' => true, 'isOpen' => false, 'items' => array(), 'title' => '', ), 'postId' => $_post_id, 'reactions' => $reactions, ); if ( $attributes['showActions'] ) { $context['modal']['intent'] = ''; $context['copyButtonText'] = __( 'Copy', 'activitypub' ); $context['errorMessage'] = ''; $context['isError'] = false; $context['isLoading'] = false; $context['postUrl'] = get_post_id( $_post_id ); $context['remoteProfile'] = ''; $context['shouldSaveProfile'] = true; } // Map comment types to remote intent types. $intent_map = array( 'like' => 'like', 'repost' => 'announce', 'quote' => 'announce', ); // Build reactions content. ob_start(); ?>
$reaction ) : /* translators: %s: reaction type. */ $aria_label = sprintf( __( 'View all %s', 'activitypub' ), Comment::get_comment_type_attr( $_type, 'label' ) ); $intent = isset( $intent_map[ $_type ] ) ? $intent_map[ $_type ] : ''; ?>
$intent ) : ?>

$modal_content, ); if ( $attributes['showActions'] ) { $modal_args['title_binding'] = 'context.modal.title'; } else { $modal_args['is_compact'] = true; } ob_start(); Blocks::render_modal( $modal_args ); $inner_content = $reactions_content . ob_get_clean(); $wrapper_attrs = array( 'id' => $block_id, 'class' => $attributes['className'] ?? '', 'data-wp-interactive' => 'activitypub/reactions', 'data-wp-context' => wp_json_encode( $context, JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP ), 'data-wp-init' => 'callbacks.initReactions', ); $wrapper_attributes = get_block_wrapper_attributes( $wrapper_attrs ); // Render the block with common wrapper. ?>
>