Completed
Push — add/identity-crisis-package ( cfc822...a567d7 )
by
unknown
09:40
created

Identity_Crisis::validate_sync_error_idc_option()   C

Complexity

Conditions 15
Paths 10

Size

Total Lines 41

Duplication

Lines 41
Ratio 100 %

Importance

Changes 0
Metric Value
cc 15
nc 10
nop 0
dl 41
loc 41
rs 5.9166
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Identity_Crisis package.
4
 *
5
 * @package  automattic/jetpack-identity-crisis
6
 */
7
8
namespace Automattic\Jetpack;
9
10
use Automattic\Jetpack\Assets\Logo as Jetpack_Logo;
11
use Automattic\Jetpack\Connection\Manager as Connection_Manager;
12
use Automattic\Jetpack\Constants as Constants;
13
use Automattic\Jetpack\Status as Status;
14
use Automattic\Jetpack\Sync\Functions;
15
use Jetpack;
16
use Jetpack_Options;
17
use Jetpack_Tracks_Client;
18
use WP_Error;
19
20
/**
21
 * This class will handle everything involved with fixing an Identity Crisis.
22
 *
23
 * @since 4.4.0
24
 */
25
class Identity_Crisis {
26
27
	/**
28
	 * Instance of the object.
29
	 *
30
	 * @var Identity_Crisis
31
	 **/
32
	private static $instance = null;
33
34
	/**
35
	 * The wpcom value of the home URL.
36
	 *
37
	 * @var string
38
	 */
39
	public static $wpcom_home_url;
40
41
	/**
42
	 * Has safe mode been confirmed?
43
	 *
44
	 * @var bool
45
	 */
46
	public static $is_safe_mode_confirmed;
47
48
	/**
49
	 * The current screen, which is set if the current user is a non-admin and this is an admin page.
50
	 *
51
	 * @var WP_Screen
52
	 */
53
	public static $current_screen;
54
55
	/**
56
	 * Initializer.
57
	 *
58
	 * @return object
59
	 */
60
	public static function init() {
61
		if ( is_null( self::$instance ) ) {
62
			self::$instance = new Identity_Crisis();
63
		}
64
65
		return self::$instance;
66
	}
67
68
	/**
69
	 * Class constructor.
70
	 *
71
	 * @return void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
72
	 */
73 View Code Duplication
	private function __construct() {
74
		add_action( 'jetpack_sync_processed_actions', array( $this, 'maybe_clear_migrate_option' ) );
75
		$urls_in_crisis = Jetpack::check_identity_crisis();
76
		if ( false === $urls_in_crisis ) {
77
			return;
78
		}
79
80
		self::$wpcom_home_url = $urls_in_crisis['wpcom_home'];
81
		add_action( 'init', array( $this, 'wordpress_init' ) );
82
	}
83
84
	/**
85
	 * Gets the link to the support document used to explain Safe Mode to users.
86
	 *
87
	 * @return string
88
	 */
89
	public static function get_safe_mod_doc_url() {
90
		return Redirect::get_url( 'jetpack-support-safe-mode' );
91
	}
92
93
	/**
94
	 * This method loops through the array of processed items from sync and checks if one of the items was the
95
	 * home_url or site_url callable. If so, then we delete the jetpack_migrate_for_idc option.
96
	 *
97
	 * @param array $processed_items Array of processed items that were synced to WordPress.com.
98
	 */
99 View Code Duplication
	public function maybe_clear_migrate_option( $processed_items ) {
100
		foreach ( (array) $processed_items as $item ) {
101
102
			// First, is this item a jetpack_sync_callable action? If so, then proceed.
103
			$callable_args = ( is_array( $item ) && isset( $item[0], $item[1] ) && 'jetpack_sync_callable' === $item[0] )
104
				? $item[1]
105
				: null;
106
107
			// Second, if $callable_args is set, check if the callable was home_url or site_url. If so,
108
			// clear the migrate option.
109
			if (
110
				isset( $callable_args, $callable_args[0] )
111
				&& ( 'home_url' === $callable_args[0] || 'site_url' === $callable_args[1] )
112
			) {
113
				Jetpack_Options::delete_option( 'migrate_for_idc' );
114
				break;
115
			}
116
		}
117
	}
118
119
	/**
120
	 * WordPress init.
121
	 *
122
	 * @return void
123
	 */
124 View Code Duplication
	public function wordpress_init() {
125
		if ( ! current_user_can( 'jetpack_disconnect' ) && is_admin() ) {
126
			add_action( 'admin_notices', array( $this, 'display_non_admin_idc_notice' ) );
127
			add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_idc_notice_files' ) );
128
			add_action( 'current_screen', array( $this, 'non_admins_current_screen_check' ) );
129
130
			return;
131
		}
132
133
		if (
134
			isset( $_GET['jetpack_idc_clear_confirmation'], $_GET['_wpnonce'] ) &&
135
			wp_verify_nonce( $_GET['_wpnonce'], 'jetpack_idc_clear_confirmation' )
136
		) {
137
			Jetpack_Options::delete_option( 'safe_mode_confirmed' );
138
			self::$is_safe_mode_confirmed = false;
139
		} else {
140
			self::$is_safe_mode_confirmed = (bool) Jetpack_Options::get_option( 'safe_mode_confirmed' );
141
		}
142
143
		// 121 Priority so that it's the most inner Jetpack item in the admin bar.
144
		add_action( 'admin_bar_menu', array( $this, 'display_admin_bar_button' ), 121 );
145
		add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_bar_css' ) );
146
147
		if ( is_admin() && ! self::$is_safe_mode_confirmed ) {
148
			add_action( 'admin_notices', array( $this, 'display_idc_notice' ) );
149
			add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_idc_notice_files' ) );
150
		}
151
	}
152
153
	/**
154
	 * Non-admins current screen check.
155
	 *
156
	 * @param object $current_screen Current screen.
157
	 *
158
	 * @return null
159
	 */
160 View Code Duplication
	public function non_admins_current_screen_check( $current_screen ) {
161
		self::$current_screen = $current_screen;
162
		if ( isset( $current_screen->id ) && 'toplevel_page_jetpack' === $current_screen->id ) {
163
			return null;
164
		}
165
166
		// If the user has dismissed the notice, and we're not currently on a Jetpack page,
167
		// then do not show the non-admin notice.
168
		if ( isset( $_COOKIE, $_COOKIE['jetpack_idc_dismiss_notice'] ) ) {
169
			remove_action( 'admin_notices', array( $this, 'display_non_admin_idc_notice' ) );
170
			remove_action( 'admin_enqueue_scripts', array( $this, 'enqueue_idc_notice_files' ) );
171
		}
172
173
		return null;
174
	}
175
176
	/**
177
	 * Renders the admin bar button.
178
	 *
179
	 * @return void
180
	 */
181 View Code Duplication
	public function display_admin_bar_button() {
182
		global $wp_admin_bar;
183
184
		$href = is_admin()
185
			? add_query_arg( 'jetpack_idc_clear_confirmation', '1' )
186
			: add_query_arg( 'jetpack_idc_clear_confirmation', '1', admin_url() );
187
188
		$href = wp_nonce_url( $href, 'jetpack_idc_clear_confirmation' );
189
190
		$title = sprintf(
191
			'<span class="jp-idc-admin-bar">%s %s</span>',
192
			'<span class="dashicons dashicons-warning"></span>',
193
			esc_html__( 'Jetpack Safe Mode', 'jetpack' )
194
		);
195
196
		$menu = array(
197
			'id'     => 'jetpack-idc',
198
			'title'  => $title,
199
			'href'   => esc_url( $href ),
200
			'parent' => 'top-secondary',
201
		);
202
203
		if ( ! self::$is_safe_mode_confirmed ) {
204
			$menu['meta'] = array(
205
				'class' => 'hide',
206
			);
207
		}
208
209
		$wp_admin_bar->add_node( $menu );
210
	}
211
212
	/**
213
	 * Checks if the site is currently in an identity crisis.
214
	 *
215
	 * @return array|bool Array of options that are in a crisis, or false if everything is OK.
216
	 */
217 View Code Duplication
	public static function check_identity_crisis() {
218
		$connection = new Connection_Manager( 'jetpack' );
219
220
		if ( ! $connection->is_active() || ( new Status() )->is_offline_mode() || ! self::validate_sync_error_idc_option() ) {
221
			return false;
222
		}
223
224
		return Jetpack_Options::get_option( 'sync_error_idc' );
225
	}
226
227
	/**
228
	 * Prepare URL for display.
229
	 *
230
	 * @param string $url URL to display.
231
	 *
232
	 * @return string
233
	 */
234
	public static function prepare_url_for_display( $url ) {
235
		return untrailingslashit( self::normalize_url_protocol_agnostic( $url ) );
236
	}
237
238
	/**
239
	 * Clears all IDC specific options. This method is used on disconnect and reconnect.
240
	 *
241
	 * @return void
242
	 */
243 View Code Duplication
	public static function clear_all_idc_options() {
244
		// If the site is currently in IDC, let's also clear the VaultPress connection options.
245
		// We have to check if the site is in IDC, otherwise we'd be clearing the VaultPress
246
		// connection any time the Jetpack connection is cycled.
247
		if ( self::validate_sync_error_idc_option() ) {
248
			delete_option( 'vaultpress' );
249
			delete_option( 'vaultpress_auto_register' );
250
		}
251
252
		Jetpack_Options::delete_option(
253
			array(
254
				'sync_error_idc',
255
				'safe_mode_confirmed',
256
				'migrate_for_idc',
257
			)
258
		);
259
	}
260
261
	/**
262
	 * Checks whether the sync_error_idc option is valid or not, and if not, will do cleanup.
263
	 *
264
	 * @return bool
265
	 * @since 5.4.0 Do not call get_sync_error_idc_option() unless site is in IDC
266
	 *
267
	 * @since 4.4.0
268
	 */
269 View Code Duplication
	public static function validate_sync_error_idc_option() {
270
		$is_valid = false;
271
272
		// Is the site opted in and does the stored sync_error_idc option match what we now generate?
273
		$sync_error = Jetpack_Options::get_option( 'sync_error_idc' );
274
		if ( $sync_error && self::sync_idc_optin() ) {
275
			$local_options = self::get_sync_error_idc_option();
276
			// Ensure all values are set.
277
			if ( isset( $sync_error['home'] ) && isset( $local_options['home'] ) && isset( $sync_error['siteurl'] ) && isset( $local_options['siteurl'] ) ) {
278
				// If the WP.com expected home and siteurl match local home and siteurl it is not valid IDC.
279
				if (
280
					isset( $sync_error['wpcom_home'] ) &&
281
					isset( $sync_error['wpcom_siteurl'] ) &&
282
					$sync_error['wpcom_home'] === $local_options['home'] &&
283
					$sync_error['wpcom_siteurl'] === $local_options['siteurl']
284
				) {
285
					$is_valid = false;
286
					// Enable migrate_for_idc so that sync actions are accepted.
287
					Jetpack_Options::update_option( 'migrate_for_idc', true );
288
				} elseif ( $sync_error['home'] === $local_options['home'] && $sync_error['siteurl'] === $local_options['siteurl'] ) {
289
					$is_valid = true;
290
				}
291
			}
292
		}
293
294
		/**
295
		 * Filters whether the sync_error_idc option is valid.
296
		 *
297
		 * @param bool $is_valid If the sync_error_idc is valid or not.
298
		 *
299
		 * @since 4.4.0
300
		 */
301
		$is_valid = (bool) apply_filters( 'jetpack_sync_error_idc_validation', $is_valid );
302
303
		if ( ! $is_valid && $sync_error ) {
304
			// Since the option exists, and did not validate, delete it.
305
			Jetpack_Options::delete_option( 'sync_error_idc' );
306
		}
307
308
		return $is_valid;
309
	}
310
311
	/**
312
	 * Normalizes a url by doing three things:
313
	 *  - Strips protocol
314
	 *  - Strips www
315
	 *  - Adds a trailing slash
316
	 *
317
	 * @param string $url URL to parse.
318
	 *
319
	 * @return WP_Error|string
320
	 * @since 4.4.0
321
	 */
322 View Code Duplication
	public static function normalize_url_protocol_agnostic( $url ) {
323
		$parsed_url = wp_parse_url( trailingslashit( esc_url_raw( $url ) ) );
324
		if ( ! $parsed_url || empty( $parsed_url['host'] ) || empty( $parsed_url['path'] ) ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $parsed_url of type string|false is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === false instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
325
			return new WP_Error(
326
				'cannot_parse_url',
0 ignored issues
show
Unused Code introduced by
The call to WP_Error::__construct() has too many arguments starting with 'cannot_parse_url'.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
327
				sprintf(
328
				/* translators: %s: URL to parse. */
329
					esc_html__( 'Cannot parse URL %s', 'jetpack' ),
330
					$url
331
				)
332
			);
333
		}
334
335
		// Strip www and protocols.
336
		$url = preg_replace( '/^www\./i', '', $parsed_url['host'] . $parsed_url['path'] );
337
338
		return $url;
339
	}
340
341
	/**
342
	 * Gets the value that is to be saved in the jetpack_sync_error_idc option.
343
	 *
344
	 * @param array $response HTTP response.
345
	 *
346
	 * @return array Array of the local urls, wpcom urls, and error code.
347
	 * @since 4.4.0
348
	 * @since 5.4.0 Add transient since home/siteurl retrieved directly from DB.
349
	 */
350 View Code Duplication
	public static function get_sync_error_idc_option( $response = array() ) {
351
		// Since the local options will hit the database directly, store the values
352
		// in a transient to allow for autoloading and caching on subsequent views.
353
		$local_options = get_transient( 'jetpack_idc_local' );
354
		if ( false === $local_options ) {
355
			$local_options = array(
356
				'home'    => Functions::home_url(),
357
				'siteurl' => Functions::site_url(),
358
			);
359
			set_transient( 'jetpack_idc_local', $local_options, MINUTE_IN_SECONDS );
360
		}
361
362
		$options = array_merge( $local_options, $response );
363
364
		$returned_values = array();
365
		foreach ( $options as $key => $option ) {
366
			if ( 'error_code' === $key ) {
367
				$returned_values[ $key ] = $option;
368
				continue;
369
			}
370
371
			$normalized_url = self::normalize_url_protocol_agnostic( $option );
372
			if ( is_wp_error( $normalized_url ) ) {
373
				continue;
374
			}
375
376
			$returned_values[ $key ] = $normalized_url;
377
		}
378
379
		set_transient( 'jetpack_idc_option', $returned_values, MINUTE_IN_SECONDS );
380
381
		return $returned_values;
382
	}
383
384
	/**
385
	 * Returns the value of the jetpack_sync_idc_optin filter, or constant.
386
	 * If set to true, the site will be put into staging mode.
387
	 *
388
	 * @return bool
389
	 * @since 4.3.2
390
	 */
391 View Code Duplication
	public static function sync_idc_optin() {
392
		if ( Constants::is_defined( 'JETPACK_SYNC_IDC_OPTIN' ) ) {
393
			$default = Constants::get_constant( 'JETPACK_SYNC_IDC_OPTIN' );
394
		} else {
395
			$default = ! Constants::is_defined( 'SUNRISE' ) && ! is_multisite();
396
		}
397
398
		/**
399
		 * Allows sites to opt in for IDC mitigation which blocks the site from syncing to WordPress.com when the home
400
		 * URL or site URL do not match what WordPress.com expects. The default value is either true, or the value of
401
		 * JETPACK_SYNC_IDC_OPTIN constant if set.
402
		 *
403
		 * @param bool $default Whether the site is opted in to IDC mitigation.
404
		 *
405
		 * @since 4.3.2
406
		 */
407
		return (bool) apply_filters( 'jetpack_sync_idc_optin', $default );
408
	}
409
410
	/**
411
	 * Does the current admin page have help tabs?
412
	 *
413
	 * @return bool
414
	 */
415 View Code Duplication
	public function admin_page_has_help_tabs() {
416
		if ( ! function_exists( 'get_current_screen' ) ) {
417
			return false;
418
		}
419
420
		$current_screen = get_current_screen();
421
		$tabs           = $current_screen->get_help_tabs();
422
423
		return ! empty( $tabs );
424
	}
425
426
	/**
427
	 * Renders the non-admin IDC notice.
428
	 *
429
	 * @return void
430
	 */
431
	public function display_non_admin_idc_notice() {
432
		$classes = 'jp-idc-notice inline is-non-admin notice notice-warning';
433
		if ( isset( self::$current_screen ) && 'toplevel_page_jetpack' !== self::$current_screen->id ) {
434
			$classes .= ' is-dismissible';
435
		}
436
437
		if ( $this->admin_page_has_help_tabs() ) {
438
			$classes .= ' has-help-tabs';
439
		}
440
		?>
441
442
		<div class="<?php echo esc_attr( $classes ); ?>">
443
			<?php $this->render_notice_header(); ?>
444
			<div class="jp-idc-notice__content-header">
445
				<h3 class="jp-idc-notice__content-header__lead">
446
					<?php echo esc_html( $this->get_non_admin_notice_text() ); ?>
447
				</h3>
448
449
				<p class="jp-idc-notice__content-header__explanation">
450
					<?php echo esc_html( $this->get_non_admin_contact_admin_text() ); ?>
451
				</p>
452
			</div>
453
		</div>
454
		<?php
455
	}
456
457
	/**
458
	 * First "step" of the IDC mitigation. Will provide some messaging and two options/buttons.
459
	 * "Confirm Staging" - Dismiss the notice and continue on with our lives in staging mode.
460
	 * "Fix Jetpack Connection" - Will disconnect the site and start the mitigation...
461
	 *
462
	 * @return void
463
	 */
464 View Code Duplication
	public function display_idc_notice() {
465
		$classes = 'jp-idc-notice inline notice notice-warning';
466
		if ( $this->admin_page_has_help_tabs() ) {
467
			$classes .= ' has-help-tabs';
468
		}
469
		?>
470
		<div class="<?php echo esc_attr( $classes ); ?>">
471
			<?php $this->render_notice_header(); ?>
472
			<?php $this->render_notice_first_step(); ?>
473
			<?php $this->render_notice_second_step(); ?>
474
		</div>
475
		<?php
476
	}
477
478
	/**
479
	 * Enqueue CSS for the admin bar.
480
	 *
481
	 * @return void
482
	 */
483
	public function enqueue_admin_bar_css() {
484
		wp_enqueue_style(
485
			'jetpack-idc-admin-bar-css',
486
			plugins_url( 'css/jetpack-idc-admin-bar.css', JETPACK__PLUGIN_FILE ),
487
			array( 'dashicons' ),
488
			JETPACK__VERSION
489
		);
490
	}
491
492
	/**
493
	 * Enqueue scripts for the notice.
494
	 *
495
	 * @return void
496
	 */
497 View Code Duplication
	public function enqueue_idc_notice_files() {
498
		wp_enqueue_script(
499
			'jetpack-idc-js',
500
			Assets::get_file_url_for_environment( '_inc/build/idc-notice.min.js', '_inc/idc-notice.js' ),
501
			array( 'jquery' ),
502
			JETPACK__VERSION,
503
			true
504
		);
505
506
		wp_localize_script(
507
			'jetpack-idc-js',
508
			'idcL10n',
509
			array(
510
				'apiRoot'         => esc_url_raw( rest_url() ),
511
				'nonce'           => wp_create_nonce( 'wp_rest' ),
512
				'tracksUserData'  => Jetpack_Tracks_Client::get_connected_user_tracks_identity(),
513
				'currentUrl'      => remove_query_arg( '_wpnonce', remove_query_arg( 'jetpack_idc_clear_confirmation' ) ),
514
				'tracksEventData' => array(
515
					'isAdmin'       => current_user_can( 'jetpack_disconnect' ),
516
					'currentScreen' => self::$current_screen ? self::$current_screen->id : false,
517
				),
518
			)
519
		);
520
521
		if ( ! wp_style_is( 'jetpack-dops-style' ) ) {
522
			wp_register_style(
523
				'jetpack-dops-style',
524
				plugins_url( '_inc/build/admin.css', JETPACK__PLUGIN_FILE ),
525
				array(),
526
				JETPACK__VERSION
527
			);
528
		}
529
530
		wp_enqueue_style(
531
			'jetpack-idc-css',
532
			plugins_url( 'css/jetpack-idc.css', JETPACK__PLUGIN_FILE ),
533
			array( 'jetpack-dops-style' ),
534
			JETPACK__VERSION
535
		);
536
537
		// Required for Tracks.
538
		wp_enqueue_script(
539
			'jp-tracks',
540
			'//stats.wp.com/w.js',
541
			array(),
542
			gmdate( 'YW' ),
543
			true
544
		);
545
546
		wp_enqueue_script(
547
			'jp-tracks-functions',
548
			plugins_url( '_inc/lib/tracks/tracks-callables.js', JETPACK__PLUGIN_FILE ),
549
			array(),
550
			JETPACK__VERSION,
551
			false
552
		);
553
	}
554
555
	/**
556
	 * Renders the notice header.
557
	 *
558
	 * @return void
559
	 */
560
	public function render_notice_header() {
561
		?>
562
		<div class="jp-idc-notice__header">
563
			<div class="jp-idc-notice__header__emblem">
564
				<?php
565
				$jetpack_logo = new Jetpack_Logo();
566
				echo esc_html( $jetpack_logo->get_jp_emblem() );
567
				?>
568
			</div>
569
			<p class="jp-idc-notice__header__text">
570
				<?php esc_html_e( 'Jetpack Safe Mode', 'jetpack' ); ?>
571
			</p>
572
		</div>
573
574
		<div class="jp-idc-notice__separator"></div>
575
		<?php
576
	}
577
578
	/**
579
	 * Is a container for the error notices.
580
	 * Will be shown/controlled by jQuery in idc-notice.js.
581
	 *
582
	 * @return void
583
	 */
584
	public function render_error_notice() {
585
		?>
586
		<div class="jp-idc-error__notice dops-notice is-error">
587
			<svg class="gridicon gridicons-notice dops-notice__icon" height="24" width="24" viewBox="0 0 24 24">
588
				<g>
589
					<path d="M12 2C6.477 2 2 6.477 2 12s4.477 10 10 10 10-4.477 10-10S17.523 2 12 2zm1 15h-2v-2h2v2zm0-4h-2l-.5-6h3l-.5 6z"></path>
590
				</g>
591
			</svg>
592
			<div class="dops-notice__content">
593
				<span class="dops-notice__text">
594
					<?php esc_html_e( 'Something went wrong:', 'jetpack' ); ?>
595
					<span class="jp-idc-error__desc"></span>
596
				</span>
597
				<a class="dops-notice__action" href="javascript:void(0);">
598
					<span id="jp-idc-error__action">
599
						<?php esc_html_e( 'Try Again', 'jetpack' ); ?>
600
					</span>
601
				</a>
602
			</div>
603
		</div>
604
		<?php
605
	}
606
607
	/**
608
	 * Renders the first step notice.
609
	 *
610
	 * @return void
611
	 */
612
	public function render_notice_first_step() {
613
		?>
614
		<div class="jp-idc-notice__first-step">
615
			<div class="jp-idc-notice__content-header">
616
				<h3 class="jp-idc-notice__content-header__lead">
617
					<?php echo esc_html( $this->get_first_step_header_lead() ); ?>
618
				</h3>
619
620
				<p class="jp-idc-notice__content-header__explanation">
621
					<?php echo esc_html( $this->get_first_step_header_explanation() ); ?>
622
				</p>
623
			</div>
624
625
			<?php $this->render_error_notice(); ?>
626
627
			<div class="jp-idc-notice__actions">
628
				<div class="jp-idc-notice__action">
629
					<p class="jp-idc-notice__action__explanation">
630
						<?php echo esc_html( $this->get_confirm_safe_mode_action_explanation() ); ?>
631
					</p>
632
					<button id="jp-idc-confirm-safe-mode-action" class="dops-button">
633
						<?php echo esc_html( $this->get_confirm_safe_mode_button_text() ); ?>
634
					</button>
635
				</div>
636
637
				<div class="jp-idc-notice__action">
638
					<p class="jp-idc-notice__action__explanation">
639
						<?php echo esc_html( $this->get_first_step_fix_connection_action_explanation() ); ?>
640
					</p>
641
					<button id="jp-idc-fix-connection-action" class="dops-button">
642
						<?php echo esc_html( $this->get_first_step_fix_connection_button_text() ); ?>
643
					</button>
644
				</div>
645
			</div>
646
		</div>
647
		<?php
648
	}
649
650
	/**
651
	 * Renders the second step notice.
652
	 *
653
	 * @return void
654
	 */
655
	public function render_notice_second_step() {
656
		?>
657
		<div class="jp-idc-notice__second-step">
658
			<div class="jp-idc-notice__content-header">
659
				<h3 class="jp-idc-notice__content-header__lead">
660
					<?php echo esc_html( $this->get_second_step_header_lead() ); ?>
661
				</h3>
662
			</div>
663
664
			<?php $this->render_error_notice(); ?>
665
666
			<div class="jp-idc-notice__actions">
667
				<div class="jp-idc-notice__action">
668
					<p class="jp-idc-notice__action__explanation">
669
						<?php echo esc_html( $this->get_migrate_site_action_explanation() ); ?>
670
					</p>
671
					<button id="jp-idc-migrate-action" class="dops-button">
672
						<?php echo esc_html( $this->get_migrate_site_button_text() ); ?>
673
					</button>
674
				</div>
675
676
				<div class="jp-idc-notice__action">
677
					<p class="jp-idc-notice__action__explanation">
678
						<?php echo esc_html( $this->get_start_fresh_action_explanation() ); ?>
679
					</p>
680
					<button id="jp-idc-reconnect-site-action" class="dops-button">
681
						<?php echo esc_html( $this->get_start_fresh_button_text() ); ?>
682
					</button>
683
				</div>
684
685
			</div>
686
687
			<p class="jp-idc-notice__unsure-prompt">
688
				<?php echo esc_html( $this->get_unsure_prompt() ); ?>
689
			</p>
690
		</div>
691
		<?php
692
	}
693
694
	/**
695
	 * Returns the first step header lead.
696
	 *
697
	 * @return string
698
	 */
699
	public function get_first_step_header_lead() {
700
		$html = wp_kses(
701
			sprintf(
702
			/* translators: %s: Safe mode docs URL and site URL. */
703
				__( 'Jetpack has been placed into <a href="%1$s">Safe mode</a> because we noticed this is an exact copy of <a href="%2$s">%3$s</a>.', 'jetpack' ),
704
				esc_url( self::get_safe_mod_doc_url() ),
705
				esc_url( self::$wpcom_home_url ),
706
				self::prepare_url_for_display( esc_url_raw( self::$wpcom_home_url ) )
707
			),
708
			array( 'a' => array( 'href' => array() ) )
709
		);
710
711
		/**
712
		 * Allows overriding of the default header text in the first step of the Safe Mode notice.
713
		 *
714
		 * @param string $html The HTML to be displayed.
715
		 *
716
		 * @since 4.4.0
717
		 */
718
		return apply_filters( 'jetpack_idc_first_step_header_lead', $html );
719
	}
720
721
	/**
722
	 * Returns the first step header explanation.
723
	 *
724
	 * @return string
725
	 */
726 View Code Duplication
	public function get_first_step_header_explanation() {
727
		$html = wp_kses(
728
			sprintf(
729
			/* translators: %s: Safe mode docs URL. */
730
				__( 'Please confirm Safe Mode or fix the Jetpack connection. Select one of the options below or <a href="%1$s">learn more about Safe Mode</a>.', 'jetpack' ),
731
				esc_url( self::get_safe_mod_doc_url() )
732
			),
733
			array( 'a' => array( 'href' => array() ) )
734
		);
735
736
		/**
737
		 * Allows overriding of the default header explanation text in the first step of the Safe Mode notice.
738
		 *
739
		 * @param string $html The HTML to be displayed.
740
		 *
741
		 * @since 4.4.0
742
		 */
743
		return apply_filters( 'jetpack_idc_first_step_header_explanation', $html );
744
	}
745
746
	/**
747
	 * Returns the confirm safe mode explanation.
748
	 *
749
	 * @return string
750
	 */
751
	public function get_confirm_safe_mode_action_explanation() {
752
		$html = wp_kses(
753
			sprintf(
754
			/* translators: %s: Site URL. */
755
				__( 'Is this website a temporary duplicate of <a href="%1$s">%2$s</a> for the purposes of testing, staging or development? If so, we recommend keeping it in Safe Mode.', 'jetpack' ),
756
				esc_url( untrailingslashit( self::$wpcom_home_url ) ),
757
				self::prepare_url_for_display( esc_url( self::$wpcom_home_url ) )
758
			),
759
			array( 'a' => array( 'href' => array() ) )
760
		);
761
762
		/**
763
		 * Allows overriding of the default text used to explain the confirm safe mode action.
764
		 *
765
		 * @param string $html The HTML to be displayed.
766
		 *
767
		 * @since 4.4.0
768
		 */
769
		return apply_filters( 'jetpack_idc_confirm_safe_mode_explanation', $html );
770
	}
771
772
	/**
773
	 * Returns the confirm safe mode button text.
774
	 *
775
	 * @return string
776
	 */
777
	public function get_confirm_safe_mode_button_text() {
778
		$string = esc_html__( 'Confirm Safe Mode', 'jetpack' );
779
780
		/**
781
		 * Allows overriding of the default text used for the confirm safe mode action button.
782
		 *
783
		 * @param string $string The string to be displayed.
784
		 *
785
		 * @since 4.4.0
786
		 */
787
		return apply_filters( 'jetpack_idc_confirm_safe_mode_button_text', $string );
788
	}
789
790
	/**
791
	 * Returns the first step fix connection action explanation.
792
	 *
793
	 * @return string
794
	 */
795
	public function get_first_step_fix_connection_action_explanation() {
796
		$html = wp_kses(
797
			sprintf(
798
			/* translators: %s: Site URL. */
799
				__( 'If this is a separate and new website, or the new home of <a href="%1$s">%2$s</a>, we recommend turning Safe Mode off, and re-establishing your connection to WordPress.com.', 'jetpack' ),
800
				esc_url( untrailingslashit( self::$wpcom_home_url ) ),
801
				self::prepare_url_for_display( esc_url( self::$wpcom_home_url ) )
802
			),
803
			array( 'a' => array( 'href' => array() ) )
804
		);
805
806
		/**
807
		 * Allows overriding of the default text used to explain the fix Jetpack connection action.
808
		 *
809
		 * @param string $html The HTML to be displayed.
810
		 *
811
		 * @since 4.4.0
812
		 */
813
		return apply_filters( 'jetpack_idc_first_fix_connection_explanation', $html );
814
	}
815
816
	/**
817
	 * Returns the first step fix connection button text.
818
	 *
819
	 * @return string
820
	 */
821
	public function get_first_step_fix_connection_button_text() {
822
		$string = esc_html__( "Fix Jetpack's Connection", 'jetpack' );
823
824
		/**
825
		 * Allows overriding of the default text used for the fix Jetpack connection action button.
826
		 *
827
		 * @param string $string The string to be displayed.
828
		 *
829
		 * @since 4.4.0
830
		 */
831
		return apply_filters( 'jetpack_idc_first_step_fix_connection_button_text', $string );
832
	}
833
834
	/**
835
	 * Returns the second step header lead.
836
	 *
837
	 * @return string
838
	 */
839 View Code Duplication
	public function get_second_step_header_lead() {
840
		$string = sprintf(
841
		/* translators: %s: Site URL. */
842
			esc_html__( 'Is %1$s the new home of %2$s?', 'jetpack' ),
843
			untrailingslashit( Jetpack::normalize_url_protocol_agnostic( get_home_url() ) ),
844
			untrailingslashit( Jetpack::normalize_url_protocol_agnostic( esc_url_raw( self::$wpcom_home_url ) ) )
845
		);
846
847
		/**
848
		 * Allows overriding of the default header text in the second step of the Safe Mode notice.
849
		 *
850
		 * @param string $html The HTML to be displayed.
851
		 *
852
		 * @since 4.4.0
853
		 */
854
		return apply_filters( 'jetpack_idc_second_step_header_lead', $string );
855
	}
856
857
	/**
858
	 * Returns the site action explanation.
859
	 *
860
	 * @return string
861
	 */
862 View Code Duplication
	public function get_migrate_site_action_explanation() {
863
		$html = wp_kses(
864
			sprintf(
865
			/* translators: %s: Site URL. */
866
				__( 'Yes. <a href="%1$s">%2$s</a> is replacing <a href="%3$s">%4$s</a>. I would like to migrate my stats and subscribers from <a href="%3$s">%4$s</a> to <a href="%1$s">%2$s</a>.', 'jetpack' ),
867
				esc_url( get_home_url() ),
868
				self::prepare_url_for_display( get_home_url() ),
869
				esc_url( self::$wpcom_home_url ),
870
				untrailingslashit( Jetpack::normalize_url_protocol_agnostic( esc_url_raw( self::$wpcom_home_url ) ) )
871
			),
872
			array( 'a' => array( 'href' => array() ) )
873
		);
874
875
		/**
876
		 * Allows overriding of the default text for explaining the migrate site action.
877
		 *
878
		 * @param string $html The HTML to be displayed.
879
		 *
880
		 * @since 4.4.0
881
		 */
882
		return apply_filters( 'jetpack_idc_migrate_site_explanation', $html );
883
	}
884
885
	/**
886
	 * Returns the migrate site button text.
887
	 *
888
	 * @return string
889
	 */
890
	public function get_migrate_site_button_text() {
891
		$string = esc_html__( 'Migrate Stats &amp; Subscribers', 'jetpack' );
892
893
		/**
894
		 * Allows overriding of the default text used for the migrate site action button.
895
		 *
896
		 * @param string $string The string to be displayed.
897
		 *
898
		 * @since 4.4.0
899
		 */
900
		return apply_filters( 'jetpack_idc_migrate_site_button_text', $string );
901
	}
902
903
	/**
904
	 * Returns the start fresh explanation.
905
	 *
906
	 * @return string
907
	 */
908 View Code Duplication
	public function get_start_fresh_action_explanation() {
909
		$html = wp_kses(
910
			sprintf(
911
			/* translators: %s: Site URL. */
912
				__( 'No. <a href="%1$s">%2$s</a> is a new and different website that\'s separate from <a href="%3$s">%4$s</a>. It requires  a new connection to WordPress.com for new stats and subscribers.', 'jetpack' ),
913
				esc_url( get_home_url() ),
914
				self::prepare_url_for_display( get_home_url() ),
915
				esc_url( self::$wpcom_home_url ),
916
				untrailingslashit( Jetpack::normalize_url_protocol_agnostic( esc_url_raw( self::$wpcom_home_url ) ) )
917
			),
918
			array( 'a' => array( 'href' => array() ) )
919
		);
920
921
		/**
922
		 * Allows overriding of the default text for explaining the start fresh action.
923
		 *
924
		 * @param string $html The HTML to be displayed.
925
		 *
926
		 * @since 4.4.0
927
		 */
928
		return apply_filters( 'jetpack_idc_start_fresh_explanation', $html );
929
	}
930
931
	/**
932
	 * Returns the start fresh button text.
933
	 *
934
	 * @return string
935
	 */
936
	public function get_start_fresh_button_text() {
937
		$string = esc_html__( 'Start Fresh &amp; Create New Connection', 'jetpack' );
938
939
		/**
940
		 * Allows overriding of the default text used for the start fresh action button.
941
		 *
942
		 * @param string $string The string to be displayed.
943
		 *
944
		 * @since 4.4.0
945
		 */
946
		return apply_filters( 'jetpack_idc_start_fresh_button_text', $string );
947
	}
948
949
	/**
950
	 * Returns the unsure prompt text.
951
	 *
952
	 * @return string
953
	 */
954 View Code Duplication
	public function get_unsure_prompt() {
955
		$html = wp_kses(
956
			sprintf(
957
			/* translators: %s: Safe mode docs URL. */
958
				__( 'Unsure what to do? <a href="%1$s">Read more about Jetpack Safe Mode</a>', 'jetpack' ),
959
				esc_url( self::get_safe_mod_doc_url() )
960
			),
961
			array( 'a' => array( 'href' => array() ) )
962
		);
963
964
		/**
965
		 * Allows overriding of the default text using in the "Unsure what to do?" prompt.
966
		 *
967
		 * @param string $html The HTML to be displayed.
968
		 *
969
		 * @since 4.4.0
970
		 */
971
		return apply_filters( 'jetpack_idc_unsure_prompt', $html );
972
	}
973
974
	/**
975
	 * Returns the non-admin notice text.
976
	 *
977
	 * @return string
978
	 */
979 View Code Duplication
	public function get_non_admin_notice_text() {
980
		$html = wp_kses(
981
			sprintf(
982
			/* translators: %s: Safe mode docs URL. */
983
				__( 'Jetpack has been placed into Safe Mode. Learn more about <a href="%1$s">Safe Mode</a>.', 'jetpack' ),
984
				esc_url( self::get_safe_mod_doc_url() )
985
			),
986
			array( 'a' => array( 'href' => array() ) )
987
		);
988
989
		/**
990
		 * Allows overriding of the default text that is displayed to non-admin on the Jetpack admin page.
991
		 *
992
		 * @param string $html The HTML to be displayed.
993
		 *
994
		 * @since 4.4.0
995
		 */
996
		return apply_filters( 'jetpack_idc_non_admin_notice_text', $html );
997
	}
998
999
	/**
1000
	 * Returns the non-admin contact admin text.
1001
	 *
1002
	 * @return string
1003
	 */
1004
	public function get_non_admin_contact_admin_text() {
1005
		$string = esc_html__( 'An administrator of this site can take Jetpack out of Safe Mode.', 'jetpack' );
1006
1007
		/**
1008
		 * Allows overriding of the default text that is displayed to non-admins prompting them to contact an admin.
1009
		 *
1010
		 * @param string $string The string to be displayed.
1011
		 *
1012
		 * @since 4.4.0
1013
		 */
1014
		return apply_filters( 'jetpack_idc_non_admin_contact_admin_text', $string );
1015
	}
1016
}
1017
1018
add_action( 'plugins_loaded', array( 'Identity_Crisis', 'init' ) );
1019