PluginProbe
ActivityPub / trunk
ActivityPub vtrunk
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 / includes / wp-admin / class-user-settings-fields.php

class-user-settings-fields.php in ActivityPub trunk, at includes/wp-admin/class-user-settings-fields.php

579 lines 22.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * ActivityPub User Settings Fields Handler.
4 *
5 * @package Activitypub
6 */
7
8 namespace Activitypub\WP_Admin;
9
10 use Activitypub\Collection\Actors;
11 use Activitypub\Collection\Extra_Fields;
12 use Activitypub\Moderation;
13 use Activitypub\OAuth\Client;
14 use Activitypub\OAuth\Scope;
15 use Activitypub\OAuth\Token;
16
17 /**
18 * Class to handle all user settings fields and callbacks.
19 */
20 class User_Settings_Fields {
21 /**
22 * Initialize the settings fields.
23 */
24 public static function init() {
25 \add_action( 'load-profile.php', array( self::class, 'register_settings' ) );
26 }
27
28 /**
29 * Register all settings fields.
30 */
31 public static function register_settings() {
32 // Mark checklist item as done.
33 \update_option( 'activitypub_checklist_profile_setup_visited', '1' );
34
35 \add_settings_section(
36 'activitypub_user_profile',
37 \esc_html__( 'ActivityPub', 'activitypub' ),
38 array( self::class, 'section_description' ),
39 'activitypub_user_settings',
40 array(
41 'before_section' => '<section id="activitypub">',
42 'after_section' => '</section>',
43 )
44 );
45
46 \add_settings_field(
47 'activitypub_profile_url',
48 \esc_html__( 'Profile URL', 'activitypub' ),
49 array( self::class, 'profile_url_callback' ),
50 'activitypub_user_settings',
51 'activitypub_user_profile'
52 );
53
54 \add_settings_field(
55 'activitypub_description',
56 \esc_html__( 'Biography', 'activitypub' ),
57 array( self::class, 'description_callback' ),
58 'activitypub_user_settings',
59 'activitypub_user_profile',
60 array( 'label_for' => 'activitypub_description' )
61 );
62
63 \add_settings_field(
64 'activitypub_header_image',
65 \esc_html__( 'Header Image', 'activitypub' ),
66 array( self::class, 'header_image_callback' ),
67 'activitypub_user_settings',
68 'activitypub_user_profile',
69 array( 'label_for' => 'activitypub_header_image' )
70 );
71
72 \add_settings_field(
73 'activitypub_notifications',
74 \esc_html__( 'Email Notifications', 'activitypub' ),
75 array( self::class, 'notifications_callback' ),
76 'activitypub_user_settings',
77 'activitypub_user_profile'
78 );
79
80 \add_settings_field(
81 'activitypub_extra_fields',
82 \esc_html__( 'Extra Fields', 'activitypub' ),
83 array( self::class, 'extra_fields_callback' ),
84 'activitypub_user_settings',
85 'activitypub_user_profile'
86 );
87
88 \add_settings_field(
89 'activitypub_also_known_as',
90 \esc_html__( 'Account Aliases', 'activitypub' ),
91 array( self::class, 'also_known_as_callback' ),
92 'activitypub_user_settings',
93 'activitypub_user_profile',
94 array( 'label_for' => 'activitypub_also_known_as' )
95 );
96
97 \add_settings_field(
98 'activitypub_hide_social_graph',
99 \__( 'Followers and Followings', 'activitypub' ),
100 array( self::class, 'hide_followers_callback' ),
101 'activitypub_user_settings',
102 'activitypub_user_profile'
103 );
104
105 // Add moderation section.
106 \add_settings_section(
107 'activitypub_user_moderation',
108 \esc_html__( 'Moderation', 'activitypub' ),
109 array( self::class, 'moderation_section_description' ),
110 'activitypub_user_settings',
111 array(
112 'before_section' => '<section id="activitypub-moderation">',
113 'after_section' => '</section>',
114 )
115 );
116
117 \add_settings_field(
118 'activitypub_user_blocked_domains',
119 \esc_html__( 'Blocked Domains', 'activitypub' ),
120 array( self::class, 'blocked_domains_callback' ),
121 'activitypub_user_settings',
122 'activitypub_user_moderation'
123 );
124
125 \add_settings_field(
126 'activitypub_user_blocked_keywords',
127 \esc_html__( 'Blocked Keywords', 'activitypub' ),
128 array( self::class, 'blocked_keywords_callback' ),
129 'activitypub_user_settings',
130 'activitypub_user_moderation'
131 );
132 }
133
134 /**
135 * Section description callback.
136 */
137 public static function section_description() {
138 echo '<p>' . \esc_html__( 'Define what others can see on your public Fediverse profile and next to your posts. With a profile picture and a fully completed profile, you are more likely to gain interactions and followers.', 'activitypub' ) . '</p>';
139 echo '<p>' . \esc_html__( 'The ActivityPub plugin tries to take as much information as possible from your profile settings. However, the following settings are not supported by WordPress or should be adjusted independently of the WordPress settings.', 'activitypub' ) . '</p>';
140 }
141
142 /**
143 * Profile URL field callback.
144 */
145 public static function profile_url_callback() {
146 $user = Actors::get_by_id( \get_current_user_id() );
147 ?>
148 <p>
149 <?php
150 \printf(
151 // translators: 1: the webfinger resource, 2: the author URL.
152 \esc_html__( '%1$s or %2$s', 'activitypub' ),
153 '<code>' . \esc_html( $user->get_webfinger() ) . '</code>',
154 '<code>' . \esc_url( $user->get_url() ) . '</code>'
155 );
156 ?>
157 </p>
158 <p class="description">
159 <?php
160 \printf(
161 // translators: the webfinger resource.
162 \esc_html__( 'Follow "@%s" by searching for it on Mastodon, Friendica, etc.', 'activitypub' ),
163 \esc_html( $user->get_webfinger() )
164 );
165 ?>
166 </p>
167 <?php
168 }
169
170 /**
171 * Description field callback.
172 */
173 public static function description_callback() {
174 $description = \get_user_option( 'activitypub_description', \get_current_user_id() );
175 $placeholder = \get_user_meta( \get_current_user_id(), 'description', true );
176 ?>
177 <textarea name="activitypub_description" id="activitypub_description" rows="5" cols="30" placeholder="<?php echo \esc_attr( $placeholder ); ?>"><?php echo \esc_html( $description ); ?></textarea>
178 <p class="description"><?php \esc_html_e( 'If you wish to use different biographical info for the fediverse, enter your alternate bio here.', 'activitypub' ); ?></p>
179 <?php
180 }
181
182 /**
183 * Header image field callback.
184 */
185 public static function header_image_callback() {
186 $header_image = \get_user_option( 'activitypub_header_image', \get_current_user_id() );
187 $classes_for_upload_button = 'button upload-button button-add-media button-add-header-image';
188 $classes_for_update_button = 'button';
189 $classes_for_wrapper = '';
190
191 if ( (int) $header_image ) {
192 $classes_for_wrapper .= ' has-header-image';
193 $classes_for_button = $classes_for_update_button;
194 $classes_for_button_on_change = $classes_for_upload_button;
195 } else {
196 $classes_for_wrapper .= ' hidden';
197 $classes_for_button = $classes_for_upload_button;
198 $classes_for_button_on_change = $classes_for_update_button;
199 }
200 ?>
201 <div id="activitypub-header-image-preview-wrapper" class="<?php echo \esc_attr( $classes_for_wrapper ); ?>">
202 <img id="activitypub-header-image-preview" src="<?php echo \esc_url( \wp_get_attachment_url( $header_image ) ); ?>" style="max-width: 100%;" alt="" />
203 </div>
204 <button
205 type="button"
206 id="activitypub-choose-from-library-button"
207 class="<?php echo \esc_attr( $classes_for_button ); ?>"
208 data-alt-classes="<?php echo \esc_attr( $classes_for_button_on_change ); ?>"
209 data-choose-text="<?php \esc_attr_e( 'Choose a Header Image', 'activitypub' ); ?>"
210 data-update-text="<?php \esc_attr_e( 'Change Header Image', 'activitypub' ); ?>"
211 data-update="<?php \esc_attr_e( 'Set as Header Image', 'activitypub' ); ?>"
212 data-width="1500"
213 data-height="500"
214 <?php
215 if ( ! \current_user_can( 'edit_others_posts' ) ) :
216 \printf( 'data-user-id="%s"', \esc_attr( \get_current_user_id() ) );
217 endif;
218 ?>
219 data-state="<?php echo \esc_attr( (int) $header_image ); ?>">
220 <?php echo (int) $header_image ? \esc_html__( 'Change Header Image', 'activitypub' ) : \esc_html__( 'Choose a Header Image', 'activitypub' ); ?>
221 </button>
222 <button
223 id="activitypub-remove-header-image"
224 type="button"
225 <?php echo (int) $header_image ? 'class="button button-secondary reset"' : 'class="button button-secondary reset hidden"'; ?>>
226 <?php \esc_html_e( 'Remove Header Image', 'activitypub' ); ?>
227 </button>
228 <input type="hidden" name="activitypub_header_image" id="activitypub_header_image" value="<?php echo \esc_attr( $header_image ); ?>">
229 <?php
230 }
231
232 /**
233 * Notifications field callback.
234 */
235 public static function notifications_callback() {
236 ?>
237 <fieldset id="activitypub-notifications">
238 <p>
239 <label>
240 <input type="checkbox" name="activitypub_mailer_new_follower" id="activitypub_mailer_new_follower" value="1" <?php \checked( 1, \get_user_option( 'activitypub_mailer_new_follower' ) ); ?> />
241 <?php \esc_html_e( 'New Followers', 'activitypub' ); ?>
242 </label>
243 </p>
244 <p>
245 <label>
246 <input type="checkbox" name="activitypub_mailer_new_dm" id="activitypub_mailer_new_dm" value="1" <?php \checked( 1, \get_user_option( 'activitypub_mailer_new_dm' ) ); ?> />
247 <?php \esc_html_e( 'Direct Messages', 'activitypub' ); ?>
248 </label>
249 </p>
250 <p>
251 <label>
252 <input type="checkbox" name="activitypub_mailer_new_mention" id="activitypub_mailer_new_mention" value="1" <?php \checked( 1, \get_user_option( 'activitypub_mailer_new_mention' ) ); ?> />
253 <?php \esc_html_e( 'New Mentions', 'activitypub' ); ?>
254 </label>
255 </p>
256 <p>
257 <label>
258 <input type="checkbox" name="activitypub_mailer_new_reaction" id="activitypub_mailer_new_reaction" value="1" <?php \checked( 1, \get_user_option( 'activitypub_mailer_new_reaction' ) ); ?> />
259 <?php \esc_html_e( 'Likes, Reposts and Quotes', 'activitypub' ); ?>
260 </label>
261 </p>
262 <p>
263 <label>
264 <input type="checkbox" name="activitypub_mailer_annual_report" id="activitypub_mailer_annual_report" value="1" <?php \checked( 1, \get_user_option( 'activitypub_mailer_annual_report' ) ); ?> />
265 <?php \esc_html_e( 'Annual Report', 'activitypub' ); ?>
266 </label>
267 </p>
268 <p>
269 <label>
270 <input type="checkbox" name="activitypub_mailer_monthly_report" id="activitypub_mailer_monthly_report" value="1" <?php \checked( 1, \get_user_option( 'activitypub_mailer_monthly_report' ) ); ?> />
271 <?php \esc_html_e( 'Monthly Report', 'activitypub' ); ?>
272 </label>
273 </p>
274 </fieldset>
275 <?php
276 }
277
278 /**
279 * Extra fields callback.
280 */
281 public static function extra_fields_callback() {
282 $extra_fields = Extra_Fields::get_actor_fields( \get_current_user_id() );
283 ?>
284 <p class="description">
285 <?php \esc_html_e( 'Your homepage, social profiles, pronouns, age, anything you want.', 'activitypub' ); ?>
286 </p>
287
288 <?php if ( ! empty( $extra_fields ) ) : ?>
289 <table class="widefat striped activitypub-extra-fields" role="presentation" style="margin: 15px 0;">
290 <?php foreach ( $extra_fields as $extra_field ) : ?>
291 <tr>
292 <td><?php echo \esc_html( $extra_field->post_title ); ?></td>
293 <td><?php echo \wp_kses_post( \get_the_excerpt( $extra_field ) ); ?></td>
294 <td>
295 <a href="<?php echo \esc_url( \get_edit_post_link( $extra_field->ID ) ); ?>" class="button">
296 <?php \esc_html_e( 'Edit', 'activitypub' ); ?>
297 </a>
298 </td>
299 </tr>
300 <?php endforeach; ?>
301 </table>
302 <?php endif; ?>
303
304 <p class="extra-fields-nav">
305 <a href="<?php echo \esc_url( \admin_url( '/post-new.php?post_type=ap_extrafield' ) ); ?>" class="button">
306 <?php \esc_html_e( 'Add new', 'activitypub' ); ?>
307 </a>
308 <a href="<?php echo \esc_url( \admin_url( '/edit.php?post_type=ap_extrafield' ) ); ?>">
309 <?php \esc_html_e( 'Manage all', 'activitypub' ); ?>
310 </a>
311 </p>
312 <?php
313 }
314
315 /**
316 * Also Known As field callback.
317 */
318 public static function also_known_as_callback() {
319 $also_known_as = \get_user_option( 'activitypub_also_known_as', \get_current_user_id() );
320 ?>
321 <textarea
322 class="large-text"
323 name="activitypub_also_known_as"
324 id="activitypub_also_known_as"
325 rows="5"
326 ><?php echo \esc_textarea( \implode( PHP_EOL, (array) $also_known_as ) ); ?></textarea>
327 <p class="description">
328 <?php \esc_html_e( 'If you&#8217;re moving from another account to this one, you&#8217;ll need to create an alias here first before transferring your followers. This step is safe, reversible, and doesn&#8217;t affect anything on its own. The migration itself is initiated from your old account.', 'activitypub' ); ?>
329 </p>
330 <p class="description">
331 <?php echo \wp_kses_post( \__( 'Enter one account per line. Profile links or usernames like <code>@username@example.com</code> are accepted and will be automatically normalized to the correct format.', 'activitypub' ) ); ?>
332 </p>
333 <?php
334 }
335
336 /**
337 * Moderation section description callback.
338 */
339 public static function moderation_section_description() {
340 echo '<p>' . \esc_html__( 'Configure personal blocks to filter ActivityPub content you don\'t want to see.', 'activitypub' ) . '</p>';
341 }
342
343 /**
344 * Blocked domains field callback.
345 */
346 public static function blocked_domains_callback() {
347 $user_id = \get_current_user_id();
348 $blocked_domains = Moderation::get_user_blocks( $user_id )['domains'];
349 ?>
350 <p class="description"><?php \esc_html_e( 'Block entire ActivityPub instances by domain name.', 'activitypub' ); ?></p>
351
352 <div class="activitypub-user-block-list" data-user-id="<?php echo \esc_attr( $user_id ); ?>">
353 <?php if ( ! empty( $blocked_domains ) ) : ?>
354 <table class="widefat striped activitypub-blocked-domain" role="presentation" style="max-width: 500px; margin: 15px 0;">
355 <?php foreach ( $blocked_domains as $domain ) : ?>
356 <tr>
357 <td><?php echo \esc_html( $domain ); ?></td>
358 <td style="width: 80px;">
359 <button type="button" class="button button-small remove-user-block-btn" data-type="domain" data-value="<?php echo \esc_attr( $domain ); ?>">
360 <?php \esc_html_e( 'Remove', 'activitypub' ); ?>
361 </button>
362 </td>
363 </tr>
364 <?php endforeach; ?>
365 </table>
366 <?php endif; ?>
367
368 <div class="add-user-block-form" style="display: flex; max-width: 500px; gap: 8px;">
369 <input type="text" class="regular-text" id="new_user_domain" placeholder="<?php \esc_attr_e( 'example.com', 'activitypub' ); ?>" style="flex: 1; min-width: 0;" />
370 <button type="button" class="button add-user-block-btn" data-type="domain" style="flex-shrink: 0; white-space: nowrap;">
371 <?php \esc_html_e( 'Add Block', 'activitypub' ); ?>
372 </button>
373 </div>
374 </div>
375 <?php
376 }
377
378 /**
379 * Blocked keywords field callback.
380 */
381 public static function blocked_keywords_callback() {
382 $user_id = \get_current_user_id();
383 $blocked_keywords = Moderation::get_user_blocks( $user_id )['keywords'];
384 ?>
385 <p class="description"><?php \esc_html_e( 'Block ActivityPub content containing specific keywords.', 'activitypub' ); ?></p>
386
387 <div class="activitypub-user-block-list" data-user-id="<?php echo \esc_attr( $user_id ); ?>">
388 <?php if ( ! empty( $blocked_keywords ) ) : ?>
389 <table class="widefat striped activitypub-blocked-keyword" role="presentation" style="max-width: 500px; margin: 15px 0;">
390 <?php foreach ( $blocked_keywords as $keyword ) : ?>
391 <tr>
392 <td><?php echo \esc_html( $keyword ); ?></td>
393 <td style="width: 80px;">
394 <button type="button" class="button button-small remove-user-block-btn" data-type="keyword" data-value="<?php echo \esc_attr( $keyword ); ?>">
395 <?php \esc_html_e( 'Remove', 'activitypub' ); ?>
396 </button>
397 </td>
398 </tr>
399 <?php endforeach; ?>
400 </table>
401 <?php endif; ?>
402
403 <div class="add-user-block-form" style="display: flex; max-width: 500px; gap: 8px;">
404 <input type="text" class="regular-text" id="new_user_keyword" placeholder="<?php \esc_attr_e( 'spam keyword', 'activitypub' ); ?>" style="flex: 1; min-width: 0;" />
405 <button type="button" class="button add-user-block-btn" data-type="keyword" style="flex-shrink: 0; white-space: nowrap;">
406 <?php \esc_html_e( 'Add Block', 'activitypub' ); ?>
407 </button>
408 </div>
409 </div>
410 <?php
411 }
412
413 /**
414 * Render the Connected Applications section on the profile page.
415 *
416 * Rendered as a standalone section (like core's Application Passwords),
417 * not through the Settings API.
418 *
419 * @since 8.1.0
420 */
421 public static function connected_apps_section() {
422 $tokens = Token::get_all_for_user( \get_current_user_id() );
423 $clients = Client::get_manually_registered();
424
425 ?>
426 <div class="activitypub-connected-apps hide-if-no-js" id="activitypub-connected-apps-section">
427 <h2><?php \esc_html_e( 'OAuth Applications', 'activitypub' ); ?></h2>
428 <p><?php \esc_html_e( 'Register OAuth applications to connect third-party clients to your account, or revoke access for existing ones.', 'activitypub' ); ?></p>
429
430 <div class="create-application-password form-wrap" id="activitypub-new-application">
431 <div class="form-field">
432 <label for="activitypub-new-app-name"><?php \esc_html_e( 'New Application Name', 'activitypub' ); ?></label>
433 <input type="text" size="30" id="activitypub-new-app-name" class="input" aria-required="true" spellcheck="false" />
434 </div>
435 <div class="form-field">
436 <label for="activitypub-new-app-redirect-uri"><?php \esc_html_e( 'Redirect URI', 'activitypub' ); ?></label>
437 <input type="url" size="30" id="activitypub-new-app-redirect-uri" class="input" aria-required="true" spellcheck="false" />
438 </div>
439 <button type="button" class="button button-secondary" id="activitypub-register-app">
440 <?php \esc_html_e( 'Register Application', 'activitypub' ); ?>
441 </button>
442 </div>
443
444 <div class="activitypub-registered-apps-wrapper" id="activitypub-registered-apps-wrapper" <?php echo empty( $clients ) ? 'style="display: none;"' : ''; ?>>
445 <h3><?php \esc_html_e( 'Registered Applications', 'activitypub' ); ?></h3>
446 <table class="wp-list-table widefat fixed striped table-view-list">
447 <thead>
448 <tr>
449 <th scope="col"><?php \esc_html_e( 'Name', 'activitypub' ); ?></th>
450 <th scope="col"><?php \esc_html_e( 'Redirect URI', 'activitypub' ); ?></th>
451 <th scope="col"><?php \esc_html_e( 'Created', 'activitypub' ); ?></th>
452 <th scope="col"><?php \esc_html_e( 'Delete', 'activitypub' ); ?></th>
453 </tr>
454 </thead>
455 <tbody id="activitypub-registered-apps-tbody">
456 <?php foreach ( $clients as $client ) : ?>
457 <?php
458 $redirect_uris = $client->get_redirect_uris();
459 $redirect_uri = ! empty( $redirect_uris ) ? $redirect_uris[0] : '&mdash;';
460 $post = \get_post( $client->get_post_id() );
461 $created = $post ? \date_i18n( \get_option( 'date_format' ), \strtotime( $post->post_date ) ) : '&mdash;';
462 ?>
463 <tr data-client-id="<?php echo \esc_attr( $client->get_client_id() ); ?>">
464 <td><?php echo \esc_html( $client->get_name() ); ?></td>
465 <td><?php echo \esc_html( $redirect_uri ); ?></td>
466 <td><?php echo \esc_html( $created ); ?></td>
467 <td>
468 <?php
469 \printf(
470 '<button type="button" class="button delete" aria-label="%1$s">%2$s</button>',
471 /* translators: %s: the application name */
472 \esc_attr( \sprintf( \__( 'Delete "%s"', 'activitypub' ), $client->get_name() ) ),
473 \esc_html__( 'Delete', 'activitypub' )
474 );
475 ?>
476 </td>
477 </tr>
478 <?php endforeach; ?>
479 </tbody>
480 <tfoot>
481 <tr>
482 <th scope="col"><?php \esc_html_e( 'Name', 'activitypub' ); ?></th>
483 <th scope="col"><?php \esc_html_e( 'Redirect URI', 'activitypub' ); ?></th>
484 <th scope="col"><?php \esc_html_e( 'Created', 'activitypub' ); ?></th>
485 <th scope="col"><?php \esc_html_e( 'Delete', 'activitypub' ); ?></th>
486 </tr>
487 </tfoot>
488 </table>
489 <div class="tablenav bottom">
490 <div class="alignright">
491 <button type="button" class="button delete" id="activitypub-delete-all-clients">
492 <?php \esc_html_e( 'Delete all registered applications', 'activitypub' ); ?>
493 </button>
494 </div>
495 </div>
496 </div>
497
498 <?php if ( ! empty( $tokens ) ) : ?>
499 <div class="activitypub-connected-apps-list-table-wrapper">
500 <h3><?php \esc_html_e( 'Active Tokens', 'activitypub' ); ?></h3>
501 <table class="wp-list-table widefat fixed striped table-view-list">
502 <thead>
503 <tr>
504 <th scope="col"><?php \esc_html_e( 'Name', 'activitypub' ); ?></th>
505 <th scope="col"><?php \esc_html_e( 'Scopes', 'activitypub' ); ?></th>
506 <th scope="col"><?php \esc_html_e( 'Created', 'activitypub' ); ?></th>
507 <th scope="col"><?php \esc_html_e( 'Last Used', 'activitypub' ); ?></th>
508 <th scope="col"><?php \esc_html_e( 'Revoke', 'activitypub' ); ?></th>
509 </tr>
510 </thead>
511 <tbody id="activitypub-connected-apps-tbody">
512 <?php foreach ( $tokens as $token ) : ?>
513 <?php
514 $client_id = $token['client_id'] ?? '';
515 $client = Client::get( $client_id );
516 $client_name = ! \is_wp_error( $client ) ? $client->get_name() : $client_id;
517 $scopes = isset( $token['scopes'] ) ? Scope::to_string( $token['scopes'] ) : '';
518 $created = ! empty( $token['created_at'] ) ? \date_i18n( \get_option( 'date_format' ), $token['created_at'] ) : '&mdash;';
519 $last_used = ! empty( $token['last_used_at'] ) ? \date_i18n( \get_option( 'date_format' ), $token['last_used_at'] ) : '&mdash;';
520 $meta_key = $token['meta_key'] ?? ''; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Not a DB query, just array key.
521 ?>
522 <tr data-meta-key="<?php echo \esc_attr( $meta_key ); ?>">
523 <td><?php echo \esc_html( $client_name ); ?></td>
524 <td><?php echo \esc_html( $scopes ); ?></td>
525 <td><?php echo \esc_html( $created ); ?></td>
526 <td><?php echo $last_used; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Contains only escaped date or &mdash; entity. ?></td>
527 <td>
528 <?php
529 \printf(
530 '<button type="button" class="button delete" aria-label="%1$s">%2$s</button>',
531 /* translators: %s: the application name */
532 \esc_attr( \sprintf( \__( 'Revoke "%s"', 'activitypub' ), $client_name ) ),
533 \esc_html__( 'Revoke', 'activitypub' )
534 );
535 ?>
536 </td>
537 </tr>
538 <?php endforeach; ?>
539 </tbody>
540 <tfoot>
541 <tr>
542 <th scope="col"><?php \esc_html_e( 'Name', 'activitypub' ); ?></th>
543 <th scope="col"><?php \esc_html_e( 'Scopes', 'activitypub' ); ?></th>
544 <th scope="col"><?php \esc_html_e( 'Created', 'activitypub' ); ?></th>
545 <th scope="col"><?php \esc_html_e( 'Last Used', 'activitypub' ); ?></th>
546 <th scope="col"><?php \esc_html_e( 'Revoke', 'activitypub' ); ?></th>
547 </tr>
548 </tfoot>
549 </table>
550 <div class="tablenav bottom">
551 <div class="alignright">
552 <button type="button" class="button delete" id="activitypub-revoke-all-tokens">
553 <?php \esc_html_e( 'Revoke all connected applications', 'activitypub' ); ?>
554 </button>
555 </div>
556 </div>
557 </div>
558 <?php endif; ?>
559 </div>
560 <?php
561 }
562
563 /**
564 * Hide Social Graph field callback.
565 */
566 public static function hide_followers_callback() {
567 $hide_followers = \get_user_option( 'activitypub_hide_social_graph', \get_current_user_id() );
568 ?>
569 <label>
570 <input type="checkbox" name="activitypub_hide_social_graph" id="activitypub_hide_social_graph" value="1" <?php \checked( '1', $hide_followers ); ?> />
571 <?php \esc_html_e( 'Hide Followers and Following on Profile', 'activitypub' ); ?>
572 </label>
573 <p class="description">
574 <?php \esc_html_e( 'People you follow will still see that you follow them.', 'activitypub' ); ?>
575 </p>
576 <?php
577 }
578 }
579