PluginProbe
Content Control – The Ultimate Content Restriction Plugin! Restrict Content, Create Conditional Blocks & More / 2.0.2
Content Control – The Ultimate Content Restriction Plugin! Restrict Content, Create Conditional Blocks & More v2.0.2
trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.1.0 1.1.1 1.1.10 1.1.2 1.1.3 1.1.4 1.1.5 1.1.6 1.1.7 1.1.8 2.0.0 2.0.1 2.0.10 2.0.11 2.0.12 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 All 47 releases
content-control / vendor-prefixed / trustedlogin / client / src / Form.php

Form.php in Content Control – The Ultimate Content Restriction Plugin! Restrict Content, Create Conditional Blocks & More 2.0.2, at vendor-prefixed/trustedlogin/client/src/Form.php

1,394 lines 45.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @license GPL-2.0-or-later
4 *
5 * Modified by code-atlantic on 18-September-2023 using Strauss.
6 * @see https://github.com/BrianHenryIE/strauss
7 */
8
9 /**
10 * Class Form
11 *
12 * @package ContentControl\Vendor\TrustedLogin\Client
13 *
14 * @copyright 2021 Katz Web Services, Inc.
15 */
16
17 namespace ContentControl\Vendor\TrustedLogin;
18
19 // Exit if accessed directly
20 if ( ! defined( 'ABSPATH' ) ) {
21 exit;
22 }
23
24 use \WP_User;
25
26
27 /**
28 * Creates the TrustedLogin support user form.
29 * - Makes the HTML
30 * - Manages assets
31 * Does not
32 * - Handle the form submission. {@see ./Ajax.php }
33 * - Setup the menu {@see ./Admin.php}
34 *
35 * @since 1.5.0
36 */
37 final class Form {
38
39 /**
40 * URL pointing to the "About TrustedLogin" page, shown below the Grant Access dialog
41 */
42 const ABOUT_TL_URL = 'https://www.trustedlogin.com/about/easy-and-safe/';
43
44 const ABOUT_LIVE_ACCESS_URL = 'https://www.trustedlogin.com/about/live-access/';
45
46 /**
47 * @var Config
48 */
49 private $config;
50
51 /**
52 * @var SiteAccess $site_access
53 */
54 private $site_access;
55
56 /**
57 * @var SupportUser $support_user
58 */
59 private $support_user;
60
61 /**
62 * @var null|Logging $logging
63 */
64 private $logging;
65
66 /**
67 * Admin constructor.
68 *
69 * @param Config $config
70 */
71 public function __construct( Config $config, Logging $logging, SupportUser $support_user, SiteAccess $site_access ) {
72 $this->config = $config;
73 $this->logging = $logging;
74 $this->support_user = $support_user;
75 $this->site_access = $site_access;
76 }
77
78 /**
79 * Register the required scripts and styles
80 *
81 * @since 1.0.0
82 */
83 public function register_assets() {
84
85 $registered = array();
86
87 // Already registered by the integrating code.
88 if ( wp_script_is( 'trustedlogin-' . $this->config->ns() ) ) {
89 $registered['trustedlogin-js'] = true;
90 } else {
91 $registered['trustedlogin-js'] = wp_register_script(
92 'trustedlogin-' . $this->config->ns(),
93 $this->config->get_setting( 'paths/js' ),
94 array( 'jquery', 'wp-a11y' ),
95 Client::VERSION,
96 true
97 );
98 }
99
100 if ( wp_style_is( 'trustedlogin-' . $this->config->ns() ) ) {
101 $registered['trustedlogin-css'] = true;
102 } else {
103 $registered['trustedlogin-css'] = wp_register_style(
104 'trustedlogin-' . $this->config->ns(),
105 $this->config->get_setting( 'paths/css' ),
106 array(),
107 Client::VERSION,
108 'all'
109 );
110 }
111
112 $registered_filtered = array_filter( $registered );
113
114 if ( count( $registered ) !== count( $registered_filtered ) ) {
115 $this->logging->log( 'Not all scripts and styles were registered: ' . print_r( $registered_filtered, true ), __METHOD__, 'error' );
116 }
117 }
118
119 /**
120 * If the current request is a valid login screen override, print the TrustedLogin request screen.
121 *
122 * @return void
123 */
124 public function maybe_print_request_screen() {
125
126 if ( ! $this->is_login_screen() ) {
127 return;
128 }
129
130 // Once logged-in, take user back to auth request screen.
131 if ( ! is_user_logged_in() ) {
132 $_REQUEST['redirect_to'] = site_url( add_query_arg( array() ) );
133
134 return;
135 }
136
137 if ( ! current_user_can( 'create_users' ) ) {
138 return;
139 }
140
141 $this->print_request_screen();
142 }
143
144 public function print_request_screen() {
145 global $interim_login, $wp_version;
146
147 // Don't output a "← Back to site" link on the login page
148 $interim_login = true;
149
150 // The login_headertitle filter was deprecated in WP 5.2.0 for login_headertext
151 if ( version_compare( $wp_version, '5.2.0', '<' ) ) {
152 add_filter( 'login_headertitle', '__return_empty_string' );
153 } else {
154 add_filter( 'login_headertext', '__return_empty_string' );
155 }
156
157 add_filter( 'login_headerurl', function () {
158 return $this->config->get_setting( 'vendor/website' );
159 } );
160
161 login_header();
162
163 wp_enqueue_style( 'common' );
164
165 wp_add_inline_style( 'common', $this->get_login_inline_css() );
166
167 echo $this->get_auth_screen();
168
169 login_footer();
170
171 die();
172 }
173
174 /**
175 * Returns inline CSS overrides for the `common` CSS dependency
176 *
177 * @since 1.0.0
178 *
179 * @return string
180 */
181 private function get_login_inline_css() {
182 return '
183 #login {
184 width: auto;
185 }
186 .login .button-primary {
187 float: none;
188 }
189 .login h1 {
190 margin-top: 36px;
191 }
192 .login h1 a {
193 background-image: url("' . $this->config->get_setting( 'vendor/logo_url' ) . '")!important;
194 background-size: contain!important;
195 }
196 ';
197 }
198
199 /**
200 * Outputs the TrustedLogin authorization screen
201 *
202 * @since 1.0.0
203 *
204 * @return void
205 */
206 public function print_auth_screen() {
207 echo $this->get_auth_screen();
208 }
209
210 public function get_auth_header_html() {
211 $support_users = $this->support_user->get_all();
212
213 if ( empty( $support_users ) ) {
214 return '';
215 }
216
217 $support_user = $support_users[0];
218
219 $_user_creator_id = get_user_option( $this->support_user->created_by_meta_key, $support_user->ID );
220 $_user_creator = $_user_creator_id ? get_user_by( 'id', $_user_creator_id ) : false;
221
222 // translators: %s is the ID of the user who created the support session. The user can't be found; only the User ID is known.
223 $unknown_user_text = sprintf( esc_html__( 'Unknown (User #%d)', 'trustedlogin' ), $_user_creator_id );
224
225 $auth_meta = ( $_user_creator && $_user_creator->exists() ) ? esc_html( $_user_creator->display_name ) : $unknown_user_text;
226
227 $revoke_url = $this->support_user->get_revoke_url( $support_user );
228
229 $template = '
230 {{revoke_access_button}}
231 <h3>{{display_name}}</h3>
232 <span class="tl-{{ns}}-auth__meta">{{auth_meta}}</span>';
233
234 $content = array(
235 'display_name' => $support_user->display_name,
236 'revoke_access_button' => sprintf( '<a href="%s" class="button button-danger alignright tl-client-revoke-button">%s</a>', $revoke_url, esc_html__( 'Revoke Access', 'trustedlogin' ) ),
237 // translators: %s is the display name of the user who granted access
238 'auth_meta' => sprintf( esc_html__( 'Created %s ago by %s', 'trustedlogin' ), human_time_diff( strtotime( $support_user->user_registered ) ), $auth_meta ),
239 );
240
241 return $this->prepare_output( $template, $content );
242 }
243
244 /**
245 * Output the contents of the Auth Link Page in wp-admin
246 *
247 * @since 1.0.0
248 *
249 * @return string HTML of the Auth screen
250 */
251 public function get_auth_screen() {
252
253 wp_enqueue_style( 'trustedlogin-' . $this->config->ns() );
254
255 $content = array(
256 'ns' => $this->config->ns(),
257 'has_access_class' => $this->support_user->get_all() ? 'has-access' : 'grant-access',
258 'notices' => $this->get_notices_html(),
259 'header' => $this->get_header_html(),
260 'intro' => $this->get_intro(),
261 'auth_header' => $this->get_auth_header_html(),
262 'details' => $this->get_details_html(),
263 'button' => $this->generate_button( 'size=hero&class=authlink button-primary tl-client-grant-button', false ),
264 'secured_by_trustedlogin' => '<span class="trustedlogin-logo-medium"></span>' . esc_html__( 'Secured by TrustedLogin', 'trustedlogin' ),
265 'footer' => $this->get_footer_html(),
266 'reference' => $this->get_reference_html(),
267 'admin_debug' => $this->get_admin_debug_html(),
268 'terms_of_service' => $this->get_terms_of_service_html(),
269 );
270
271 $auth_screen_template = '
272 <div class="tl-{{ns}}-auth tl-{{ns}}-{{has_access_class}}">
273 {{header}}
274 <section class="tl-{{ns}}-auth__body">
275 <h2 class="tl-{{ns}}-auth__intro">{{intro}}</h2>
276 <div class="tl-{{ns}}-auth__content">
277 <header class="tl-{{ns}}-auth__header">
278 {{auth_header}}
279 </header>
280 <div class="tl-{{ns}}-auth__details">
281 {{details}}
282 </div>
283 <div class="tl-{{ns}}-auth__response" aria-live="assertive"></div>
284 {{notices}}
285 <div class="tl-{{ns}}-auth__actions">
286 {{button}}
287 </div>
288 {{terms_of_service}}
289 </div>
290 <div class="tl-{{ns}}-auth__secured_by">{{secured_by_trustedlogin}}</div>
291 </section>
292 <footer class="tl-{{ns}}-auth__footer">
293 {{footer}}
294 {{reference}}
295 </footer>
296 {{admin_debug}}
297 </div>';
298
299 /**
300 * Filter trustedlogin/{ns}/template/auth
301 *
302 * @param string $output_template The Auth form HTML
303 */
304 $auth_screen_template = apply_filters( 'trustedlogin/' . $this->config->ns() . '/template/auth', $auth_screen_template );
305
306 $output = $this->prepare_output( $auth_screen_template, $content );
307
308 return $output;
309 }
310
311 private function get_header_html() {
312
313 if ( $this->is_login_screen() ) {
314 return '';
315 }
316
317 $header_template = '
318 <header class="tl-{{ns}}-auth__header__top">
319 <div class="tl-{{ns}}-auth__logo">{{logo}}</div>
320 </header>';
321
322 $variables = array(
323 'ns' => $this->config->ns(),
324 'logo' => $this->get_logo_html(),
325 );
326
327 return $this->prepare_output( $header_template, $variables );
328 }
329
330 /**
331 * Returns the HTML for the optional Terms of Service agreement text & link.
332 *
333 * @since 1.6.0
334 *
335 * @return string Empty if `terms_of_service/url` setting is not set.
336 */
337 private function get_terms_of_service_html() {
338
339 $terms_of_service_url = $this->config->get_setting( 'terms_of_service/url' );
340
341 if ( ! $terms_of_service_url ) {
342 return '';
343 }
344
345 /**
346 * Filter trustedlogin/{ns}/template/auth/terms_of_service/anchor.
347 * @since 1.6.0
348 * @param string $tos_anchor The text of the link to the Terms of Service.
349 */
350 $tos_anchor = apply_filters( 'trustedlogin/' . $this->config->ns() . '/template/auth/terms_of_service/anchor', esc_html__( 'Terms of Service', 'trustedlogin' ) );
351
352 $tos_link_template = '<a href="{{url}}" target="_blank" rel="noopener noreferrer">{{anchor}}</a>';
353
354 $tos_link_variables = array(
355 'url' => esc_url( $terms_of_service_url ),
356 'anchor' => esc_html( $tos_anchor ),
357 );
358
359 $terms_of_service_template = '
360 <div class="tl-{{ns}}-auth__tos">
361 <p>{{tos_text}}</p>
362 </div>';
363
364 $variables = array(
365 'ns' => $this->config->ns(),
366 'tos_text' => esc_html__( 'By granting access, you agree to the {{tos_link}}.', 'trustedlogin' ),
367 'tos_link' => $this->prepare_output( $tos_link_template, $tos_link_variables ),
368 );
369
370 return $this->prepare_output( $terms_of_service_template, $variables );
371 }
372
373 /**
374 * Shows the current site URL and, if passed as $_GET['ref'], a support reference ID
375 *
376 * @return string Empty string if there is no reference or if the `trustedlogin/{ns}/template/auth/display_reference` filter returns false.
377 */
378 private function get_reference_html() {
379
380 $reference_id = Client::get_reference_id();
381
382 if ( null === $reference_id ) {
383 return '';
384 }
385
386 /**
387 * Filter trustedlogin/{ns}/template/auth/display_reference
388 *
389 * Used to hide or show the reference ID in the auth screen template.
390 *
391 * @since 1.3
392 *
393 * @param bool $display_reference Whether to display the reference ID on the auth screen. Default: true.
394 * @param bool $is_login_screen Whether the auth form is being displayed on the login screen.
395 * @param string $ref The reference ID.
396 */
397 $display_reference = apply_filters( 'trustedlogin/' . $this->config->ns() . '/template/auth/display_reference', true, $this->is_login_screen(), $reference_id );
398
399 if ( ! $display_reference ) {
400 return '';
401 }
402
403 $template = '<div class="tl-{{ns}}-auth__ref"><p><span class="tl-{{ns}}-auth_ref__id">{{reference_text}}</span></p></div>';
404
405 $content = array(
406 // translators: %s is the reference ID
407 'reference_text' => sprintf( esc_html__( 'Reference #%s', 'trustedlogin' ), $reference_id ),
408 'ns' => $this->config->ns(),
409 'site_url' => esc_html( str_replace( array( 'https://', 'http://' ), '', get_site_url() ) ),
410 );
411
412 return $this->prepare_output( $template, $content );
413 }
414
415 private function get_intro() {
416
417
418 $has_access = $this->support_user->get_all();
419
420 if ( $has_access ) {
421 foreach ( $has_access as $access ) {
422 // translators: %1$s is replaced with the name of the software developer (e.g. "Acme Widgets"). %2$s is the amount of time remaining for access ("1 week")
423 $intro = sprintf( esc_html__( '%1$s has site access that expires in %2$s.', 'trustedlogin' ), '<a href="' . esc_url( $this->config->get_setting( 'vendor/website' ) ) . '" target="_blank" rel="noopener noreferrer">' . $this->config->get_setting( 'vendor/title' ) . '</a>', str_replace( ' ', '&nbsp;', $this->support_user->get_expiration( $access, true, false ) ) );
424 }
425
426 return $intro;
427 }
428
429 if ( $this->is_login_screen() ) {
430 // translators: %1$s is replaced with the name of the software developer (e.g. "Acme Widgets")
431 $intro = sprintf( esc_html__( '%1$s would like support access to this site.', 'trustedlogin' ), '<a href="' . esc_url( $this->config->get_setting( 'vendor/website' ) ) . '">' . $this->config->get_display_name() . '</a>' );
432 } else {
433 // translators: %1$s is replaced with the name of the software developer (e.g. "Acme Widgets")
434 $intro = sprintf( esc_html__( 'Grant %1$s access to this site.', 'trustedlogin' ), '<a href="' . esc_url( $this->config->get_setting( 'vendor/website' ) ) . '">' . $this->config->get_display_name() . '</a>' );
435 }
436
437 return $intro;
438 }
439
440 /**
441 * Returns whether sending support ticket to the vendor is enabled.
442 *
443 * @since 1.5.0
444 * @return bool
445 */
446 private function is_create_ticket_enabled() {
447
448 // There's already an existing ticket; no need to create another one.
449 if ( Client::get_reference_id() ) {
450 return false;
451 }
452
453 return $this->config->get_setting( 'webhook/url' ) && $this->config->get_setting( 'webhook/create_ticket', false );
454 }
455
456 /**
457 * Returns whether sending debug data to the support vendor is enabled.
458 *
459 * @since 1.5.0
460 * @return bool
461 */
462 private function is_debug_data_enabled() {
463 return $this->config->get_setting( 'webhook/url' ) && $this->config->get_setting( 'webhook/debug_data', false );
464 }
465
466 private function get_details_html() {
467
468 $has_access = $this->support_user->get_all();
469
470 // Has access
471 if ( $has_access ) {
472 $output_template = '';
473 $output_template .= '{{users_table}}';
474 $content = array(
475 'users_table' => $this->output_support_users( false, array( 'current_url' => true ) ),
476 );
477
478 return $this->prepare_output( $output_template, $content, false );
479 }
480
481 $ns = $this->config->ns();
482
483 $output_template = '
484 <p><span class="dashicons dashicons-info-outline dashicons--small"></span> This will allow <strong>{{name}}</strong> to:</p>
485 <div class="tl-{{ns}}-auth__roles">
486 <h2>
487 <span class="dashicons dashicons-admin-users dashicons--large"></span>{{roles_summary}}
488 </h2>
489 {{caps}}
490 </div>
491 <div class="tl-{{ns}}-auth__expire">
492 <h2>
493 <span class="dashicons dashicons-clock dashicons--large"></span>{{expire_summary}}{{expire_desc}}
494 </h2>
495 </div>
496 ';
497
498 if ( $this->is_create_ticket_enabled() ) {
499
500 $message_summary = sprintf(
501 '<span
502 class="tl-{{ns}}-toggle"
503 data-toggle=".tl-{{ns}}-ticket__fields">
504 %s <span class="dashicons dashicons--small dashicons-arrow-down-alt2"></span>
505 </span>',
506 esc_html__( 'Include a message for support?', 'trustedlogin' )
507 );
508
509 $message_fields = sprintf( '
510 <fieldset class="tl-{{ns}}-ticket__fields hidden">
511 <textarea
512 class="tl-{{ns}}-ticket-field__message large-text"
513 id="tl-{{ns}}-ticket-message"
514 placeholder="%s"
515 cols="50"
516 rows="8"
517 ></textarea>
518 </fieldset>
519 ', esc_html__( 'Please describe the issue you are having.', 'trustedlogin' ) );
520
521 $output_template .= $this->prepare_output( '<div class="tl-{{ns}}-ticket">
522 <h2>
523 <span class="dashicons dashicons-format-chat dashicons--large"></span>
524 {{message_summary}}
525 </h2>
526 {{message_fields}}
527 </div>', array(
528 'ns' => $ns,
529 'message_summary' => $this->prepare_output( $message_summary, array( 'ns' => $ns ) ),
530 'message_fields' => $this->prepare_output( $message_fields, array( 'ns' => $ns ) ),
531 )
532 );
533 }
534
535 if ( $this->is_debug_data_enabled() ) {
536 $output_template .= '
537 <div class="tl-{{ns}}-auth__debug">
538 {{debug_data_consent}}
539 </div>';
540 }
541
542 // translators: %s is replaced with the of time that the login will be active for (e.g. "1 week")
543 $expire_summary = sprintf( esc_html__( 'Access this site for %s.', 'trustedlogin' ), '<strong>' . human_time_diff( 0, $this->config->get_setting( 'decay' ) ) . '</strong>' );
544
545 // translators: %s is replaced by the amount of time that the login will be active for (e.g. "1 week")
546 $expire_desc = '<small>' . sprintf( esc_html__( 'Access auto-expires in %s. You may revoke access at any time.', 'trustedlogin' ), human_time_diff( 0, $this->config->get_setting( 'decay' ) ) ) . '</small>';
547
548 $cloned_role = translate_user_role( ucfirst( $this->config->get_setting( 'role' ) ) );
549
550 if( $this->config->get_setting( 'clone_role' ) ) {
551
552 // translators: %s is replaced with the name of the role (e.g. "Administrator")
553 $roles_summary = sprintf( esc_html__( 'Create a user with a role based on %s.', 'trustedlogin' ), '<strong>' . $cloned_role . '</strong>' );
554
555 if ( $this->config->get_setting( 'caps/add' ) || $this->config->get_setting( 'caps/remove' ) ) {
556 $roles_summary .= sprintf( '<small class="tl-' . $ns . '-toggle" data-toggle=".tl-' . $ns . '-auth__role-container">%s <span class="dashicons dashicons--small dashicons-arrow-down-alt2"></span></small>', esc_html__( 'View modified role capabilities', 'trustedlogin' ) );
557 }
558
559 } else {
560
561 // translators: %s is replaced with the name of the role (e.g. "Administrator")
562 $roles_summary = sprintf( esc_html__( 'Create a user with a role of %s.', 'trustedlogin' ), '<strong>' . $cloned_role . '</strong>' );
563 }
564
565 $content = array(
566 'ns' => $ns,
567 'name' => $this->config->get_display_name(),
568 'expire_summary' => $expire_summary,
569 'expire_desc' => $expire_desc,
570 'debug_data_consent' => $this->get_debug_data_consent_html(),
571 'roles_summary' => $roles_summary,
572 'caps' => $this->get_caps_html(),
573 );
574
575 return $this->prepare_output( $output_template, $content );
576 }
577
578 /**
579 * Get the HTML for the debug data consent checkbox.
580 *
581 * This is only shown if the webhook/url is defined and webhook/debug_data setting is true.
582 *
583 * @since 1.4.0
584 *
585 * @return string
586 */
587 private function get_debug_data_consent_html() {
588
589 // translators: [link] and [/link] are replaced with a link to the Site Health page. Do not translate.
590 $output = sprintf( '<h2><label><input type="checkbox" id="tl-{{ns}}-debug-data-consent" class="tl-{{ns}}-auth__checkbox--large" /> %s</label></h2>', strtr( esc_html__( 'Include the [link]Site Health[/link] troubleshooting report', 'trustedlogin' ), array(
591 '[link]' => '<a href="' . esc_url( admin_url( 'site-health.php?tab=debug' ) ) . '">',
592 '[/link]' => '</a>',
593 ) ) );
594
595 $content = array(
596 'ns' => $this->config->ns(),
597 );
598
599 return $this->prepare_output( $output, $content );
600 }
601
602 /**
603 * Get role capabilities HTML the Auth form
604 *
605 * @return string Empty string if there are no caps defined. Otherwise, HTML of caps in lists.
606 */
607 private function get_caps_html() {
608
609 $added = $this->config->get_setting( 'caps/add' );
610 $removed = $this->config->get_setting( 'caps/remove' );
611
612 $caps = '';
613 $caps .= $this->get_caps_section( $added, __( 'Additional capabilities:', 'trustedlogin' ), 'dashicons-yes-alt' );
614 $caps .= $this->get_caps_section( $removed, __( 'Removed capabilities:', 'trustedlogin' ), 'dashicons-dismiss' );
615
616 if ( empty( $caps ) ) {
617 return $caps;
618 }
619
620 return '<div class="tl-' . $this->config->ns() . '-auth__role-container hidden">' . $caps . '</div>';
621 }
622
623 /**
624 * Generate additional/removed capabilities sections
625 *
626 * @param array $caps_array Associative array of cap => reason why cap is set
627 * @param string $heading Text to show for the heading of the caps section
628 * @param string $dashicon CSS class for the specific dashicon
629 *
630 * @return string
631 */
632 private function get_caps_section( $caps_array, $heading = '', $dashicon = '' ) {
633
634 $caps_array = array_filter( (array) $caps_array, array( $this->config, 'is_not_null' ) );
635
636 if ( empty( $caps_array ) ) {
637 return '';
638 }
639
640 $output = '';
641 $output .= '<div>';
642 $output .= '<h3>' . esc_html( $heading ) . '</h3>';
643 $output .= '<ul>';
644
645 foreach ( (array) $caps_array as $cap => $reason ) {
646 $dashicon = '<span class="dashicons ' . esc_attr( $dashicon ) . ' dashicons--small"></span>';
647 $reason = empty( $reason ) ? '' : '<small>' . esc_html( $reason ) . '</small>';
648 $output .= sprintf( '<li>%s<span class="code">%s</span>%s</li>', $dashicon, esc_html( $cap ), $reason );
649 }
650
651 $output .= '</ul>';
652 $output .= '</div>';
653
654 return $output;
655 }
656
657 /**
658 * Generates HTML for notices about current server environment perhaps not being accessible.
659 *
660 * @return string
661 */
662 private function get_notices_html() {
663
664 if ( ! function_exists( 'wp_get_environment_type' ) ) {
665 return '';
666 }
667
668 if ( in_array( wp_get_environment_type(), array( 'staging', 'production' ), true ) ) {
669 return '';
670 }
671
672 if ( defined( 'TRUSTEDLOGIN_DISABLE_LOCAL_NOTICE' ) && TRUSTEDLOGIN_DISABLE_LOCAL_NOTICE ) {
673 return '';
674 }
675
676 $notice_template = '
677 <div class="inline notice notice-alt notice-warning">
678 <h3>{{local_site}}</h3>
679 <p>{{need_access}} <a href="{{about_live_access_url}}" target="_blank" rel="noopener noreferrer">{{learn_more}}</a></p>
680 </div>';
681
682 $content = array(
683 // translators: %s is replaced with the name of the software developer (e.g. "Acme Widgets")
684 'local_site' => sprintf( esc_html__( '%s support may not be able to access this site.', 'trustedlogin' ), $this->config->get_setting( 'vendor/title' ) ),
685 'need_access' => esc_html__( 'This website is running in a local development environment. To provide support, we must be able to access your site using a publicly-accessible URL.', 'trustedlogin' ),
686 'about_live_access_url' => esc_url( $this->config->get_setting( 'vendor/about_live_access_url', self::ABOUT_LIVE_ACCESS_URL ) ),
687 'learn_more' => esc_html__( 'Learn more.', 'trustedlogin' ),
688 );
689
690 return $this->prepare_output( $notice_template, $content );
691 }
692
693 /**
694 * @return string
695 */
696 private function get_logo_html() {
697
698 $logo_url = $this->config->get_setting( 'vendor/logo_url' );
699
700 $logo_output = '';
701
702 if ( ! empty( $logo_url ) ) {
703 $logo_output = sprintf(
704 '<a href="%1$s" title="%2$s" target="_blank" rel="noreferrer noopener"><img src="%3$s" alt="%4$s" /></a>',
705 esc_url( $this->config->get_setting( 'vendor/website' ) ),
706 // translators: %s is replaced with the name of the software developer (e.g. "Acme Widgets")
707 sprintf( 'Visit the %s website (opens in a new tab)', $this->config->get_setting( 'vendor/title' ) ),
708 esc_attr( $this->config->get_setting( 'vendor/logo_url' ) ),
709 esc_attr( $this->config->get_setting( 'vendor/title' ) )
710 );
711 }
712
713 return $logo_output;
714 }
715
716 /**
717 * Returns the HTML for the footer in the Auth form
718 *
719 * @return string
720 */
721 private function get_footer_html() {
722
723 $support_url = $this->config->get_setting( 'vendor/support_url' );
724
725 if ( $reference_id = Client::get_reference_id() ) {
726
727 $support_args = array(
728 'tl' => Client::VERSION,
729 'ref' => $reference_id,
730 'ns' => $this->config->ns(),
731 );
732
733 $support_url = add_query_arg( $support_args, $support_url );
734 }
735
736 $footer_links = array(
737 esc_html__( 'Learn about TrustedLogin', 'trustedlogin' ) => self::ABOUT_TL_URL,
738 // translators: %s is replaced with the name of the software developer (e.g. "Acme Widgets")
739 sprintf( 'Visit %s support', $this->config->get_setting( 'vendor/title' ) ) => $support_url,
740 );
741
742 /**
743 * Filter trustedlogin/{ns}/template/auth/footer_links
744 *
745 * Used to add/remove Footer Links on grantlink page
746 *
747 * @since 1.0.0
748 *
749 * @param array $footer_links Array of links to show in auth footer (Key is anchor text; Value is URL)
750 */
751 $footer_links = apply_filters( 'trustedlogin/' . $this->config->ns() . '/template/auth/footer_links', $footer_links );
752
753 $footer_links_output = '';
754 foreach ( $footer_links as $text => $link ) {
755 $footer_links_output .= sprintf(
756 '<li><a href="%1$s" target="_blank">%2$s</a></li>',
757 esc_url( $link ),
758 esc_html( $text )
759 );
760 }
761
762 $footer_output = '';
763 if ( ! empty( $footer_links_output ) ) {
764 $footer_output = sprintf( '<ul>%1$s</ul>', $footer_links_output );
765 }
766
767 return $footer_output;
768 }
769
770 /**
771 * Returns the HTML for helpful debug info in the Auth form.
772 *
773 * Only shown if ?debug is present in the URL and the user has `manage_options` capability.
774 *
775 * @since 1.5.0
776 *
777 * @return string
778 */
779 private function get_admin_debug_html() {
780
781 if ( ! isset( $_GET['debug'] ) ) {
782 return '';
783 }
784
785 if( ! current_user_can( 'manage_options' ) ) {
786 return '';
787 }
788
789 $remote = new Remote( $this->config, $this->logging );
790 $encryption = new Encryption( $this->config, $remote, $this->logging );
791
792 $items = array(
793 esc_html__( 'TrustedLogin Status', 'trustedlogin' ) => sprintf( '<a href="%s" target="_blank" rel="noopener noreferrer">%s</a>', 'https://status.trustedlogin.com', is_wp_error( wp_remote_request( 'https://app.trustedlogin.com/api/status' ) ) ? esc_html__( 'Offline', 'trustedlogin' ) : esc_html__( 'Online', 'trustedlogin' ) ),
794 esc_html__( 'API Key', 'trustedlogin' ) => sprintf( '<code>%s</code>', $this->config->get_setting( 'auth/api_key' ) ),
795 esc_html__( 'License Key', 'trustedlogin' ) => sprintf( '<code>%s</code>', $this->config->get_setting( 'auth/license_key' ) ),
796 esc_html__( 'Log URL', 'trustedlogin' ) => sprintf( '<a href="%s" target="_blank" rel="noopener noreferrer">%s</a>', str_replace( ABSPATH, get_site_url() . '/', $this->logging->get_log_file_path() ), esc_html__( 'Download the log', 'trustedlogin' ) ),
797 esc_html__( 'Log Level', 'trustedlogin' ) => $this->config->get_setting( 'logging/threshold', esc_html__( '(Default)', 'trustedlogin' ) ),
798 esc_html__( 'Webhook URL', 'trustedlogin' ) => sprintf( '<code>%s</code>', $this->config->get_setting( 'webhook/url', '(Empty)' ) ),
799 esc_html__( 'Vendor Public Key', 'trustedlogin' ) => sprintf( '<code>%s</code> (<a href="%s" target="_blank">%s</a>)', $encryption->get_vendor_public_key(), $encryption->get_remote_encryption_key_url(), esc_html__( 'Verify key', 'trustedlogin' ) ),
800 );
801
802 $debugging_info = '';
803 foreach( $items as $label => $value ) {
804 $debugging_info .= sprintf( '<p><strong>%s</strong>: %s</p>', $label, $value );
805 }
806
807 $debugging_output = '<div class="tl-{{ns}}-auth__admin_debugging">
808 <h3>{{debugging_label}}</h3>
809 {{debugging_info}}
810
811 <h3>{{tl_config_label}}</h3>
812 {{tl_config}}
813 </div>';
814
815 return $this->prepare_output( $debugging_output, array(
816 'ns' => $this->config->ns(),
817 'debugging_label' => esc_html__( 'Debugging Info', 'trustedlogin' ),
818 'debugging_info' => $debugging_info,
819 'tl_config_label' => esc_html__( 'TrustedLogin Config', 'trustedlogin' ),
820 'tl_config' => '<pre>' . print_r( $this->config->get_settings(), true ) . '</pre>',
821 ) );
822 }
823
824 private function prepare_output( $template, $content, $wp_kses = true ) {
825
826 $output_html = $template;
827
828 foreach ( $content as $key => $value ) {
829 $output_html = str_replace( '{{' . $key . '}}', $value, $output_html );
830 }
831
832 if ( $wp_kses ) {
833
834 // Allow SVGs for logos
835 $allowed_protocols = wp_allowed_protocols();
836 $allowed_protocols[] = 'data';
837
838 $output_html = wp_kses(
839 $output_html,
840 array(
841 'a' => array(
842 'class' => array(),
843 'id' => array(),
844 'href' => array(),
845 'title' => array(),
846 'rel' => array(),
847 'target' => array(),
848 'data-toggle' => array(),
849 'data-access' => array(),
850 ),
851 'img' => array(
852 'class' => array(),
853 'id' => array(),
854 'src' => array(),
855 'href' => array(),
856 'alt' => array(),
857 'title' => array(),
858 ),
859 'span' => array(
860 'class' => array(),
861 'id' => array(),
862 'title' => array(),
863 'data-toggle' => array(),
864 'style' => array(),
865 ),
866 'label' => array( 'class' => array(), 'id' => array(), 'for' => array() ),
867 'code' => array( 'class' => array(), 'id' => array() ),
868 'tt' => array( 'class' => array(), 'id' => array() ),
869 'pre' => array( 'class' => array(), 'id' => array() ),
870 'table' => array( 'class' => array(), 'id' => array() ),
871 'thead' => array(),
872 'tfoot' => array(),
873 'td' => array( 'class' => array(), 'id' => array(), 'colspan' => array() ),
874 'th' => array(
875 'class' => array(),
876 'id' => array(),
877 'colspan' => array(),
878 'scope' => array(),
879 ),
880 'ul' => array( 'class' => array(), 'id' => array() ),
881 'li' => array( 'class' => array(), 'id' => array() ),
882 'p' => array( 'class' => array(), 'id' => array() ),
883 'h1' => array( 'class' => array(), 'id' => array() ),
884 'h2' => array( 'class' => array(), 'id' => array() ),
885 'h3' => array( 'class' => array(), 'id' => array(), 'style' => array(), ),
886 'h4' => array( 'class' => array(), 'id' => array() ),
887 'h5' => array( 'class' => array(), 'id' => array() ),
888 'div' => array(
889 'class' => array(),
890 'id' => array(),
891 'aria-live' => array(),
892 'style' => array(),
893 ),
894 'small' => array( 'class' => array(), 'id' => array(), 'data-toggle' => array() ),
895 'header' => array( 'class' => array(), 'id' => array() ),
896 'footer' => array( 'class' => array(), 'id' => array() ),
897 'section' => array( 'class' => array(), 'id' => array() ),
898 'br' => array(),
899 'strong' => array(),
900 'em' => array(),
901 'fieldset' => array( 'class' => array(), 'id' => array() ),
902 'input' => array(
903 'class' => array(),
904 'id' => array(),
905 'type' => array( 'text' ),
906 'value' => array(),
907 'size' => array(),
908 'aria-live' => array(),
909 'aria-label' => array(),
910 'style' => array(),
911 ),
912 'textarea' => array(
913 'class' => array(),
914 'id' => array(),
915 'rows' => array(),
916 'cols' => array(),
917 'placeholder' => array(),
918 ),
919 'button' => array(
920 'class' => array(),
921 'id' => array(),
922 'aria-live' => array(),
923 'style' => array(),
924 'title' => array(),
925 ),
926 ),
927 $allowed_protocols
928 );
929 }
930
931 return $output_html;
932 }
933
934 /**
935 * Output the TrustedLogin Button and required scripts
936 *
937 * @since 1.0.0
938 *
939 * @param array $atts {@see get_button()} for configuration array
940 * @param bool $print Should results be printed and returned (true) or only returned (false)
941 *
942 * @return string the HTML output
943 */
944 public function generate_button( $atts = array(), $print = true ) {
945
946 if ( ! current_user_can( 'create_users' ) ) {
947 return '';
948 }
949
950 if ( ! wp_script_is( 'trustedlogin-' . $this->config->ns(), 'registered' ) ) {
951 $this->logging->log( 'JavaScript is not registered. Make sure `trustedlogin` handle is added to "no-conflict" plugin settings.', __METHOD__, 'error' );
952 }
953
954 if ( ! wp_style_is( 'trustedlogin-' . $this->config->ns(), 'registered' ) ) {
955 $this->logging->log( 'Style is not registered. Make sure `trustedlogin` handle is added to "no-conflict" plugin settings.', __METHOD__, 'error' );
956 }
957
958 wp_enqueue_style( 'trustedlogin-' . $this->config->ns() );
959
960 $button_settings = array(
961 'vendor' => $this->config->get_setting( 'vendor' ),
962 'ajaxurl' => admin_url( 'admin-ajax.php' ),
963 '_nonce' => wp_create_nonce( 'tl_nonce-' . get_current_user_id() ),
964 'lang' => $this->translations(),
965 'debug' => $this->logging->is_enabled(),
966 'selector' => '.button-trustedlogin-' . $this->config->ns(),
967 'reference_id' => Client::get_reference_id(),
968 'query_string' => esc_url( remove_query_arg( array(
969 Endpoint::REVOKE_SUPPORT_QUERY_PARAM,
970 '_wpnonce',
971 ) ) ),
972 'create_ticket' => $this->is_create_ticket_enabled(),
973 );
974
975 // TODO: Add data to tl_obj when detecting that it's already been localized by another vendor
976 wp_localize_script( 'trustedlogin-' . $this->config->ns(), 'tl_obj', $button_settings );
977
978 wp_enqueue_script( 'trustedlogin-' . $this->config->ns() );
979
980 $return = $this->get_button( $atts );
981
982 if ( $print ) {
983 echo $return;
984 }
985
986 return $return;
987 }
988
989 /**
990 * Generates HTML for a TrustedLogin Grant Access button
991 *
992 * @param array $atts {
993 *
994 * @type string $text Button text to grant access. Sanitized using esc_html(). Default: "Grant %s Access"
995 * (%s replaced with vendor/title setting)
996 * @type string $exists_text Button text when vendor already has a support account. Sanitized using esc_html().
997 * Default: "Extend %s Access" (%s replaced with vendor/title setting)
998 * @type string $size WordPress CSS button size. Options: 'small', 'normal', 'large', 'hero'. Default: "hero"
999 * @type string $class CSS class added to the button. Default: "button-primary"
1000 * @type string $tag Tag used to display the button. Options: 'a', 'button', 'span'. Default: "a"
1001 * @type bool $powered_by Whether to display the TrustedLogin badge on the button. Default: true
1002 * @type string $support_url The URL to use as a backup if JavaScript fails or isn't available. Sanitized using
1003 * esc_url(). Default: `vendor/support_url` configuration setting URL.
1004 * }
1005 *
1006 * @return string
1007 */
1008 public function get_button( $atts = array() ) {
1009
1010 $defaults = array(
1011 // translators: %s is replaced with the name of the software developer (e.g. "Acme Widgets")
1012 'text' => sprintf( esc_html__( 'Grant %s Access', 'trustedlogin' ), $this->config->get_display_name() ),
1013 // translators: %s is replaced with the name of the software developer (e.g. "Acme Widgets")
1014 'exists_text' => sprintf( esc_html__( 'Extend %s Access', 'trustedlogin' ), $this->config->get_display_name(), ucwords( human_time_diff( time(), time() + $this->config->get_setting( 'decay' ) ) ) ),
1015 'size' => 'hero',
1016 'class' => 'button-primary',
1017 'tag' => 'a', // "a", "button", "span"
1018 'powered_by' => false,
1019 'support_url' => $this->config->get_setting( 'vendor/support_url' ),
1020 );
1021
1022 $sizes = array( 'small', 'normal', 'large', 'hero' );
1023
1024 $atts = wp_parse_args( $atts, $defaults );
1025
1026 switch ( $atts['size'] ) {
1027 case '':
1028 $css_class = '';
1029 break;
1030 case 'normal':
1031 $css_class = 'button';
1032 break;
1033 default:
1034 if ( ! in_array( $atts['size'], $sizes ) ) {
1035 $atts['size'] = 'hero';
1036 }
1037
1038 $css_class = 'button button-' . $atts['size'];
1039 }
1040
1041 $_valid_tags = array( 'a', 'button', 'span' );
1042
1043 if ( ! empty( $atts['tag'] ) && in_array( strtolower( $atts['tag'] ), $_valid_tags, true ) ) {
1044 $tag = $atts['tag'];
1045 } else {
1046 $tag = 'a';
1047 }
1048
1049 $data_atts = array();
1050
1051 if ( $this->support_user->get_all() ) {
1052 $text = '<span class="dashicons dashicons-update-alt dashicons--small"></span> ' . esc_html( $atts['exists_text'] );
1053 $href = admin_url( 'users.php?role=' . $this->support_user->role->get_name() );
1054 $data_atts['access'] = 'extend';
1055 } else {
1056 $text = esc_html( $atts['text'] );
1057 $href = $atts['support_url'];
1058 $data_atts['access'] = 'grant';
1059 }
1060
1061 $css_class = implode( ' ', array( $css_class, $atts['class'] ) );
1062 $css_class = trim( $css_class );
1063
1064 $data_string = '';
1065 foreach ( $data_atts as $key => $value ) {
1066 $data_string .= sprintf( ' data-%s="%s"', esc_attr( $key ), esc_attr( $value ) );
1067 }
1068
1069 $powered_by = '';
1070 if ( $atts['powered_by'] ) {
1071 $powered_by = sprintf(
1072 '<small><span class="trustedlogin-logo"></span>%s</small>',
1073 esc_html__( 'Secured by TrustedLogin', 'trustedlogin' )
1074 );
1075 }
1076
1077 $anchor_html = $text . $powered_by;
1078
1079 return sprintf(
1080 '<%1$s href="%2$s" class="%3$s button-trustedlogin-%4$s" aria-role="button" %5$s>%6$s</%1$s>',
1081 /* %1$s */
1082 $tag,
1083 /* %2$s */
1084 esc_url( $href ),
1085 /* %3$s */
1086 esc_attr( $css_class ),
1087 /* %4$s */
1088 $this->config->ns(),
1089 /* %5$s */
1090 $data_string,
1091 /* %6$s */
1092 $anchor_html
1093 );
1094 }
1095
1096 /**
1097 * Helper function: Build translate-able strings for alert messages
1098 *
1099 * @since 1.0.0
1100 *
1101 * @return array of Translations and strings to be localized to JS variables
1102 */
1103 public function translations() {
1104
1105 $vendor_title = $this->config->get_setting( 'vendor/title' );
1106
1107 /**
1108 * Filter: Allow for adding into GET parameters on support_url
1109 *
1110 * @since 1.0.0
1111 *
1112 * ```
1113 * $url_query_args = [
1114 * 'message' => (string) What error should be sent to the support system.
1115 * ];
1116 * ```
1117 *
1118 * @param array $url_query_args {
1119 *
1120 * @type string $message What error should be sent to the support system.
1121 * @type string|null $ref A sanitized reference ID, if passed. Otherwise, null.
1122 * }
1123 */
1124 $query_args = apply_filters(
1125 'trustedlogin/' . $this->config->ns() . '/support_url/query_args',
1126 array(
1127 'message' => __( 'Could not create TrustedLogin access.', 'trustedlogin' ),
1128 'ref' => Client::get_reference_id(),
1129 )
1130 );
1131
1132 $error_content = sprintf(
1133 '<p>%s</p><p>%s</p>',
1134 sprintf(
1135 // translators: %s is replaced with the name of the software developer (e.g. "Acme Widgets")
1136 esc_html__( 'The user details could not be sent to %1$s automatically.', 'trustedlogin' ),
1137 $vendor_title
1138 ),
1139 sprintf(
1140 // translators: %1$s is the vendor support url and %2$s is the vendor title
1141 __( 'Please <a href="%1$s" target="_blank">click here</a> to go to the %2$s support site', 'trustedlogin' ),
1142 esc_url( add_query_arg( $query_args, $this->config->get_setting( 'vendor/support_url' ) ) ),
1143 $vendor_title
1144 )
1145 );
1146
1147 $translations = array(
1148 'buttons' => array(
1149 'confirm' => esc_html__( 'Confirm', 'trustedlogin' ),
1150 'ok' => esc_html__( 'Ok', 'trustedlogin' ),
1151 // translators: %1$s is the vendor title
1152 'go_to_site' => sprintf( __( 'Go to %1$s support site', 'trustedlogin' ), $vendor_title ),
1153 'close' => esc_html__( 'Close', 'trustedlogin' ),
1154 'cancel' => esc_html__( 'Cancel', 'trustedlogin' ),
1155 // translators: %1$s is the vendor title
1156 'revoke' => sprintf( esc_html__( 'Revoke %1$s support access', 'trustedlogin' ), $vendor_title ),
1157 'copy' => esc_html__( 'Copy', 'trustedlogin' ),
1158 'copied' => esc_html__( 'Copied!', 'trustedlogin' ),
1159 ),
1160 'a11y' => array(
1161 'opens_new_window' => esc_attr__( '(This link opens in a new window.)', 'trustedlogin' ),
1162 'copied_text' => esc_html__( 'The access key has been copied to your clipboard.', 'trustedlogin' ),
1163 ),
1164 'status' => array(
1165 'synced' => array(
1166 'title' => esc_html__( 'Support access granted', 'trustedlogin' ),
1167 'content' => sprintf(
1168 // translators: %1$s is the vendor title
1169 __( 'A temporary support user has been created, and sent to %1$s support.', 'trustedlogin' ),
1170 $vendor_title
1171 ),
1172 ),
1173 'pending' => array(
1174 // translators: %1$s is the vendor title
1175 'content' => sprintf( __( 'Generating & encrypting secure support access for %1$s', 'trustedlogin' ), $vendor_title ),
1176 ),
1177 'extending' => array(
1178 // translators: %1$s is the vendor title and %2$s is the human-readable expiration time (for example, "1 week")
1179 'content' => sprintf( __( 'Extending support access for %1$s by %2$s', 'trustedlogin' ), $vendor_title, human_time_diff( time(), time() + $this->config->get_setting( 'decay' ) ) ),
1180 ),
1181 'syncing' => array(
1182 // translators: %1$s is the vendor title
1183 'content' => sprintf( __( 'Sending encrypted access to %1$s.', 'trustedlogin' ), $vendor_title ),
1184 ),
1185 'error' => array(
1186 // translators: %1$s is the vendor title
1187 'title' => sprintf( __( 'Error syncing support user to %1$s', 'trustedlogin' ), $vendor_title ),
1188 'content' => wp_kses( $error_content, array(
1189 'a' => array(
1190 'href' => array(),
1191 'rel' => array(),
1192 'target' => array(),
1193 ),
1194 'p' => array(),
1195 ) ),
1196 ),
1197 'cancel' => array(
1198 'title' => esc_html__( 'Action Cancelled', 'trustedlogin' ),
1199 'content' => sprintf(
1200 // translators: %1$s is the vendor title
1201 __( 'A support account for %1$s was not created.', 'trustedlogin' ),
1202 $vendor_title
1203 ),
1204 ),
1205 'failed' => array(
1206 'title' => esc_html__( 'Support Access Was Not Granted', 'trustedlogin' ),
1207 'content' => esc_html__( 'There was an error granting access: ', 'trustedlogin' ),
1208 ),
1209 'failed_permissions' => array(
1210 'content' => esc_html__( 'Your authorized session has expired. Please refresh the page.', 'trustedlogin' ),
1211 ),
1212 'accesskey' => array(
1213 'title' => esc_html__( 'TrustedLogin Key Created', 'trustedlogin' ),
1214 'content' => sprintf(
1215 // translators: %1$s is the vendor title
1216 __( 'Share this TrustedLogin Key with %1$s to give them secure access:', 'trustedlogin' ),
1217 $vendor_title
1218 ),
1219 'revoke_link' => esc_url( add_query_arg( array( Endpoint::REVOKE_SUPPORT_QUERY_PARAM => $this->config->ns() ), admin_url() ) ),
1220 ),
1221 'error404' => array(
1222 'title' => esc_html__( 'The TrustedLogin vendor could not be found.', 'trustedlogin' ),
1223 'content' => '',
1224 ),
1225 'error409' => array(
1226 'title' => sprintf(
1227 // translators: %1$s is the vendor title
1228 __( '%1$s Support user already exists', 'trustedlogin' ),
1229 $vendor_title
1230 ),
1231 'content' => sprintf(
1232 wp_kses(
1233 // translators: %1$s is the vendor title, %2$s is the URL to the users list page
1234 __( 'A support user for %1$s already exists. You may revoke this support access from your <a href="%2$s" target="_blank">Users list</a>.', 'trustedlogin' ),
1235 array( 'a' => array( 'href' => array(), 'target' => array() ) )
1236 ),
1237 $vendor_title,
1238 esc_url( admin_url( 'users.php?role=' . $this->support_user->role->get_name() ) )
1239 ),
1240 ),
1241 ),
1242 );
1243
1244 return $translations;
1245 }
1246
1247 /**
1248 * Outputs table of created support users
1249 *
1250 * @since 1.0.0
1251 *
1252 * @param bool $print Whether to print and return (true) or return (false) the results. Default: true
1253 * @param array $atts Settings for the table. {
1254 *
1255 * @type bool $current_url Whether to generate Revoke links based on the current URL. Default: false.
1256 * }
1257 *
1258 * @return string HTML table of active support users for vendor. Empty string if current user can't `create_users`
1259 */
1260 public function output_support_users( $print = true, $atts = array() ) {
1261
1262 if ( ( ! is_admin() && ! $this->is_login_screen() ) || ! current_user_can( 'create_users' ) ) {
1263 return '';
1264 }
1265
1266 // The `trustedlogin/{$ns}/button` action passes an empty string
1267 if ( '' === $print ) {
1268 $print = true;
1269 }
1270
1271 $support_users = $this->support_user->get_all();
1272
1273 if ( empty( $support_users ) ) {
1274
1275 // translators: %s is replaced with the name of the software developer (e.g. "Acme Widgets")
1276 $return = '<h3>' . sprintf( esc_html__( 'No %s users exist.', 'trustedlogin' ), $this->config->get_setting( 'vendor/title' ) ) . '</h3>';
1277
1278 if ( $print ) {
1279 echo $return;
1280 }
1281
1282 return $return;
1283 }
1284
1285 $return = '';
1286
1287 $access_key = $this->site_access->get_access_key();
1288
1289 if ( is_wp_error( $access_key ) ) {
1290
1291 $access_key_template = <<<EOD
1292 <%3\$s class="tl-%1\$s-auth__accesskey">
1293 <h3>%2\$s</h3>
1294 <p>%4\$s <samp>%5\$s</samp></p>
1295 </%3\$s>
1296 EOD;
1297 $access_key_output = sprintf(
1298 $access_key_template,
1299 /* %1$s */
1300 sanitize_title( $this->config->ns() ),
1301 /* %2$s */
1302 esc_html__( 'Error', 'trustedlogin' ),
1303 /* %3$s */
1304 'div',
1305 /* %4$s */
1306 esc_html__( 'There was an error returning the access key.', 'trustedlogin' ),
1307 /* %5$s */
1308 esc_html( $access_key->get_error_message() )
1309 );
1310 } else {
1311
1312 $access_key_template = <<<EOD
1313 <%6\$s class="tl-%1\$s-auth__accesskey">
1314 <label for="tl-%1\$s-access-key"><h3>%2\$s</h3></label>
1315 <p>%8\$s</p>
1316
1317 <div class="tl-%1\$s-auth__accesskey_wrapper">
1318 <input id="tl-%1\$s-access-key" type="text" value="%4\$s" size="64" class="tl-%1\$s-auth__accesskey_field code" aria-label="%3\$s">
1319 <button id="tl-%1\$s-copy" class="tl-%1\$s-auth__accesskey_copy button" aria-live="off" title="%7\$s"><span class="screen-reader-text">%5\$s</span></button>
1320 </div>
1321 </%6\$s>
1322 EOD;
1323 $access_key_output = sprintf(
1324 $access_key_template,
1325 /* %1$s */
1326 sanitize_title( $this->config->ns() ),
1327 /* %2$s */
1328 esc_html__( 'Site access key:', 'trustedlogin' ),
1329 /* %3$s */
1330 esc_html__( 'Access Key', 'trustedlogin' ),
1331 /* %4$s */
1332 esc_attr( $access_key ),
1333 /* %5$s */
1334 esc_html__( 'Copy', 'trustedlogin' ),
1335 /* %6$s */
1336 'div',
1337 /* %7$s */
1338 esc_html__( 'Copy the access key to your clipboard', 'trustedlogin' ),
1339 // translators: %s is the display name of the TrustedLogin support user.
1340 /* %8$s */
1341 sprintf( esc_html__( 'The access key is not a password; only %1$s will be able to access your site using this code. You may share this access key on support forums.', 'trustedlogin' ), $this->support_user->get_first()->display_name )
1342 );
1343 }
1344
1345
1346 $return .= $access_key_output;
1347
1348 if ( $print ) {
1349 echo $return;
1350 }
1351
1352 return $return;
1353 }
1354
1355
1356 /**
1357 * Notice: Shown when a support user is manually revoked by admin;
1358 *
1359 * @return void
1360 */
1361 public function admin_notice_revoked() {
1362
1363 static $displayed_notice;
1364
1365 // Only show notice once
1366 if ( $displayed_notice ) {
1367 return;
1368 }
1369
1370 ?>
1371 <div class="notice notice-success is-dismissible">
1372 <h3><?php
1373 // translators: %s is replaced with the name of the software developer (e.g. "Acme Widgets")
1374 echo esc_html( sprintf( __( '%s access revoked.', 'trustedlogin' ), $this->config->get_setting( 'vendor/title' ) ) );
1375 ?></h3>
1376 <?php if ( ! current_user_can( 'delete_users' ) ) { ?>
1377 <p><?php echo esc_html__( 'You may safely close this window.', 'trustedlogin' ); ?></p>
1378 <?php } ?>
1379 </div>
1380 <?php
1381
1382 $displayed_notice = true;
1383 }
1384
1385 /**
1386 * Is this a login screen and should TrustedLogin override the login screen for the current namespace?
1387 *
1388 * @return bool
1389 */
1390 private function is_login_screen() {
1391 return did_action( 'login_init' ) && isset( $_GET['ns'] ) && $_GET['ns'] === $this->config->ns();
1392 }
1393 }
1394