PluginProbe
Friends / 4.2.2
Friends v4.2.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.2.2, at templates/frontend/author-header.php

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