PluginProbe
Friends / 4.3.1
Friends v4.3.1
4.3.2 4.3.1 4.3.0 4.2.2 4.2.1 4.2.0 4.1.0 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 2.7.9 2.8.0 2.8.1 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 2.9.0 2.9.1 All 88 releases
friends / templates / frontend / followers.php

followers.php in Friends 4.3.1, at templates/frontend/followers.php

413 lines 14.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * This is the Followers list
4 *
5 * @version 1.0
6 * @package Friends
7 */
8
9 $args = array_merge( $friends_args, $args );
10 $blog_followers = class_exists( '\ActivityPub\Collection\Actors' ) && \ActivityPub\Collection\Actors::BLOG_USER_ID === $args['user_id'];
11 if ( ! isset( $args['title'] ) || ! $args['title'] ) {
12 $args['title'] = __( 'Your Followers', 'friends' );
13 if ( $blog_followers ) {
14 $args['title'] = __( 'Your Blog Followers', 'friends' );
15 }
16 }
17
18 $default_filter = isset( $args['filter'] ) ? $args['filter'] : 'all';
19 $filter = isset( $_GET['filter'] ) ? sanitize_key( $_GET['filter'] ) : $default_filter; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
20 if ( ! in_array( $filter, array( 'all', 'following', 'not-following' ), true ) ) {
21 $filter = 'all';
22 }
23 // Backwards compatibility with ?mutual.
24 if ( isset( $_GET['mutual'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
25 $filter = 'following';
26 }
27
28 $sort = isset( $_GET['sort'] ) ? sanitize_key( $_GET['sort'] ) : 'newest'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
29 if ( ! in_array( $sort, array( 'newest', 'oldest', 'name' ), true ) ) {
30 $sort = 'newest';
31 }
32
33 $search_term = isset( $_GET['q'] ) ? trim( wp_unslash( $_GET['q'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
34
35 $args['no-bottom-margin'] = true;
36
37 Friends\Friends::template_loader()->get_template_part( 'frontend/header', null, $args );
38
39 $followers_list_page = 'users.php?page=activitypub-followers-list';
40 if ( $blog_followers ) {
41 $followers_list_page = 'options-general.php?page=activitypub&tab=followers';
42 }
43 ?>
44 <section class="followers">
45 <?php
46 if ( class_exists( '\ActivityPub\Collection\Followers' ) ) {
47 $follower_data = \ActivityPub\Collection\Followers::query( $args['user_id'] );
48 $total = $follower_data['total'];
49
50 // Apply search filter first so downstream work operates on the smaller set.
51 if ( '' !== $search_term ) {
52 $search_term_lc = function_exists( 'mb_strtolower' ) ? mb_strtolower( $search_term ) : strtolower( $search_term );
53 $follower_data['followers'] = array_values(
54 array_filter(
55 $follower_data['followers'],
56 function ( $f ) use ( $search_term_lc ) {
57 $haystack = '';
58 if ( isset( $f->post_title ) ) {
59 $haystack .= $f->post_title . ' ';
60 }
61 if ( isset( $f->guid ) ) {
62 $haystack .= $f->guid . ' ';
63 }
64 if ( isset( $f->post_content ) ) {
65 $haystack .= wp_strip_all_tags( $f->post_content );
66 }
67 $haystack = function_exists( 'mb_strtolower' ) ? mb_strtolower( $haystack ) : strtolower( $haystack );
68 return false !== strpos( $haystack, $search_term_lc );
69 }
70 )
71 );
72 }
73
74 // Classify followers only when a filter is active.
75 if ( 'all' !== $filter ) {
76 $following_ids = array();
77 $not_following_ids = array();
78 foreach ( $follower_data['followers'] as $follower ) {
79 $url = $follower->guid;
80 $is_following = false;
81 if ( $url ) {
82 $is_following = Friends\User_Feed::get_by_url( $url );
83 if ( ! $is_following || is_wp_error( $is_following ) ) {
84 $is_following = Friends\User_Feed::get_by_url( str_replace( '@', 'users/', $url ) );
85 }
86 }
87 if ( $is_following && ! is_wp_error( $is_following ) ) {
88 $following_ids[] = $follower->ID;
89 } else {
90 $not_following_ids[] = $follower->ID;
91 }
92 }
93
94 if ( 'following' === $filter ) {
95 $filtered_followers = array_filter(
96 $follower_data['followers'],
97 function ( $f ) use ( $following_ids ) {
98 return in_array( $f->ID, $following_ids, true );
99 }
100 );
101 } else {
102 $filtered_followers = array_filter(
103 $follower_data['followers'],
104 function ( $f ) use ( $not_following_ids ) {
105 return in_array( $f->ID, $not_following_ids, true );
106 }
107 );
108 }
109 } else {
110 $filtered_followers = $follower_data['followers'];
111 }
112
113 // Sort.
114 $filtered_followers = array_values( $filtered_followers );
115 if ( 'oldest' === $sort ) {
116 usort(
117 $filtered_followers,
118 function ( $a, $b ) {
119 return $a->ID - $b->ID;
120 }
121 );
122 } elseif ( 'name' === $sort ) {
123 usort(
124 $filtered_followers,
125 function ( $a, $b ) {
126 return strnatcasecmp( $a->post_title, $b->post_title );
127 }
128 );
129 }
130
131 // Paginate.
132 $filtered_total = count( $filtered_followers );
133 $followers_per_page = 20;
134 $current_page = isset( $_GET['fpage'] ) ? max( 1, absint( $_GET['fpage'] ) ) : 1; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
135 $page_followers = array_slice( $filtered_followers, ( $current_page - 1 ) * $followers_per_page, $followers_per_page );
136
137 // Convert only the current page's followers to actor data.
138 $display_followers = array();
139 foreach ( $page_followers as $follower ) {
140 if ( $follower instanceof \WP_Post ) {
141 $follower = \Activitypub\Collection\Remote_Actors::get_actor( $follower );
142 if ( is_wp_error( $follower ) ) {
143 continue;
144 }
145 }
146 $data = $follower->to_array();
147
148 $data['url'] = \ActivityPub\object_to_uri( $data['url'] );
149 $data['server'] = wp_parse_url( $data['url'], PHP_URL_HOST );
150 $data['css_class'] = '';
151
152 $following = Friends\User_Feed::get_by_url( $data['url'] );
153 if ( ! $following || is_wp_error( $following ) ) {
154 $following = Friends\User_Feed::get_by_url( str_replace( '@', 'users/', $data['url'] ) );
155 }
156 if ( $following && ! is_wp_error( $following ) ) {
157 $data['friend_user'] = $following->get_friend_user();
158 $data['action_url'] = $following->get_friend_user()->get_local_friends_page_url();
159 $data['url'] = $following->get_friend_user()->get_local_friends_page_url();
160 if ( 'all' === $filter ) {
161 $data['css_class'] = ' already-following';
162 }
163 } else {
164 $data['friend_user'] = false;
165 $data['action_url'] = add_query_arg( 'url', $data['url'], admin_url( 'admin.php?page=add-friend' ) );
166 }
167 $data['remove_action_url'] = add_query_arg( 's', $data['url'], admin_url( $followers_list_page ) );
168 $display_followers[] = $data;
169 }
170
171 $base_url = strtok( $_SERVER['REQUEST_URI'], '?' ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
172 $link_args = array();
173 if ( 'all' !== $filter ) {
174 $link_args['filter'] = $filter;
175 }
176 if ( 'newest' !== $sort ) {
177 $link_args['sort'] = $sort;
178 }
179 if ( '' !== $search_term ) {
180 $link_args['q'] = $search_term;
181 }
182 ?>
183 <p>
184 <?php
185 if ( $blog_followers ) {
186 echo esc_html(
187 sprintf(
188 // translators: %s is the number of followers.
189 _n( 'You have %s blog follower.', 'You have %s blog followers.', $total, 'friends' ),
190 $total
191 )
192 );
193 } else {
194 echo esc_html(
195 sprintf(
196 // translators: %s is the number of followers.
197 _n( 'You have %s follower.', 'You have %s followers.', $total, 'friends' ),
198 $total
199 )
200 );
201 }
202
203 echo ' <a href="' . esc_attr( admin_url( $followers_list_page ) ) . '">';
204 if ( $blog_followers ) {
205 esc_html_e( 'View all blog followers in wp-admin', 'friends' );
206 } else {
207 esc_html_e( 'View all followers in wp-admin', 'friends' );
208 }
209 echo '</a>';
210 ?>
211 </p>
212 <form method="get" action="<?php echo esc_url( $base_url ); ?>" class="friends-search" role="search">
213 <label class="friends-search-label">
214 <?php esc_html_e( 'Search:', 'friends' ); ?>
215 <input type="search" name="q" value="<?php echo esc_attr( $search_term ); ?>" placeholder="<?php esc_attr_e( 'Name, handle, or description', 'friends' ); ?>" class="friends-search-input" />
216 </label>
217 <button type="submit" class="button friends-search-submit"><?php esc_html_e( 'Search', 'friends' ); ?></button>
218 <?php if ( 'all' !== $filter ) : ?>
219 <input type="hidden" name="filter" value="<?php echo esc_attr( $filter ); ?>" />
220 <?php endif; ?>
221 <?php if ( 'newest' !== $sort ) : ?>
222 <input type="hidden" name="sort" value="<?php echo esc_attr( $sort ); ?>" />
223 <?php endif; ?>
224 <?php
225 if ( '' !== $search_term ) :
226 $clear_args = $link_args;
227 unset( $clear_args['q'] );
228 $clear_url = $clear_args ? add_query_arg( $clear_args, $base_url ) : $base_url;
229 ?>
230 <a href="<?php echo esc_url( $clear_url ); ?>" class="friends-search-clear"><?php esc_html_e( 'Clear', 'friends' ); ?></a>
231 <?php endif; ?>
232 </form>
233 <?php if ( '' !== $search_term ) : ?>
234 <p>
235 <?php
236 echo esc_html(
237 sprintf(
238 // translators: %1$s is the number of matches, %2$s is the search term.
239 _n( '%1$s match for "%2$s"', '%1$s matches for "%2$s"', count( $filtered_followers ), 'friends' ),
240 number_format_i18n( count( $filtered_followers ) ),
241 $search_term
242 )
243 );
244 ?>
245 </p>
246 <?php endif; ?>
247 <p>
248 <?php esc_html_e( 'Filter:', 'friends' ); ?>
249 <?php
250 $filters = array(
251 'all' => __( 'All', 'friends' ),
252 'following' => __( 'Following', 'friends' ),
253 'not-following' => __( 'Not Following', 'friends' ),
254 );
255 $filter_links = array();
256 foreach ( $filters as $filter_key => $filter_label ) {
257 $url = $base_url;
258 $f_args = $link_args;
259 if ( 'all' !== $filter_key ) {
260 $f_args['filter'] = $filter_key;
261 } else {
262 unset( $f_args['filter'] );
263 }
264 if ( $f_args ) {
265 $url = add_query_arg( $f_args, $url );
266 }
267 if ( $filter === $filter_key ) {
268 $filter_links[] = '<strong>' . esc_html( $filter_label ) . '</strong>';
269 } else {
270 $filter_links[] = '<a href="' . esc_url( $url ) . '">' . esc_html( $filter_label ) . '</a>';
271 }
272 }
273 echo wp_kses(
274 implode( ' | ', $filter_links ),
275 array(
276 'strong' => array(),
277 'a' => array( 'href' => array() ),
278 )
279 );
280 ?>
281
282 &nbsp;&nbsp;
283 <?php esc_html_e( 'Sort:', 'friends' ); ?>
284 <?php
285 $sorts = array(
286 'newest' => __( 'Newest', 'friends' ),
287 'oldest' => __( 'Oldest', 'friends' ),
288 'name' => __( 'Name', 'friends' ),
289 );
290 $sort_links = array();
291 foreach ( $sorts as $sort_key => $sort_label ) {
292 $url = $base_url;
293 $s_args = $link_args;
294 if ( 'newest' !== $sort_key ) {
295 $s_args['sort'] = $sort_key;
296 } else {
297 unset( $s_args['sort'] );
298 }
299 if ( $s_args ) {
300 $url = add_query_arg( $s_args, $url );
301 }
302 if ( $sort === $sort_key ) {
303 $sort_links[] = '<strong>' . esc_html( $sort_label ) . '</strong>';
304 } else {
305 $sort_links[] = '<a href="' . esc_url( $url ) . '">' . esc_html( $sort_label ) . '</a>';
306 }
307 }
308 echo wp_kses(
309 implode( ' | ', $sort_links ),
310 array(
311 'strong' => array(),
312 'a' => array( 'href' => array() ),
313 )
314 );
315 ?>
316 </p>
317 <ul>
318 <?php
319 foreach ( $display_followers as $follower ) {
320 ?>
321 <li class="follower-item">
322 <details class="follower-details" data-nonce="<?php echo esc_attr( wp_create_nonce( 'friends-preview' ) ); ?>" data-following="<?php echo esc_attr( $follower['following'] ); ?>" data-followers="<?php echo esc_attr( $follower['followers'] ); ?>" data-id="<?php echo esc_attr( $follower['id'] ); ?>">
323 <summary>
324 <a href="<?php echo esc_url( $follower['url'] ); ?>" class="follower-link<?php echo esc_attr( $follower['css_class'] ); ?>">
325 <img width="40" height="40" src="<?php echo esc_attr( $follower['icon']['url'] ); ?>" loading="lazy" class="avatar activitypub-avatar" />
326 <span class="follower-info">
327 <strong class="follower-name"><?php echo esc_html( $follower['name'] ); ?></strong>
328 <span class="follower-handle">@<?php echo esc_html( $follower['preferredUsername'] . '@' . $follower['server'] ); ?></span>
329 </span>
330 </a>
331 <span class="follower-meta">
332 <span class="follower-since">
333 <?php
334 echo esc_html(
335 sprintf(
336 // translators: %s is a date.
337 __( 'since %s', 'friends' ),
338 $follower['published']
339 )
340 );
341 ?>
342 </span>
343 <span class="their-followers"></span>
344 <span class="their-following"></span>
345 </span>
346 <span class="follower-actions">
347 <?php if ( $follower['friend_user'] ) : ?>
348 <span class="follower-status" title="<?php esc_attr_e( 'Already following', 'friends' ); ?>">
349 <span class="dashicons dashicons-yes-alt"></span> <?php esc_html_e( 'Following', 'friends' ); ?>
350 </span>
351 <?php else : ?>
352 <a href="<?php echo esc_url( $follower['action_url'] ); ?>" class="follower-action follower-add" title="<?php esc_attr_e( 'Follow back', 'friends' ); ?>">
353 <span class="dashicons dashicons-plus-alt"></span> <?php esc_html_e( 'Follow back', 'friends' ); ?>
354 </a>
355 <?php endif; ?>
356 <a href="<?php echo esc_url( $follower['remove_action_url'] ); ?>" class="follower-action follower-delete" title="<?php esc_attr_e( 'Remove follower', 'friends' ); ?>" data-nonce="<?php echo esc_attr( wp_create_nonce( 'friends-followers' ) ); ?>" data-handle="<?php echo esc_attr( $follower['preferredUsername'] . '@' . $follower['server'] ); ?>" data-id="<?php echo esc_attr( $follower['id'] ); ?>">
357 <span class="dashicons dashicons-dismiss"></span> <?php esc_html_e( 'Remove', 'friends' ); ?>
358 </a>
359 </span>
360 <p class="follower-description">
361 <?php
362 echo wp_kses(
363 $follower['summary'],
364 array(
365 'a' => array(
366 'href' => array(),
367 ),
368 )
369 );
370 ?>
371 </p>
372 </summary>
373 <p class="loading-posts">
374 <span><?php esc_html_e( 'Loading posts', 'friends' ); ?></span>
375 <i class="form-icon loading"></i>
376 </p>
377 </details>
378 </li>
379 <?php
380 }
381 ?>
382 </ul>
383 <?php
384 $total_pages = ceil( $filtered_total / $followers_per_page );
385 if ( $total_pages > 1 ) {
386 $pagination_args = array(
387 'base' => add_query_arg( 'fpage', '%#%' ),
388 'format' => '',
389 'current' => $current_page,
390 'total' => $total_pages,
391 );
392 if ( $link_args ) {
393 $pagination_args['add_args'] = $link_args;
394 }
395 echo '<nav class="pagination">';
396 echo wp_kses_post( paginate_links( $pagination_args ) );
397 echo '</nav>';
398 }
399 } else {
400 ?>
401 <p><?php esc_html_e( 'The follower list is currently dependent on the ActivityPub plugin.', 'friends' ); ?></p>
402 <?php
403
404 }
405 ?>
406 </section>
407 <?php
408 Friends\Friends::template_loader()->get_template_part(
409 'frontend/footer',
410 null,
411 $args
412 );
413