PluginProbe
Friends / 4.3.2
Friends v4.3.2
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 / author-header.php

author-header.php in Friends 4.3.2, at templates/frontend/author-header.php

303 lines 12.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * This template contains the author header on /friends/.
4 *
5 * @package Friends
6 */
7
8 $edit_user_link = $args['friends']->admin->admin_edit_user_link( false, $args['friend_user'] );
9 $_feeds = count( $args['friend_user']->get_feeds() );
10 $rules = count( $args['friend_user']->get_feed_rules() );
11 $active_feeds = count( $args['friend_user']->get_active_feeds() );
12 $hidden_post_count = $args['friend_user']->get_post_in_trash_count();
13 $display_name_html = apply_filters( 'friends_author_display_name_html', esc_html( $args['friend_user']->display_name ), $args['friend_user']->display_name, $args['friend_user'] );
14
15 // Get ActivityPub feeds and their data (header image, profile URLs, summary).
16 $activitypub_feeds = array();
17 $seen_activitypub_feeds = array();
18 $header_image_url = null;
19 $activitypub_summary = null;
20 foreach ( $args['friend_user']->get_active_feeds() as $feed ) {
21 // Check if this is an ActivityPub feed (parser is 'activitypub').
22 if ( 'activitypub' !== $feed->get_parser() ) {
23 continue;
24 }
25
26 $ap_actor_id = $feed->get_ap_actor_id();
27 $ap_actor_url = $feed->get_ap_actor_url();
28 // The parser is only loaded while the ActivityPub plugin is active; a feed can still be marked as one without it.
29 $ap_actor_acct = '';
30 if ( class_exists( 'Friends\Feed_Parser_ActivityPub' ) ) {
31 $ap_actor_acct = Friends\Feed_Parser_ActivityPub::get_actor_acct_from_attributed_to(
32 array(
33 'ap_actor_id' => $ap_actor_id,
34 )
35 );
36 }
37
38 // If no actor URL from linked actor, use the feed URL as the actor URL.
39 if ( ! $ap_actor_url ) {
40 $ap_actor_url = $feed->get_url();
41 }
42
43 if ( ! $ap_actor_url ) {
44 continue;
45 }
46
47 $dedupe_key = $ap_actor_acct ? 'acct:' . strtolower( $ap_actor_acct ) : 'url:' . strtolower( untrailingslashit( $ap_actor_url ) );
48 if ( isset( $seen_activitypub_feeds[ $dedupe_key ] ) ) {
49 continue;
50 }
51 $seen_activitypub_feeds[ $dedupe_key ] = true;
52
53 $feed_data = array(
54 'url' => $ap_actor_url,
55 'acct' => $ap_actor_acct,
56 );
57
58 // Try to get actor metadata including header image and summary.
59 if ( class_exists( '\Activitypub\Collection\Remote_Actors' ) ) {
60 $actor = null;
61
62 // First try using the linked actor ID.
63 if ( $ap_actor_id ) {
64 $actor = \Activitypub\Collection\Remote_Actors::get_actor( $ap_actor_id );
65 }
66
67 // If no linked actor or it failed, try fetching by URL.
68 if ( ( ! $actor || is_wp_error( $actor ) ) && method_exists( '\Activitypub\Collection\Remote_Actors', 'get_by_uri' ) ) {
69 $actor_post = \Activitypub\Collection\Remote_Actors::get_by_uri( $ap_actor_url );
70 if ( $actor_post instanceof \WP_Post ) {
71 $actor = \Activitypub\Collection\Remote_Actors::get_actor( $actor_post->ID );
72 }
73 }
74
75 if ( $actor && ! is_wp_error( $actor ) ) {
76 $image = $actor->get_image();
77 if ( $image ) {
78 $feed_data['header'] = \Activitypub\object_to_uri( $image );
79 // Use the first header image found.
80 if ( ! $header_image_url ) {
81 $header_image_url = $feed_data['header'];
82 }
83 }
84
85 // Get summary/bio if we don't have one yet.
86 if ( ! $activitypub_summary ) {
87 $summary = $actor->get_summary();
88 if ( $summary ) {
89 $activitypub_summary = $summary;
90 }
91 }
92 }
93 }
94
95 $activitypub_feeds[] = $feed_data;
96 }
97
98 // Use ActivityPub summary as fallback for user description.
99 $user_description = $args['friend_user']->description;
100 if ( empty( $user_description ) && $activitypub_summary ) {
101 $user_description = $activitypub_summary;
102 }
103
104 ?><div id="author-header" class="mb-2<?php echo $header_image_url ? ' has-header-image' : ''; ?>"
105 <?php
106 if ( $header_image_url ) :
107 ?>
108 style="background-image: url('<?php echo esc_url( $header_image_url ); ?>');"<?php endif; ?>>
109 <h2 id="page-title">
110 <?php if ( $args['friend_user']->is_starred() ) : ?>
111 <a href="" class="dashicons dashicons-star-filled starred" data-id="<?php echo esc_attr( $args['friend_user']->user_login ); ?>" data-nonce="<?php echo esc_attr( wp_create_nonce( 'star-' . $args['friend_user']->user_login ) ); ?>"></a>
112 <?php else : ?>
113 <a href="" class="dashicons dashicons-star-empty not-starred" data-id="<?php echo esc_attr( $args['friend_user']->user_login ); ?>" data-nonce="<?php echo esc_attr( wp_create_nonce( 'star-' . $args['friend_user']->user_login ) ); ?>"></a>
114 <?php endif; ?>
115 <a href="<?php echo esc_attr( $args['friend_user']->get_local_friends_page_url() ); ?>">
116 <?php
117 if ( $args['friends']->frontend->reaction ) {
118 echo esc_html(
119 sprintf(
120 // translators: %1$s is an emoji reaction, %2$s is a type of feed, e.g. "Main Feed".
121 __( 'My %1$s reactions on %2$s', 'friends' ),
122 $args['friends']->frontend->reaction,
123 $args['friend_user']->display_name
124 )
125 );
126 } else {
127 if ( $args['friend_user']->get_avatar_url() ) {
128 ?>
129 <img src="<?php echo esc_attr( $args['friend_user']->get_avatar_url() ); ?>" alt="<?php echo esc_attr( $args['friend_user']->display_name ); ?>" class="avatar" width="36" height="36" style="vertical-align: middle;" />
130 <?php
131 }
132 echo wp_kses_post( $display_name_html );
133 }
134 ?>
135 </a>
136 </h2>
137
138 <?php if ( $user_description ) : ?>
139 <p>
140 <?php
141 echo wp_kses(
142 make_clickable( str_replace( '</p>', '<br/>', $user_description ) ),
143 array(
144 'a' => array( 'href' => array() ),
145 'span' => array( 'class' => array() ),
146 'br' => array(),
147 )
148 );
149 ?>
150 </p>
151 <?php endif; ?>
152
153 <?php if ( apply_filters( 'friends_debug', false ) ) : ?>
154 <span class="chip"><?php echo esc_html( get_class( $args['friend_user'] ) ); ?></span>
155 <?php endif; ?>
156
157 <span class="chip"><?php echo /* phpcs:ignore WordPress.WP.I18n.MissingArgDomain */ esc_html( sprintf( /* translators: %s is a localized date (F j, Y) */__( 'Since %s', 'friends' ), date_i18n( __( 'F j, Y' ), strtotime( $args['friend_user']->user_registered ) ) ) ); ?></span>
158
159 <?php
160 if ( ! empty( $args['friend_user']->user_url ) ) {
161 $user_url_parts = wp_parse_url( $args['friend_user']->user_url );
162 if ( isset( $user_url_parts['host'] ) ) {
163 $user_hostname = $user_url_parts['host'];
164 if ( substr( $user_hostname, 0, 4 ) === 'www.' ) {
165 $user_hostname = substr( $user_hostname, 4 );
166 }
167 if ( isset( $user_url_parts['path'] ) && substr( $user_url_parts['path'], 0, 2 ) === '/@' ) {
168 $p = strpos( $user_url_parts['path'], '/', 1 );
169 if ( false === $p ) {
170 $p = strlen( $user_url_parts['path'] );
171 }
172 $user_hostname .= esc_html( substr( $user_url_parts['path'], 0, $p ) );
173 }
174 ?>
175 <a class="chip" href="<?php echo esc_url( $args['friend_user']->user_url ); ?>" target="_blank" rel="noopener noreferrer"><?php echo esc_html( $user_hostname ); ?></a>
176 <?php
177 }
178 }
179 ?>
180
181 <?php
182 // Display ActivityPub profile links.
183 foreach ( $activitypub_feeds as $ap_feed ) :
184 $ap_url_parts = wp_parse_url( $ap_feed['url'] );
185 if ( isset( $ap_url_parts['host'] ) ) :
186 $ap_hostname = $ap_url_parts['host'];
187 if ( substr( $ap_hostname, 0, 4 ) === 'www.' ) {
188 $ap_hostname = substr( $ap_hostname, 4 );
189 }
190 // Extract @username for Mastodon-style URLs like /@username.
191 $ap_display = $ap_hostname;
192 if ( ! empty( $ap_feed['acct'] ) ) {
193 $ap_display = '@' . $ap_feed['acct'];
194 } elseif ( isset( $ap_url_parts['path'] ) && preg_match( '#^/@([^/]+)#', $ap_url_parts['path'], $matches ) ) {
195 $ap_display = '@' . $matches[1] . '@' . $ap_hostname;
196 } elseif ( isset( $ap_url_parts['path'] ) && preg_match( '#^/users/([^/]+)#i', $ap_url_parts['path'], $matches ) ) {
197 $ap_display = '@' . $matches[1] . '@' . $ap_hostname;
198 }
199 ?>
200 <a class="chip activitypub-profile" href="<?php echo esc_url( $ap_feed['url'] ); ?>" target="_blank" rel="noopener" title="<?php esc_attr_e( 'ActivityPub Profile', 'friends' ); ?>">
201 <span class="dashicons dashicons-rss" style="font-size: 14px; width: 14px; height: 14px; margin-right: 4px; vertical-align: text-bottom;"></span><?php echo esc_html( $ap_display ); ?>
202 </a>
203 <span class="chip activitypub-follower-check is-loading"
204 data-actor-url="<?php echo esc_attr( $ap_feed['url'] ); ?>"
205 data-nonce="<?php echo esc_attr( wp_create_nonce( 'friends-check-follower' ) ); ?>"
206 title="<?php esc_attr_e( 'Checking whether this actor follows you.', 'friends' ); ?>">
207 <?php esc_html_e( 'Checking follower...', 'friends' ); ?>
208 </span>
209 <?php
210 endif;
211 endforeach;
212 ?>
213
214 <?php foreach ( $args['friend_user']->get_post_count_by_post_format() as $post_format => $count ) : ?>
215 <a class="chip" href="<?php echo esc_attr( $args['friend_user']->get_local_friends_page_post_format_url( $post_format ) ); ?>"><?php echo esc_html( $args['friends']->get_post_format_plural_string( $post_format, $count ) ); ?></a>
216 <?php endforeach; ?>
217 <?php if ( isset( $_GET['show-hidden'] ) ) : // phpcs:ignore WordPress.Security.NonceVerification.Recommended ?>
218 <a class="chip" href="<?php echo esc_attr( remove_query_arg( 'show-hidden' ) ); ?>">
219 <?php echo esc_html__( 'Hide hidden items', 'friends' ); ?>
220 </a>
221 <?php elseif ( $hidden_post_count > 0 ) : ?>
222 <a class="chip" href="<?php echo esc_attr( add_query_arg( 'show-hidden', 1 ) ); ?>">
223 <?php echo esc_html( sprintf( /* translators: %s is the number of hidden posts */_n( '%s hidden items', '%s hidden items', $hidden_post_count, 'friends' ), number_format_i18n( $hidden_post_count ) ) ); ?>
224 </a>
225 <?php endif; ?>
226
227 <?php foreach ( Friends\Reactions::get_available_emojis() as $slug => $reaction ) : ?>
228 <a class="chip" href="<?php echo esc_attr( $args['friend_user']->get_local_friends_page_reaction_url( $slug ) ); ?>">
229 <?php
230 echo esc_html(
231 sprintf(
232 // translators: %s is an emoji.
233 __( 'Reacted with %s', 'friends' ),
234 $reaction->char
235 )
236 );
237 ?>
238 </a>
239 <?php endforeach; ?>
240
241 <?php if ( apply_filters( 'friends_show_author_edit', true, $args['friend_user'] ) ) : ?>
242 <a class="chip" href="<?php echo esc_attr( self_admin_url( 'admin.php?page=edit-friend-feeds&user=' . $args['friend_user']->user_login ) ); ?>">
243 <?php echo esc_html( sprintf( /* translators: %s is the number of feeds */_n( '%s feed', '%s feeds', $active_feeds, 'friends' ), number_format_i18n( $active_feeds ) ) ); ?>
244
245 <?php if ( $_feeds - $active_feeds > 1 ) : ?>
246 &nbsp;<small><?php echo esc_html( sprintf( /* translators: %s is the number of feeds */_n( '(+%s more)', '(+%s more)', $_feeds - $active_feeds, 'friends' ), number_format_i18n( $_feeds - $active_feeds ) ) ); ?></small>
247 <?php endif; ?>
248 </a>
249
250 <?php if ( $rules > 0 ) : ?>
251 <a class="chip" href="<?php echo esc_attr( self_admin_url( 'admin.php?page=edit-friend-rules&user=' . $args['friend_user']->user_login . '&_wpnonce=' . wp_create_nonce( 'edit-friend-rules-' . $args['friend_user']->user_login ) ) ); ?>">
252 <?php
253 // translators: %d is the number of rules.
254 echo esc_html( sprintf( _n( '%d rule', '%d rules', $rules, 'friends' ), $rules ) );
255 ?>
256 </a>
257 <?php endif; ?>
258
259 <a class="chip" href="<?php echo esc_attr( $edit_user_link ); ?>"><?php /* phpcs:ignore WordPress.WP.I18n.MissingArgDomain */ esc_html_e( 'Edit' ); ?></a>
260 <?php endif; ?>
261
262 <?php if ( $args['friend_user'] instanceof \Friends\Subscription ) : ?>
263 <?php
264 $_folders = \Friends\Subscription::get_folders();
265 $_current_folder = $args['friend_user']->get_folder();
266 $_current_id = $_current_folder ? $_current_folder->term_id : 0;
267 $_folder_nonce = wp_create_nonce( 'friends-move-to-folder' );
268 ?>
269 <span class="chip friends-folder-selector">
270 &#128193; <select class="friends-move-to-folder" data-id="<?php echo esc_attr( $args['friend_user']->user_login ); ?>" data-nonce="<?php echo esc_attr( $_folder_nonce ); ?>">
271 <option value="0"<?php selected( $_current_id, 0 ); ?>><?php esc_html_e( 'No folder', 'friends' ); ?></option>
272 <?php foreach ( $_folders as $_folder ) : ?>
273 <option value="<?php echo esc_attr( $_folder->term_id ); ?>"<?php selected( $_current_id, $_folder->term_id ); ?>><?php echo esc_html( $_folder->name ); ?></option>
274 <?php endforeach; ?>
275 <option value="new"><?php esc_html_e( '+ New folder', 'friends' ); ?></option>
276 </select>
277 </span>
278 <?php endif; ?>
279
280 <?php if ( $args['friend_user']->can_refresh_feeds() ) : ?>
281 <a class="chip refresh-feeds" href="" data-user="<?php echo esc_attr( $args['friend_user']->user_login ); ?>" data-nonce="<?php echo esc_attr( wp_create_nonce( 'friends-refresh' ) ); ?>"><?php esc_html_e( 'Refresh', 'friends' ); ?></a>
282 <?php endif; ?>
283
284 <a class="chip toggle-compact" href=""><?php echo esc_html( 'collapsed' === $args['frontend_default_view'] ? __( 'Expanded mode', 'friends' ) : __( 'Compact mode', 'friends' ) ); ?></a>
285
286 <?php do_action( 'friends_author_header', $args['friend_user'], $args ); ?>
287 </div>
288 <?php if ( $header_image_url ) : ?>
289 <script>
290 ( function() {
291 var header = document.getElementById( 'author-header' );
292 if ( ! header ) return;
293 var titleRow = header.closest( '.mastodon-col-header' );
294 var navbar = header.closest( 'header' ) || ( titleRow ? titleRow.querySelector( '.mastodon-col-title-row' ) : null );
295 if ( ! navbar ) return;
296 navbar.classList.add( 'has-header-image' );
297 navbar.style.backgroundImage = header.style.backgroundImage;
298 header.style.backgroundImage = '';
299 header.classList.remove( 'has-header-image' );
300 } )();
301 </script>
302 <?php endif; ?>
303