PluginProbe
ActivityPub / 9.2.0
ActivityPub v9.2.0
9.3.1 9.3.0 9.2.2 9.2.1 9.2.0 9.1.0 9.0.2 9.0.1 9.0.0 8.3.0 8.2.1 8.2.0 8.1.1 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.2.0 1.3.0 2.0.0 2.0.1 2.1.0 2.1.1 All 160 releases
activitypub / build / follow-me / render.php

render.php in ActivityPub 9.2.0, at build/follow-me/render.php

256 lines 8.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Server-side rendering of the `activitypub/follow-me` block.
4 *
5 * @package ActivityPub
6 */
7
8 use Activitypub\Blocks;
9 use Activitypub\Collection\Actors;
10 use Activitypub\Collection\Followers;
11
12 use function Activitypub\is_activitypub_request;
13
14 if ( is_activitypub_request() || is_feed() ) {
15 return;
16 }
17
18 /* @var array $attributes Block attributes. */
19 $attributes = wp_parse_args( $attributes );
20
21 /* @var WP_Block $block Parsed block.*/
22 $block = $block ?? null;
23
24 /* @var string $content Inner blocks content. */
25 $content = $content ?? '';
26
27 // Get the user ID from the selected user attribute.
28 $user_id = Blocks::get_user_id( $attributes['selectedUser'] ?? 'blog' );
29 $actor = Actors::get_by_id( $user_id );
30 if ( is_wp_error( $actor ) ) {
31 return;
32 }
33
34 // Generate a unique ID for the block.
35 $block_id = 'activitypub-follow-me-block-' . wp_unique_id();
36
37 // Get block style information.
38 $style = wp_get_global_styles();
39 $background_color = $attributes['backgroundColor'] ?? $style['color']['background'] ?? '';
40 $button_style = $attributes['style'] ?? array();
41
42 // Set up the Interactivity API config.
43 wp_interactivity_config(
44 'activitypub/follow-me',
45 array(
46 'namespace' => ACTIVITYPUB_REST_NAMESPACE,
47 'i18n' => array(
48 'copy' => __( 'Copy', 'activitypub' ),
49 'copied' => __( 'Copied!', 'activitypub' ),
50 'emptyProfileError' => __( 'Please enter a profile URL or handle.', 'activitypub' ),
51 'genericError' => __( 'An error occurred. Please try again.', 'activitypub' ),
52 'invalidProfileError' => __( 'Please enter a valid profile URL or handle.', 'activitypub' ),
53 ),
54 )
55 );
56
57 // Add the block wrapper attributes.
58 $wrapper_attributes = array(
59 'id' => $block_id,
60 'class' => 'activitypub-follow-me-block-wrapper',
61 'data-wp-interactive' => 'activitypub/follow-me',
62 'data-wp-init' => 'callbacks.initButtonStyles',
63 );
64 if ( isset( $attributes['buttonOnly'] ) ) {
65 $wrapper_attributes['class'] .= ' is-style-button-only';
66 }
67
68 $wrapper_context = wp_interactivity_data_wp_context(
69 array(
70 'backgroundColor' => $background_color,
71 'blockId' => $block_id,
72 'buttonStyle' => $button_style,
73 'copyButtonText' => __( 'Copy', 'activitypub' ),
74 'errorMessage' => '',
75 'isError' => false,
76 'isLoading' => false,
77 'modal' => array( 'isOpen' => false ),
78 'remoteProfile' => '',
79 'userId' => $user_id,
80 'webfinger' => '@' . $actor->get_webfinger(),
81 )
82 );
83
84 if ( empty( $content ) ) {
85 $button_text = $attributes['buttonText'] ?? __( 'Follow', 'activitypub' );
86 $content = '<div class="wp-block-button"><a class="wp-element-button wp-block-button__link">' . esc_html( $button_text ) . '</a></div>';
87 } else {
88 $content = implode( PHP_EOL, wp_list_pluck( $block->parsed_block['innerBlocks'], 'innerHTML' ) );
89 }
90
91 $content = Blocks::add_directions(
92 $content,
93 array( 'class_name' => 'wp-element-button' ),
94 array(
95 'data-wp-on--click' => 'actions.toggleModal',
96 'data-wp-on--keydown' => 'actions.onKeydown',
97 'data-wp-bind--aria-expanded' => 'context.modal.isOpen',
98 'aria-label' => __( 'Follow me on the Fediverse', 'activitypub' ),
99 'aria-haspopup' => 'dialog',
100 'aria-controls' => $block_id . '-modal-title',
101 'role' => 'button',
102 'tabindex' => '0',
103 )
104 );
105
106 $header_image = $actor->get_image();
107 $has_header = ! empty( $header_image['url'] ) && str_contains( $attributes['className'] ?? '', 'is-style-profile' );
108
109 $stats = array(
110 'posts' => $user_id ? count_user_posts( $user_id, 'post', true ) : (int) wp_count_posts()->publish,
111 'followers' => Followers::count( $user_id ),
112 );
113
114 ob_start();
115 ?>
116 <div class="activitypub-dialog__section">
117 <h4><?php esc_html_e( 'My Profile', 'activitypub' ); ?></h4>
118 <div class="activitypub-dialog__description">
119 <?php esc_html_e( 'Paste my profile into the search field of your favorite open social app or platform.', 'activitypub' ); ?>
120 </div>
121 <div class="activitypub-dialog__button-group">
122 <label for="<?php echo esc_attr( $block_id . '-profile-handle' ); ?>" class="screen-reader-text">
123 <?php esc_html_e( 'My Fediverse handle', 'activitypub' ); ?>
124 </label>
125 <input
126 aria-readonly="true"
127 class="wp-block-search__input"
128 id="<?php echo esc_attr( $block_id . '-profile-handle' ); ?>"
129 readonly
130 tabindex="-1"
131 type="text"
132 value="<?php echo esc_attr( '@' . $actor->get_webfinger() ); ?>"
133 />
134 <button
135 aria-label="<?php esc_attr_e( 'Copy handle to clipboard', 'activitypub' ); ?>"
136 class="wp-element-button"
137 data-wp-on--click="actions.copyToClipboard"
138 type="button"
139 >
140 <span data-wp-text="context.copyButtonText"></span>
141 </button>
142 </div>
143 </div>
144 <div class="activitypub-dialog__section">
145 <h4><?php esc_html_e( 'Your Profile', 'activitypub' ); ?></h4>
146 <div class="activitypub-dialog__description">
147 <?php esc_html_e( 'Or, if you know your own profile, we can start things that way!', 'activitypub' ); ?>
148 <?php Blocks::render_modal_help(); ?>
149 </div>
150 <div class="activitypub-dialog__button-group">
151 <label for="<?php echo esc_attr( $block_id . '-remote-profile' ); ?>" class="screen-reader-text">
152 <?php esc_html_e( 'Your Fediverse profile', 'activitypub' ); ?>
153 </label>
154 <input
155 class="wp-block-search__input"
156 data-wp-bind--aria-invalid="context.isError"
157 data-wp-bind--value="context.remoteProfile"
158 data-wp-on--input="actions.updateRemoteProfile"
159 data-wp-on--keydown="actions.handleKeyDown"
160 id="<?php echo esc_attr( $block_id . '-remote-profile' ); ?>"
161 placeholder="<?php esc_attr_e( '@username@example.com', 'activitypub' ); ?>"
162 type="text"
163 />
164 <button
165 aria-label="<?php esc_attr_e( 'Follow', 'activitypub' ); ?>"
166 class="wp-element-button"
167 data-wp-bind--disabled="context.isLoading"
168 data-wp-on--click="actions.submitRemoteProfile"
169 type="button"
170 >
171 <span data-wp-bind--hidden="context.isLoading"><?php esc_html_e( 'Follow', 'activitypub' ); ?></span>
172 <span data-wp-bind--hidden="!context.isLoading"><?php esc_html_e( 'Loading&hellip;', 'activitypub' ); ?></span>
173 </button>
174 </div>
175 <div
176 class="activitypub-dialog__error"
177 data-wp-bind--hidden="!context.isError"
178 data-wp-text="context.errorMessage"
179 ></div>
180 </div>
181 <?php
182 $modal_content = ob_get_clean();
183
184 ?>
185 <div
186 <?php echo get_block_wrapper_attributes( $wrapper_attributes ); // phpcs:ignore WordPress.Security.EscapeOutput ?>
187 <?php echo $wrapper_context; // phpcs:ignore WordPress.Security.EscapeOutput ?>
188 >
189 <div class="activitypub-profile p-author h-card">
190 <?php if ( $has_header ) : ?>
191 <div class="activitypub-profile__header" style="background-image: url('<?php echo esc_url( $header_image['url'] ); ?>');"></div>
192 <?php endif; ?>
193
194 <div class="activitypub-profile__body">
195 <img
196 class="activitypub-profile__avatar u-photo"
197 src="<?php echo esc_url( $actor->get_icon()['url'] ); ?>"
198 alt="<?php echo esc_attr( $actor->get_name() ); ?>"
199 />
200
201 <div class="activitypub-profile__content">
202 <div class="activitypub-profile__info">
203 <div class="activitypub-profile__name p-name"><?php echo esc_html( $actor->get_name() ); ?></div>
204 <?php /** Using `data-wp-text` to avoid @see enrich_content_data() turning it into a mention. */ ?>
205 <div class="activitypub-profile__handle p-nickname p-x-webfinger" data-wp-text="context.webfinger"></div>
206 </div>
207
208 <?php echo $content; // phpcs:ignore WordPress.Security.EscapeOutput ?>
209
210 <?php if ( $actor->get_summary() ) : ?>
211 <div class="activitypub-profile__bio p-note">
212 <?php echo wp_kses_post( $actor->get_summary() ); ?>
213 </div>
214 <?php endif; ?>
215
216 <div class="activitypub-profile__stats">
217 <?php if ( null !== $stats['posts'] ) : ?>
218 <div>
219 <?php
220 printf(
221 /* translators: %s: Number of posts */
222 esc_html( _n( '%s post', '%s posts', (int) $stats['posts'], 'activitypub' ) ),
223 '<strong>' . esc_html( number_format_i18n( $stats['posts'] ) ) . '</strong>'
224 );
225 ?>
226 </div>
227 <?php endif; ?>
228 <?php if ( null !== $stats['followers'] ) : ?>
229 <div>
230 <?php
231 printf(
232 /* translators: %s: Number of followers */
233 esc_html( _n( '%s follower', '%s followers', (int) $stats['followers'], 'activitypub' ) ),
234 '<strong>' . esc_html( number_format_i18n( $stats['followers'] ) ) . '</strong>'
235 );
236 ?>
237 </div>
238 <?php endif; ?>
239 </div>
240 </div>
241 </div>
242 </div>
243
244 <?php
245 // Render the modal using the Blocks class.
246 Blocks::render_modal(
247 array(
248 'id' => $block_id . '-modal',
249 'content' => $modal_content,
250 /* translators: %s: Profile name. */
251 'title' => sprintf( esc_html__( 'Follow %s', 'activitypub' ), esc_html( $actor->get_name() ) ),
252 )
253 );
254 ?>
255 </div>
256