Completed
Push — master ( 6c000b...436ee5 )
by
unknown
11:04
created

WC_Admin_Setup_Wizard::tracking_modal()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 44

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 0
dl 0
loc 44
ccs 0
cts 8
cp 0
crap 2
rs 9.216
c 0
b 0
f 0
1
<?php
2
/**
3
 * Setup Wizard Class
4
 *
5
 * Takes new users through some basic steps to setup their store.
6
 *
7
 * @package     WooCommerce/Admin
8
 * @version     2.6.0
9
 */
10
11 1
if ( ! defined( 'ABSPATH' ) ) {
12
	exit;
13
}
14
15
/**
16
 * WC_Admin_Setup_Wizard class.
17
 */
18
class WC_Admin_Setup_Wizard {
19
20
	/**
21
	 * Current step
22
	 *
23
	 * @var string
24
	 */
25
	private $step = '';
26
27
	/**
28
	 * Steps for the setup wizard
29
	 *
30
	 * @var array
31
	 */
32
	private $steps = array();
33
34
	/**
35
	 * Actions to be executed after the HTTP response has completed
36
	 *
37
	 * @var array
38
	 */
39
	private $deferred_actions = array();
40
41
	/**
42
	 * Tweets user can optionally send after install
43
	 *
44
	 * @var array
45
	 */
46
	private $tweets = array(
47
		'Someone give me woo-t, I just set up a new store with #WordPress and @WooCommerce!',
48
		'Someone give me high five, I just set up a new store with #WordPress and @WooCommerce!',
49
	);
50
51
	/**
52
	 * Hook in tabs.
53
	 */
54 1
	public function __construct() {
55 1
		if ( apply_filters( 'woocommerce_enable_setup_wizard', true ) && current_user_can( 'manage_woocommerce' ) ) {
56
			add_action( 'admin_menu', array( $this, 'admin_menus' ) );
57
			add_action( 'admin_init', array( $this, 'setup_wizard' ) );
58
			add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
59
		}
60
	}
61
62
	/**
63
	 * Add admin menus/screens.
64
	 */
65
	public function admin_menus() {
66
		add_dashboard_page( '', '', 'manage_options', 'wc-setup', '' );
67
	}
68
69
	/**
70
	 * The theme "extra" should only be shown if the current user can modify themes
71
	 * and the store doesn't already have a WooCommerce theme.
72
	 *
73
	 * @return boolean
74
	 */
75
	protected function should_show_theme() {
76
		$support_woocommerce = current_theme_supports( 'woocommerce' ) && ! $this->is_default_theme();
77
78
		return (
79
			current_user_can( 'install_themes' ) &&
80
			current_user_can( 'switch_themes' ) &&
81
			! is_multisite() &&
82
			! $support_woocommerce
83
		);
84
	}
85
86
	/**
87
	 * Is the user using a default WP theme?
88
	 *
89
	 * @return boolean
90
	 */
91
	protected function is_default_theme() {
92
		return wc_is_active_theme(
93
			array(
94
				'twentynineteen',
95
				'twentyseventeen',
96
				'twentysixteen',
97
				'twentyfifteen',
98
				'twentyfourteen',
99
				'twentythirteen',
100
				'twentyeleven',
101
				'twentytwelve',
102
				'twentyten',
103
			)
104
		);
105
	}
106
107
	/**
108
	 * The "automated tax" extra should only be shown if the current user can
109
	 * install plugins and the store is in a supported country.
110
	 */
111
	protected function should_show_automated_tax() {
112
		if ( ! current_user_can( 'install_plugins' ) ) {
113
			return false;
114
		}
115
116
		$country_code = WC()->countries->get_base_country();
117
		// https://developers.taxjar.com/api/reference/#countries .
118
		$tax_supported_countries = array_merge(
119
			array( 'US', 'CA', 'AU' ),
120
			WC()->countries->get_european_union_countries()
121
		);
122
123
		return in_array( $country_code, $tax_supported_countries, true );
124
	}
125
126
	/**
127
	 * Should we show the MailChimp install option?
128
	 * True only if the user can install plugins.
129
	 *
130
	 * @return boolean
131
	 */
132
	protected function should_show_mailchimp() {
133
		return current_user_can( 'install_plugins' );
134
	}
135
136
	/**
137
	 * Should we show the Facebook install option?
138
	 * True only if the user can install plugins,
139
	 * and up until the end date of the recommendation.
140
	 *
141
	 * @return boolean
142
	 */
143
	protected function should_show_facebook() {
144
		return current_user_can( 'install_plugins' );
145
	}
146
147
	/**
148
	 * Should we show the WooCommerce Admin install option?
149
	 * True only if the user can install plugins,
150
	 * and up until the end date of the recommendation.
151
	 *
152
	 * @return boolean
153
	 */
154
	protected function should_show_wc_admin() {
155
		return current_user_can( 'install_plugins' );
156
	}
157
158
	/**
159
	 * Should we display the 'Recommended' step?
160
	 * True if at least one of the recommendations will be displayed.
161
	 *
162
	 * @return boolean
163
	 */
164
	protected function should_show_recommended_step() {
165
		return $this->should_show_theme()
166
			|| $this->should_show_automated_tax()
167
			|| $this->should_show_mailchimp()
168
			|| $this->should_show_facebook()
169
			|| $this->should_show_wc_admin();
170
	}
171
172
	/**
173
	 * Register/enqueue scripts and styles for the Setup Wizard.
174
	 *
175
	 * Hooked onto 'admin_enqueue_scripts'.
176
	 */
177
	public function enqueue_scripts() {
178
		// Whether or not there is a pending background install of Jetpack.
179
		$pending_jetpack = ! class_exists( 'Jetpack' ) && get_option( 'woocommerce_setup_background_installing_jetpack' );
180
		$suffix          = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
181
182
		wp_register_script( 'jquery-blockui', WC()->plugin_url() . '/assets/js/jquery-blockui/jquery.blockUI' . $suffix . '.js', array( 'jquery' ), '2.70', true );
183
		wp_register_script( 'selectWoo', WC()->plugin_url() . '/assets/js/selectWoo/selectWoo.full' . $suffix . '.js', array( 'jquery' ), '1.0.6' );
184
		wp_register_script( 'wc-enhanced-select', WC()->plugin_url() . '/assets/js/admin/wc-enhanced-select' . $suffix . '.js', array( 'jquery', 'selectWoo' ), WC_VERSION );
185
		wp_localize_script(
186
			'wc-enhanced-select',
187
			'wc_enhanced_select_params',
188
			array(
189
				'i18n_no_matches'           => _x( 'No matches found', 'enhanced select', 'woocommerce' ),
190
				'i18n_ajax_error'           => _x( 'Loading failed', 'enhanced select', 'woocommerce' ),
191
				'i18n_input_too_short_1'    => _x( 'Please enter 1 or more characters', 'enhanced select', 'woocommerce' ),
192
				'i18n_input_too_short_n'    => _x( 'Please enter %qty% or more characters', 'enhanced select', 'woocommerce' ),
193
				'i18n_input_too_long_1'     => _x( 'Please delete 1 character', 'enhanced select', 'woocommerce' ),
194
				'i18n_input_too_long_n'     => _x( 'Please delete %qty% characters', 'enhanced select', 'woocommerce' ),
195
				'i18n_selection_too_long_1' => _x( 'You can only select 1 item', 'enhanced select', 'woocommerce' ),
196
				'i18n_selection_too_long_n' => _x( 'You can only select %qty% items', 'enhanced select', 'woocommerce' ),
197
				'i18n_load_more'            => _x( 'Loading more results&hellip;', 'enhanced select', 'woocommerce' ),
198
				'i18n_searching'            => _x( 'Searching&hellip;', 'enhanced select', 'woocommerce' ),
199
				'ajax_url'                  => admin_url( 'admin-ajax.php' ),
200
				'search_products_nonce'     => wp_create_nonce( 'search-products' ),
201
				'search_customers_nonce'    => wp_create_nonce( 'search-customers' ),
202
			)
203
		);
204
		wp_enqueue_style( 'woocommerce_admin_styles', WC()->plugin_url() . '/assets/css/admin.css', array(), WC_VERSION );
205
		wp_enqueue_style( 'wc-setup', WC()->plugin_url() . '/assets/css/wc-setup.css', array( 'dashicons', 'install' ), WC_VERSION );
206
207
		wp_register_script( 'wc-setup', WC()->plugin_url() . '/assets/js/admin/wc-setup' . $suffix . '.js', array( 'jquery', 'wc-enhanced-select', 'jquery-blockui', 'wp-util', 'jquery-tiptip', 'backbone', 'wc-backbone-modal' ), WC_VERSION );
208
		wp_localize_script(
209
			'wc-setup',
210
			'wc_setup_params',
211
			array(
212
				'pending_jetpack_install' => $pending_jetpack ? 'yes' : 'no',
213
				'states'                  => WC()->countries->get_states(),
214
				'postcodes'               => $this->get_postcodes(),
215
				'current_step'            => isset( $this->steps[ $this->step ] ) ? $this->step : false,
216
				'i18n'                    => array(
217
					'extra_plugins' => array(
218
						'payment' => array(
219
							'stripe_create_account'        => __( 'Stripe setup is powered by Jetpack and WooCommerce Services.', 'woocommerce' ),
220
							'ppec_paypal_reroute_requests' => __( 'PayPal setup is powered by Jetpack and WooCommerce Services.', 'woocommerce' ),
221
							'stripe_create_account,ppec_paypal_reroute_requests' => __( 'Stripe and PayPal setup are powered by Jetpack and WooCommerce Services.', 'woocommerce' ),
222
						),
223
					),
224
				),
225
			)
226
		);
227
	}
228
229
	/**
230
	 * Helper method to get postcode configurations from `WC()->countries->get_country_locale()`.
231
	 * We don't use `wp_list_pluck` because it will throw notices when postcode configuration is not defined for a country.
232
	 *
233
	 * @return array
234
	 */
235
	private function get_postcodes() {
236
		$locales   = WC()->countries->get_country_locale();
237
		$postcodes = array();
238
		foreach ( $locales as $country_code => $locale ) {
239
			if ( isset( $locale['postcode'] ) ) {
240
				$postcodes[ $country_code ] = $locale['postcode'];
241
			}
242
		}
243
		return $postcodes;
244
	}
245
246
	/**
247
	 * Show the setup wizard.
248
	 */
249
	public function setup_wizard() {
250
		if ( empty( $_GET['page'] ) || 'wc-setup' !== $_GET['page'] ) { // WPCS: CSRF ok, input var ok.
251
			return;
252
		}
253
		$default_steps = array(
254
			'store_setup' => array(
255
				'name'    => __( 'Store setup', 'woocommerce' ),
256
				'view'    => array( $this, 'wc_setup_store_setup' ),
257
				'handler' => array( $this, 'wc_setup_store_setup_save' ),
258
			),
259
			'payment'     => array(
260
				'name'    => __( 'Payment', 'woocommerce' ),
261
				'view'    => array( $this, 'wc_setup_payment' ),
262
				'handler' => array( $this, 'wc_setup_payment_save' ),
263
			),
264
			'shipping'    => array(
265
				'name'    => __( 'Shipping', 'woocommerce' ),
266
				'view'    => array( $this, 'wc_setup_shipping' ),
267
				'handler' => array( $this, 'wc_setup_shipping_save' ),
268
			),
269
			'recommended' => array(
270
				'name'    => __( 'Recommended', 'woocommerce' ),
271
				'view'    => array( $this, 'wc_setup_recommended' ),
272
				'handler' => array( $this, 'wc_setup_recommended_save' ),
273
			),
274
			'activate'    => array(
275
				'name'    => __( 'Activate', 'woocommerce' ),
276
				'view'    => array( $this, 'wc_setup_activate' ),
277
				'handler' => array( $this, 'wc_setup_activate_save' ),
278
			),
279
			'next_steps'  => array(
280
				'name'    => __( 'Ready!', 'woocommerce' ),
281
				'view'    => array( $this, 'wc_setup_ready' ),
282
				'handler' => '',
283
			),
284
		);
285
286
		// Hide recommended step if nothing is going to be shown there.
287
		if ( ! $this->should_show_recommended_step() ) {
288
			unset( $default_steps['recommended'] );
289
		}
290
291
		// Hide shipping step if the store is selling digital products only.
292
		if ( 'virtual' === get_option( 'woocommerce_product_type' ) ) {
293
			unset( $default_steps['shipping'] );
294
		}
295
296
		// Hide activate section when the user does not have capabilities to install plugins, think multiside admins not being a super admin.
297
		if ( ! current_user_can( 'install_plugins' ) ) {
298
			unset( $default_steps['activate'] );
299
		}
300
301
		$this->steps = apply_filters( 'woocommerce_setup_wizard_steps', $default_steps );
302
		$this->step  = isset( $_GET['step'] ) ? sanitize_key( $_GET['step'] ) : current( array_keys( $this->steps ) ); // WPCS: CSRF ok, input var ok.
303
304
		// @codingStandardsIgnoreStart
305 View Code Duplication
		if ( ! empty( $_POST['save_step'] ) && isset( $this->steps[ $this->step ]['handler'] ) ) {
306
			call_user_func( $this->steps[ $this->step ]['handler'], $this );
307
		}
308
		// @codingStandardsIgnoreEnd
309
310
		ob_start();
311
		$this->setup_wizard_header();
312
		$this->setup_wizard_steps();
313
		$this->setup_wizard_content();
314
		$this->setup_wizard_footer();
315
		exit;
316
	}
317
318
	/**
319
	 * Get the URL for the next step's screen.
320
	 *
321
	 * @param string $step  slug (default: current step).
322
	 * @return string       URL for next step if a next step exists.
323
	 *                      Admin URL if it's the last step.
324
	 *                      Empty string on failure.
325
	 * @since 3.0.0
326
	 */
327
	public function get_next_step_link( $step = '' ) {
328
		if ( ! $step ) {
329
			$step = $this->step;
330
		}
331
332
		$keys = array_keys( $this->steps );
333
		if ( end( $keys ) === $step ) {
334
			return admin_url();
335
		}
336
337
		$step_index = array_search( $step, $keys, true );
338
		if ( false === $step_index ) {
339
			return '';
340
		}
341
342
		return add_query_arg( 'step', $keys[ $step_index + 1 ], remove_query_arg( 'activate_error' ) );
343
	}
344
345
	/**
346
	 * Setup Wizard Header.
347
	 */
348
	public function setup_wizard_header() {
349
		set_current_screen();
350
		?>
351
		<!DOCTYPE html>
352
		<html <?php language_attributes(); ?>>
353
		<head>
354
			<meta name="viewport" content="width=device-width" />
355
			<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
356
			<title><?php esc_html_e( 'WooCommerce &rsaquo; Setup Wizard', 'woocommerce' ); ?></title>
357
			<?php do_action( 'admin_enqueue_scripts' ); ?>
358
			<?php wp_print_scripts( 'wc-setup' ); ?>
359
			<?php do_action( 'admin_print_styles' ); ?>
360
			<?php do_action( 'admin_head' ); ?>
361
		</head>
362
		<body class="wc-setup wp-core-ui">
363
			<h1 id="wc-logo"><a href="https://woocommerce.com/"><img src="<?php echo esc_url( WC()->plugin_url() ); ?>/assets/images/woocommerce_logo.png" alt="<?php esc_attr_e( 'WooCommerce', 'woocommerce' ); ?>" /></a></h1>
364
		<?php
365
	}
366
367
	/**
368
	 * Setup Wizard Footer.
369
	 */
370
	public function setup_wizard_footer() {
371
		?>
372
			<?php if ( 'store_setup' === $this->step ) : ?>
373
				<a class="wc-setup-footer-links" href="<?php echo esc_url( admin_url() ); ?>"><?php esc_html_e( 'Not right now', 'woocommerce' ); ?></a>
374
			<?php elseif ( 'recommended' === $this->step || 'activate' === $this->step ) : ?>
375
				<a class="wc-setup-footer-links" href="<?php echo esc_url( $this->get_next_step_link() ); ?>"><?php esc_html_e( 'Skip this step', 'woocommerce' ); ?></a>
376
			<?php endif; ?>
377
			<?php do_action( 'woocommerce_setup_footer' ); ?>
378
			</body>
379
		</html>
380
		<?php
381
	}
382
383
	/**
384
	 * Output the steps.
385
	 */
386
	public function setup_wizard_steps() {
387
		$output_steps      = $this->steps;
388
		$selected_features = array_filter( $this->wc_setup_activate_get_feature_list() );
389
390
		// Hide the activate step if Jetpack is already active, unless WooCommerce Services
391
		// features are selected, or unless the Activate step was already taken.
392
		if ( class_exists( 'Jetpack' ) && Jetpack::is_active() && empty( $selected_features ) && 'yes' !== get_transient( 'wc_setup_activated' ) ) {
393
			unset( $output_steps['activate'] );
394
		}
395
396
		?>
397
		<ol class="wc-setup-steps">
398
			<?php
399
			foreach ( $output_steps as $step_key => $step ) {
400
				$is_completed = array_search( $this->step, array_keys( $this->steps ), true ) > array_search( $step_key, array_keys( $this->steps ), true );
401
402
				if ( $step_key === $this->step ) {
403
					?>
404
					<li class="active"><?php echo esc_html( $step['name'] ); ?></li>
405
					<?php
406
				} elseif ( $is_completed ) {
407
					?>
408
					<li class="done">
409
						<a href="<?php echo esc_url( add_query_arg( 'step', $step_key, remove_query_arg( 'activate_error' ) ) ); ?>"><?php echo esc_html( $step['name'] ); ?></a>
410
					</li>
411
					<?php
412
				} else {
413
					?>
414
					<li><?php echo esc_html( $step['name'] ); ?></li>
415
					<?php
416
				}
417
			}
418
			?>
419
		</ol>
420
		<?php
421
	}
422
423
	/**
424
	 * Output the content for the current step.
425
	 */
426
	public function setup_wizard_content() {
427
		echo '<div class="wc-setup-content">';
428
		if ( ! empty( $this->steps[ $this->step ]['view'] ) ) {
429
			call_user_func( $this->steps[ $this->step ]['view'], $this );
430
		}
431
		echo '</div>';
432
	}
433
434
	/**
435
	 * Initial "store setup" step.
436
	 * Location, product type, page setup, and tracking opt-in.
437
	 */
438
	public function wc_setup_store_setup() {
439
		$address        = WC()->countries->get_base_address();
440
		$address_2      = WC()->countries->get_base_address_2();
441
		$city           = WC()->countries->get_base_city();
442
		$state          = WC()->countries->get_base_state();
443
		$country        = WC()->countries->get_base_country();
444
		$postcode       = WC()->countries->get_base_postcode();
445
		$currency       = get_option( 'woocommerce_currency', 'GBP' );
446
		$product_type   = get_option( 'woocommerce_product_type', 'both' );
447
		$sell_in_person = get_option( 'woocommerce_sell_in_person', 'none_selected' );
448
449
		if ( empty( $country ) ) {
450
			$user_location = WC_Geolocation::geolocate_ip();
451
			$country       = $user_location['country'];
452
			$state         = $user_location['state'];
453
		}
454
455
		$locale_info         = include WC()->plugin_path() . '/i18n/locale-info.php';
456
		$currency_by_country = wp_list_pluck( $locale_info, 'currency_code' );
457
		?>
458
		<form method="post" class="address-step">
459
			<input type="hidden" name="save_step" value="store_setup" />
460
			<?php wp_nonce_field( 'wc-setup' ); ?>
461
			<p class="store-setup"><?php esc_html_e( 'The following wizard will help you configure your store and get you started quickly.', 'woocommerce' ); ?></p>
462
463
			<div class="store-address-container">
464
465
				<label for="store_country" class="location-prompt"><?php esc_html_e( 'Where is your store based?', 'woocommerce' ); ?></label>
466
				<select id="store_country" name="store_country" required data-placeholder="<?php esc_attr_e( 'Choose a country&hellip;', 'woocommerce' ); ?>" aria-label="<?php esc_attr_e( 'Country', 'woocommerce' ); ?>" class="location-input wc-enhanced-select dropdown">
467
					<?php foreach ( WC()->countries->get_countries() as $code => $label ) : ?>
468
						<option <?php selected( $code, $country ); ?> value="<?php echo esc_attr( $code ); ?>"><?php echo esc_html( $label ); ?></option>
469
					<?php endforeach; ?>
470
				</select>
471
472
				<label class="location-prompt" for="store_address"><?php esc_html_e( 'Address', 'woocommerce' ); ?></label>
473
				<input type="text" id="store_address" class="location-input" name="store_address" required value="<?php echo esc_attr( $address ); ?>" />
474
475
				<label class="location-prompt" for="store_address_2"><?php esc_html_e( 'Address line 2', 'woocommerce' ); ?></label>
476
				<input type="text" id="store_address_2" class="location-input" name="store_address_2" value="<?php echo esc_attr( $address_2 ); ?>" />
477
478
				<div class="city-and-postcode">
479
					<div>
480
						<label class="location-prompt" for="store_city"><?php esc_html_e( 'City', 'woocommerce' ); ?></label>
481
						<input type="text" id="store_city" class="location-input" name="store_city" required value="<?php echo esc_attr( $city ); ?>" />
482
					</div>
483
					<div class="store-state-container hidden">
484
						<label for="store_state" class="location-prompt">
485
							<?php esc_html_e( 'State', 'woocommerce' ); ?>
486
						</label>
487
						<select id="store_state" name="store_state" data-placeholder="<?php esc_attr_e( 'Choose a state&hellip;', 'woocommerce' ); ?>" aria-label="<?php esc_attr_e( 'State', 'woocommerce' ); ?>" class="location-input wc-enhanced-select dropdown"></select>
488
					</div>
489
					<div>
490
						<label class="location-prompt" for="store_postcode"><?php esc_html_e( 'Postcode / ZIP', 'woocommerce' ); ?></label>
491
						<input type="text" id="store_postcode" class="location-input" name="store_postcode" required value="<?php echo esc_attr( $postcode ); ?>" />
492
					</div>
493
				</div>
494
			</div>
495
496
			<div class="store-currency-container">
497
			<label class="location-prompt" for="currency_code">
498
				<?php esc_html_e( 'What currency do you accept payments in?', 'woocommerce' ); ?>
499
			</label>
500
			<select
501
				id="currency_code"
502
				name="currency_code"
503
				required
504
				data-placeholder="<?php esc_attr_e( 'Choose a currency&hellip;', 'woocommerce' ); ?>"
505
				class="location-input wc-enhanced-select dropdown"
506
			>
507
				<option value=""><?php esc_html_e( 'Choose a currency&hellip;', 'woocommerce' ); ?></option>
508
				<?php foreach ( get_woocommerce_currencies() as $code => $name ) : ?>
509
					<option value="<?php echo esc_attr( $code ); ?>" <?php selected( $currency, $code ); ?>>
510
						<?php
511
						$symbol = get_woocommerce_currency_symbol( $code );
512
513
						if ( $symbol === $code ) {
514
							/* translators: 1: currency name 2: currency code */
515
							echo esc_html( sprintf( __( '%1$s (%2$s)', 'woocommerce' ), $name, $code ) );
516
						} else {
517
							/* translators: 1: currency name 2: currency symbol, 3: currency code */
518
							echo esc_html( sprintf( __( '%1$s (%2$s %3$s)', 'woocommerce' ), $name, get_woocommerce_currency_symbol( $code ), $code ) );
519
						}
520
						?>
521
					</option>
522
				<?php endforeach; ?>
523
			</select>
524
			<script type="text/javascript">
525
				var wc_setup_currencies = JSON.parse( decodeURIComponent( '<?php echo rawurlencode( wp_json_encode( $currency_by_country ) ); ?>' ) );
526
				var wc_base_state       = "<?php echo esc_js( $state ); ?>";
527
			</script>
528
			</div>
529
530
			<div class="product-type-container">
531
			<label class="location-prompt" for="product_type">
532
				<?php esc_html_e( 'What type of products do you plan to sell?', 'woocommerce' ); ?>
533
			</label>
534
			<select id="product_type" name="product_type" required class="location-input wc-enhanced-select dropdown">
535
				<option value="both" <?php selected( $product_type, 'both' ); ?>><?php esc_html_e( 'I plan to sell both physical and digital products', 'woocommerce' ); ?></option>
536
				<option value="physical" <?php selected( $product_type, 'physical' ); ?>><?php esc_html_e( 'I plan to sell physical products', 'woocommerce' ); ?></option>
537
				<option value="virtual" <?php selected( $product_type, 'virtual' ); ?>><?php esc_html_e( 'I plan to sell digital products', 'woocommerce' ); ?></option>
538
			</select>
539
			</div>
540
541
			<input
542
				type="checkbox"
543
				id="woocommerce_sell_in_person"
544
				name="sell_in_person"
545
				value="yes"
546
				<?php checked( $sell_in_person, true ); ?>
547
			/>
548
			<label class="location-prompt" for="woocommerce_sell_in_person">
549
				<?php esc_html_e( 'I will also be selling products or services in person.', 'woocommerce' ); ?>
550
			</label>
551
552
			<input type="checkbox" id="wc_tracker_checkbox" name="wc_tracker_checkbox" value="yes" <?php checked( 'yes', get_option( 'woocommerce_allow_tracking', 'no' ) ); ?> />
553
554
			<?php $this->tracking_modal(); ?>
555
556
			<p class="wc-setup-actions step">
557
				<button class="button-primary button button-large" value="<?php esc_attr_e( "Let's go!", 'woocommerce' ); ?>" name="save_step"><?php esc_html_e( "Let's go!", 'woocommerce' ); ?></button>
558
			</p>
559
		</form>
560
		<?php
561
	}
562
563
	/**
564
	 * Template for the usage tracking modal.
565
	 */
566
	public function tracking_modal() {
567
		?>
568
		<script type="text/template" id="tmpl-wc-modal-tracking-setup">
569
			<div class="wc-backbone-modal woocommerce-tracker">
570
				<div class="wc-backbone-modal-content">
571
					<section class="wc-backbone-modal-main" role="main">
572
						<header class="wc-backbone-modal-header">
573
							<h1><?php esc_html_e( 'Help improve WooCommerce with usage tracking', 'woocommerce' ); ?></h1>
574
						</header>
575
						<article>
576
							<p>
577
							<?php
578
								printf(
579
									wp_kses(
580
										/* translators: %1$s: usage tracking help link */
581
										__( 'Learn more about how usage tracking works, and how you\'ll be helping <a href="%1$s" target="_blank">here</a>.', 'woocommerce' ),
582
										array(
583
											'a'    => array(
584
												'href'   => array(),
585
												'target' => array(),
586
											),
587
										)
588
									),
589
									'https://woocommerce.com/usage-tracking/'
590
								);
591
							?>
592
							</p>
593
							<p class="woocommerce-tracker-checkbox">
594
								<input type="checkbox" id="wc_tracker_checkbox_dialog" name="wc_tracker_checkbox_dialog" value="yes" <?php checked( 'yes', get_option( 'woocommerce_allow_tracking', 'no' ) ); ?> />
595
								<label for="wc_tracker_checkbox_dialog"><?php esc_html_e( 'Enable usage tracking and help improve WooCommerce', 'woocommerce' ); ?></label>
596
							</p>
597
						</article>
598
						<footer>
599
							<div class="inner">
600
								<button class="button button-primary button-large" id="wc_tracker_submit" aria-label="<?php esc_attr_e( 'Continue', 'woocommerce' ); ?>"><?php esc_html_e( 'Continue', 'woocommerce' ); ?></a>
601
							</div>
602
						</footer>
603
					</section>
604
				</div>
605
			</div>
606
			<div class="wc-backbone-modal-backdrop modal-close"></div>
607
		</script>
608
		<?php
609
	}
610
611
	/**
612
	 * Save initial store settings.
613
	 */
614
	public function wc_setup_store_setup_save() {
615
		check_admin_referer( 'wc-setup' );
616
617
		$address        = isset( $_POST['store_address'] ) ? wc_clean( wp_unslash( $_POST['store_address'] ) ) : '';
618
		$address_2      = isset( $_POST['store_address_2'] ) ? wc_clean( wp_unslash( $_POST['store_address_2'] ) ) : '';
619
		$city           = isset( $_POST['store_city'] ) ? wc_clean( wp_unslash( $_POST['store_city'] ) ) : '';
620
		$country        = isset( $_POST['store_country'] ) ? wc_clean( wp_unslash( $_POST['store_country'] ) ) : '';
621
		$state          = isset( $_POST['store_state'] ) ? wc_clean( wp_unslash( $_POST['store_state'] ) ) : '*';
622
		$postcode       = isset( $_POST['store_postcode'] ) ? wc_clean( wp_unslash( $_POST['store_postcode'] ) ) : '';
623
		$currency_code  = isset( $_POST['currency_code'] ) ? wc_clean( wp_unslash( $_POST['currency_code'] ) ) : '';
624
		$product_type   = isset( $_POST['product_type'] ) ? wc_clean( wp_unslash( $_POST['product_type'] ) ) : '';
625
		$sell_in_person = isset( $_POST['sell_in_person'] ) && ( 'yes' === wc_clean( wp_unslash( $_POST['sell_in_person'] ) ) );
626
		$tracking       = isset( $_POST['wc_tracker_checkbox'] ) && ( 'yes' === wc_clean( wp_unslash( $_POST['wc_tracker_checkbox'] ) ) );
627
628
		update_option( 'woocommerce_store_address', $address );
629
		update_option( 'woocommerce_store_address_2', $address_2 );
630
		update_option( 'woocommerce_store_city', $city );
631
		update_option( 'woocommerce_default_country', $country . ':' . $state );
632
		update_option( 'woocommerce_store_postcode', $postcode );
633
		update_option( 'woocommerce_currency', $currency_code );
634
		update_option( 'woocommerce_product_type', $product_type );
635
		update_option( 'woocommerce_sell_in_person', $sell_in_person );
636
637
		$locale_info = include WC()->plugin_path() . '/i18n/locale-info.php';
638
639
		if ( isset( $locale_info[ $country ] ) ) {
640
			update_option( 'woocommerce_weight_unit', $locale_info[ $country ]['weight_unit'] );
641
			update_option( 'woocommerce_dimension_unit', $locale_info[ $country ]['dimension_unit'] );
642
643
			// Set currency formatting options based on chosen location and currency.
644
			if ( $locale_info[ $country ]['currency_code'] === $currency_code ) {
645
				update_option( 'woocommerce_currency_pos', $locale_info[ $country ]['currency_pos'] );
646
				update_option( 'woocommerce_price_decimal_sep', $locale_info[ $country ]['decimal_sep'] );
647
				update_option( 'woocommerce_price_num_decimals', $locale_info[ $country ]['num_decimals'] );
648
				update_option( 'woocommerce_price_thousand_sep', $locale_info[ $country ]['thousand_sep'] );
649
			}
650
		}
651
652
		if ( $tracking ) {
653
			update_option( 'woocommerce_allow_tracking', 'yes' );
654
			wp_schedule_single_event( time() + 10, 'woocommerce_tracker_send_event', array( true ) );
655
		} else {
656
			update_option( 'woocommerce_allow_tracking', 'no' );
657
		}
658
659
		WC_Install::create_pages();
660
		wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
661
		exit;
662
	}
663
664
	/**
665
	 * Finishes replying to the client, but keeps the process running for further (async) code execution.
666
	 *
667
	 * @see https://core.trac.wordpress.org/ticket/41358 .
668
	 */
669 View Code Duplication
	protected function close_http_connection() {
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
670
		// Only 1 PHP process can access a session object at a time, close this so the next request isn't kept waiting.
671
		// @codingStandardsIgnoreStart
672
		if ( session_id() ) {
673
			session_write_close();
674
		}
675
		// @codingStandardsIgnoreEnd
676
677
		wc_set_time_limit( 0 );
678
679
		// fastcgi_finish_request is the cleanest way to send the response and keep the script running, but not every server has it.
680
		if ( is_callable( 'fastcgi_finish_request' ) ) {
681
			fastcgi_finish_request();
682
		} else {
683
			// Fallback: send headers and flush buffers.
684
			if ( ! headers_sent() ) {
685
				header( 'Connection: close' );
686
			}
687
			@ob_end_flush(); // @codingStandardsIgnoreLine.
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
688
			flush();
689
		}
690
	}
691
692
	/**
693
	 * Function called after the HTTP request is finished, so it's executed without the client having to wait for it.
694
	 *
695
	 * @see WC_Admin_Setup_Wizard::install_plugin
696
	 * @see WC_Admin_Setup_Wizard::install_theme
697
	 */
698
	public function run_deferred_actions() {
699
		$this->close_http_connection();
700
		foreach ( $this->deferred_actions as $action ) {
701
			call_user_func_array( $action['func'], $action['args'] );
702
703
			// Clear the background installation flag if this is a plugin.
704
			if (
705
				isset( $action['func'][1] ) &&
706
				'background_installer' === $action['func'][1] &&
707
				isset( $action['args'][0] )
708
			) {
709
				delete_option( 'woocommerce_setup_background_installing_' . $action['args'][0] );
710
			}
711
		}
712
	}
713
714
	/**
715
	 * Helper method to queue the background install of a plugin.
716
	 *
717
	 * @param string $plugin_id  Plugin id used for background install.
718
	 * @param array  $plugin_info Plugin info array containing name and repo-slug, and optionally file if different from [repo-slug].php.
719
	 */
720
	protected function install_plugin( $plugin_id, $plugin_info ) {
721
		// Make sure we don't trigger multiple simultaneous installs.
722
		if ( get_option( 'woocommerce_setup_background_installing_' . $plugin_id ) ) {
723
			return;
724
		}
725
726
		$plugin_file = isset( $plugin_info['file'] ) ? $plugin_info['file'] : $plugin_info['repo-slug'] . '.php';
727
		if ( is_plugin_active( $plugin_info['repo-slug'] . '/' . $plugin_file ) ) {
728
			return;
729
		}
730
731
		if ( empty( $this->deferred_actions ) ) {
732
			add_action( 'shutdown', array( $this, 'run_deferred_actions' ) );
733
		}
734
735
		array_push(
736
			$this->deferred_actions,
737
			array(
738
				'func' => array( 'WC_Install', 'background_installer' ),
739
				'args' => array( $plugin_id, $plugin_info ),
740
			)
741
		);
742
743
		// Set the background installation flag for this plugin.
744
		update_option( 'woocommerce_setup_background_installing_' . $plugin_id, true );
745
	}
746
747
748
	/**
749
	 * Helper method to queue the background install of a theme.
750
	 *
751
	 * @param string $theme_id  Theme id used for background install.
752
	 */
753
	protected function install_theme( $theme_id ) {
754
		if ( empty( $this->deferred_actions ) ) {
755
			add_action( 'shutdown', array( $this, 'run_deferred_actions' ) );
756
		}
757
		array_push(
758
			$this->deferred_actions,
759
			array(
760
				'func' => array( 'WC_Install', 'theme_background_installer' ),
761
				'args' => array( $theme_id ),
762
			)
763
		);
764
	}
765
766
	/**
767
	 * Helper method to install Jetpack.
768
	 */
769
	protected function install_jetpack() {
770
		$this->install_plugin(
771
			'jetpack',
772
			array(
773
				'name'      => __( 'Jetpack', 'woocommerce' ),
774
				'repo-slug' => 'jetpack',
775
			)
776
		);
777
	}
778
779
	/**
780
	 * Helper method to install WooCommerce Services and its Jetpack dependency.
781
	 */
782
	protected function install_woocommerce_services() {
783
		$this->install_jetpack();
784
		$this->install_plugin(
785
			'woocommerce-services',
786
			array(
787
				'name'      => __( 'WooCommerce Services', 'woocommerce' ),
788
				'repo-slug' => 'woocommerce-services',
789
			)
790
		);
791
	}
792
793
	/**
794
	 * Retrieve info for missing WooCommerce Services and/or Jetpack plugin.
795
	 *
796
	 * @return array
797
	 */
798 1
	protected function get_wcs_requisite_plugins() {
799 1
		$plugins = array();
800 1 View Code Duplication
		if ( ! is_plugin_active( 'woocommerce-services/woocommerce-services.php' ) && ! get_option( 'woocommerce_setup_background_installing_woocommerce-services' ) ) {
801 1
			$plugins[] = array(
802 1
				'name' => __( 'WooCommerce Services', 'woocommerce' ),
803 1
				'slug' => 'woocommerce-services',
804
			);
805
		}
806 1 View Code Duplication
		if ( ! is_plugin_active( 'jetpack/jetpack.php' ) && ! get_option( 'woocommerce_setup_background_installing_jetpack' ) ) {
807 1
			$plugins[] = array(
808 1
				'name' => __( 'Jetpack', 'woocommerce' ),
809 1
				'slug' => 'jetpack',
810
			);
811
		}
812 1
		return $plugins;
813
	}
814
815
	/**
816
	 * Plugin install info message markup with heading.
817
	 */
818
	public function plugin_install_info() {
819
		?>
820
		<span class="plugin-install-info">
821
			<span class="plugin-install-info-label"><?php esc_html_e( 'The following plugins will be installed and activated for you:', 'woocommerce' ); ?></span>
822
			<span class="plugin-install-info-list"></span>
823
		</span>
824
		<?php
825
	}
826
827
	/**
828
	 * Get shipping methods based on country code.
829
	 *
830
	 * @param string $country_code Country code.
831
	 * @param string $currency_code Currency code.
832
	 * @return array
833
	 */
834
	protected function get_wizard_shipping_methods( $country_code, $currency_code ) {
0 ignored issues
show
Unused Code introduced by
The parameter $country_code is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $currency_code is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
835
		$shipping_methods = array(
836
			'flat_rate'     => array(
837
				'name'        => __( 'Flat Rate', 'woocommerce' ),
838
				'description' => __( 'Set a fixed price to cover shipping costs.', 'woocommerce' ),
839
				'settings'    => array(
840
					'cost' => array(
841
						'type'          => 'text',
842
						'default_value' => __( 'Cost', 'woocommerce' ),
843
						'description'   => __( 'What would you like to charge for flat rate shipping?', 'woocommerce' ),
844
						'required'      => true,
845
					),
846
				),
847
			),
848
			'free_shipping' => array(
849
				'name'        => __( 'Free Shipping', 'woocommerce' ),
850
				'description' => __( "Don't charge for shipping.", 'woocommerce' ),
851
			),
852
		);
853
854
		return $shipping_methods;
855
	}
856
857
	/**
858
	 * Render the available shipping methods for a given country code.
859
	 *
860
	 * @param string $country_code Country code.
861
	 * @param string $currency_code Currency code.
862
	 * @param string $input_prefix Input prefix.
863
	 */
864
	protected function shipping_method_selection_form( $country_code, $currency_code, $input_prefix ) {
865
		$selected         = 'flat_rate';
866
		$shipping_methods = $this->get_wizard_shipping_methods( $country_code, $currency_code );
867
		?>
868
		<div class="wc-wizard-shipping-method-select">
869
			<div class="wc-wizard-shipping-method-dropdown">
870
				<select
871
					id="<?php echo esc_attr( "{$input_prefix}[method]" ); ?>"
872
					name="<?php echo esc_attr( "{$input_prefix}[method]" ); ?>"
873
					class="method wc-enhanced-select"
874
					data-plugins="<?php echo wc_esc_json( wp_json_encode( $this->get_wcs_requisite_plugins() ) ); ?>"
875
				>
876 View Code Duplication
				<?php foreach ( $shipping_methods as $method_id => $method ) : ?>
877
					<option value="<?php echo esc_attr( $method_id ); ?>" <?php selected( $selected, $method_id ); ?>><?php echo esc_html( $method['name'] ); ?></option>
878
				<?php endforeach; ?>
879
				</select>
880
			</div>
881
			<div class="shipping-method-descriptions">
882 View Code Duplication
				<?php foreach ( $shipping_methods as $method_id => $method ) : ?>
883
					<p class="shipping-method-description <?php echo esc_attr( $method_id ); ?> <?php echo $method_id !== $selected ? 'hide' : ''; ?>">
884
						<?php echo esc_html( $method['description'] ); ?>
885
					</p>
886
				<?php endforeach; ?>
887
			</div>
888
		</div>
889
890
		<div class="shipping-method-settings">
891
		<?php foreach ( $shipping_methods as $method_id => $method ) : ?>
892
			<?php
893
			if ( empty( $method['settings'] ) ) {
894
				continue;
895
			}
896
			?>
897
			<div class="shipping-method-setting <?php echo esc_attr( $method_id ); ?> <?php echo $method_id !== $selected ? 'hide' : ''; ?>">
898
			<?php foreach ( $method['settings'] as $setting_id => $setting ) : ?>
899
				<?php $method_setting_id = "{$input_prefix}[{$method_id}][{$setting_id}]"; ?>
900
				<input
901
					type="<?php echo esc_attr( $setting['type'] ); ?>"
902
					placeholder="<?php echo esc_attr( $setting['default_value'] ); ?>"
903
					id="<?php echo esc_attr( $method_setting_id ); ?>"
904
					name="<?php echo esc_attr( $method_setting_id ); ?>"
905
					class="<?php echo esc_attr( $setting['required'] ? 'shipping-method-required-field' : '' ); ?>"
906
					<?php echo ( $method_id === $selected && $setting['required'] ) ? 'required' : ''; ?>
907
				/>
908
				<p class="description">
909
					<?php echo esc_html( $setting['description'] ); ?>
910
				</p>
911
			<?php endforeach; ?>
912
			</div>
913
		<?php endforeach; ?>
914
		</div>
915
		<?php
916
	}
917
918
	/**
919
	 * Render a product weight unit dropdown.
920
	 *
921
	 * @return string
922
	 */
923
	protected function get_product_weight_selection() {
924
		$weight_unit = get_option( 'woocommerce_weight_unit' );
925
		ob_start();
926
		?>
927
		<span class="wc-setup-shipping-unit">
928
			<select id="weight_unit" name="weight_unit" class="wc-enhanced-select">
929
				<option value="kg" <?php selected( $weight_unit, 'kg' ); ?>><?php esc_html_e( 'Kilograms', 'woocommerce' ); ?></option>
930
				<option value="g" <?php selected( $weight_unit, 'g' ); ?>><?php esc_html_e( 'Grams', 'woocommerce' ); ?></option>
931
				<option value="lbs" <?php selected( $weight_unit, 'lbs' ); ?>><?php esc_html_e( 'Pounds', 'woocommerce' ); ?></option>
932
				<option value="oz" <?php selected( $weight_unit, 'oz' ); ?>><?php esc_html_e( 'Ounces', 'woocommerce' ); ?></option>
933
			</select>
934
		</span>
935
		<?php
936
937
		return ob_get_clean();
938
	}
939
940
	/**
941
	 * Render a product dimension unit dropdown.
942
	 *
943
	 * @return string
944
	 */
945
	protected function get_product_dimension_selection() {
946
		$dimension_unit = get_option( 'woocommerce_dimension_unit' );
947
		ob_start();
948
		?>
949
		<span class="wc-setup-shipping-unit">
950
			<select id="dimension_unit" name="dimension_unit" class="wc-enhanced-select">
951
				<option value="m" <?php selected( $dimension_unit, 'm' ); ?>><?php esc_html_e( 'Meters', 'woocommerce' ); ?></option>
952
				<option value="cm" <?php selected( $dimension_unit, 'cm' ); ?>><?php esc_html_e( 'Centimeters', 'woocommerce' ); ?></option>
953
				<option value="mm" <?php selected( $dimension_unit, 'mm' ); ?>><?php esc_html_e( 'Millimeters', 'woocommerce' ); ?></option>
954
				<option value="in" <?php selected( $dimension_unit, 'in' ); ?>><?php esc_html_e( 'Inches', 'woocommerce' ); ?></option>
955
				<option value="yd" <?php selected( $dimension_unit, 'yd' ); ?>><?php esc_html_e( 'Yards', 'woocommerce' ); ?></option>
956
			</select>
957
		</span>
958
		<?php
959
960
		return ob_get_clean();
961
	}
962
963
	/**
964
	 * Shipping.
965
	 */
966
	public function wc_setup_shipping() {
967
		$country_code          = WC()->countries->get_base_country();
968
		$country_name          = WC()->countries->countries[ $country_code ];
969
		$prefixed_country_name = WC()->countries->estimated_for_prefix( $country_code ) . $country_name;
970
		$currency_code         = get_woocommerce_currency();
971
		$existing_zones        = WC_Shipping_Zones::get_zones();
972
		$intro_text            = '';
973
974
		if ( empty( $existing_zones ) ) {
975
			$intro_text = sprintf(
976
				/* translators: %s: country name including the 'the' prefix if needed */
977
				__( "We've created two Shipping Zones - for %s and for the rest of the world. Below you can set Flat Rate shipping costs for these Zones or offer Free Shipping.", 'woocommerce' ),
978
				$prefixed_country_name
979
			);
980
		}
981
982
		$is_wcs_labels_supported  = $this->is_wcs_shipping_labels_supported_country( $country_code );
983
		$is_shipstation_supported = $this->is_shipstation_supported_country( $country_code );
984
985
		?>
986
		<h1><?php esc_html_e( 'Shipping', 'woocommerce' ); ?></h1>
987
		<?php if ( $intro_text ) : ?>
988
			<p><?php echo wp_kses_post( $intro_text ); ?></p>
989
		<?php endif; ?>
990
		<form method="post">
991
			<?php if ( $is_wcs_labels_supported || $is_shipstation_supported ) : ?>
992
				<ul class="wc-setup-shipping-recommended">
993
				<?php
994
				if ( $is_wcs_labels_supported ) :
995
					$this->display_recommended_item(
996
						array(
997
							'type'        => 'woocommerce_services',
998
							'title'       => __( 'Did you know you can print shipping labels at home?', 'woocommerce' ),
999
							'description' => __( 'Use WooCommerce Shipping (powered by WooCommerce Services & Jetpack) to save time at the post office by printing your shipping labels at home.', 'woocommerce' ),
1000
							'img_url'     => WC()->plugin_url() . '/assets/images/obw-woocommerce-services-icon.png',
1001
							'img_alt'     => __( 'WooCommerce Services icon', 'woocommerce' ),
1002
							'plugins'     => $this->get_wcs_requisite_plugins(),
1003
						)
1004
					);
1005 View Code Duplication
				elseif ( $is_shipstation_supported ) :
1006
					$this->display_recommended_item(
1007
						array(
1008
							'type'        => 'shipstation',
1009
							'title'       => __( 'Did you know you can print shipping labels at home?', 'woocommerce' ),
1010
							'description' => __( 'We recommend using ShipStation to save time at the post office by printing your shipping labels at home. Try ShipStation free for 30 days.', 'woocommerce' ),
1011
							'img_url'     => WC()->plugin_url() . '/assets/images/obw-shipstation-icon.png',
1012
							'img_alt'     => __( 'ShipStation icon', 'woocommerce' ),
1013
							'plugins'     => array(
1014
								array(
1015
									'name' => __( 'ShipStation', 'woocommerce' ),
1016
									'slug' => 'woocommerce-shipstation-integration',
1017
								),
1018
							),
1019
						)
1020
					);
1021
				endif;
1022
				?>
1023
				</ul>
1024
			<?php endif; ?>
1025
1026
			<?php if ( empty( $existing_zones ) ) : ?>
1027
				<ul class="wc-wizard-services shipping">
1028
					<li class="wc-wizard-service-item">
1029
						<div class="wc-wizard-service-name">
1030
							<p><?php echo esc_html_e( 'Shipping Zone', 'woocommerce' ); ?></p>
1031
						</div>
1032
						<div class="wc-wizard-service-description">
1033
							<p><?php echo esc_html_e( 'Shipping Method', 'woocommerce' ); ?></p>
1034
						</div>
1035
					</li>
1036
					<li class="wc-wizard-service-item">
1037
						<div class="wc-wizard-service-name">
1038
							<p><?php echo esc_html( $country_name ); ?></p>
1039
						</div>
1040
						<div class="wc-wizard-service-description">
1041
							<?php $this->shipping_method_selection_form( $country_code, $currency_code, 'shipping_zones[domestic]' ); ?>
1042
						</div>
1043
						<div class="wc-wizard-service-enable">
1044
							<span class="wc-wizard-service-toggle">
1045
								<input id="shipping_zones[domestic][enabled]" type="checkbox" name="shipping_zones[domestic][enabled]" value="yes" checked="checked" class="wc-wizard-shipping-method-enable" data-plugins="true" />
1046
								<label for="shipping_zones[domestic][enabled]">
1047
							</span>
1048
						</div>
1049
					</li>
1050
					<li class="wc-wizard-service-item">
1051
						<div class="wc-wizard-service-name">
1052
							<p><?php echo esc_html_e( 'Locations not covered by your other zones', 'woocommerce' ); ?></p>
1053
						</div>
1054
						<div class="wc-wizard-service-description">
1055
							<?php $this->shipping_method_selection_form( $country_code, $currency_code, 'shipping_zones[intl]' ); ?>
1056
						</div>
1057
						<div class="wc-wizard-service-enable">
1058
							<span class="wc-wizard-service-toggle">
1059
								<input id="shipping_zones[intl][enabled]" type="checkbox" name="shipping_zones[intl][enabled]" value="yes" checked="checked" class="wc-wizard-shipping-method-enable" data-plugins="true" />
1060
								<label for="shipping_zones[intl][enabled]">
1061
							</span>
1062
						</div>
1063
					</li>
1064
					<li class="wc-wizard-service-info">
1065
						<p>
1066
						<?php
1067
						printf(
1068
							wp_kses(
1069
								/* translators: %1$s: live rates tooltip text, %2$s: shipping extensions URL */
1070
								__( 'If you\'d like to offer <span class="help_tip" data-tip="%1$s">live rates</span> from a specific carrier (e.g. UPS) you can find a variety of extensions available for WooCommerce <a href="%2$s" target="_blank">here</a>.', 'woocommerce' ),
1071
								array(
1072
									'span' => array(
1073
										'class'    => array(),
1074
										'data-tip' => array(),
1075
									),
1076
									'a'    => array(
1077
										'href'   => array(),
1078
										'target' => array(),
1079
									),
1080
								)
1081
							),
1082
							esc_attr__( 'A live rate is the exact cost to ship an order, quoted directly from the shipping carrier.', 'woocommerce' ),
1083
							'https://woocommerce.com/product-category/woocommerce-extensions/shipping-methods/shipping-carriers/'
1084
						);
1085
						?>
1086
						</p>
1087
					</li>
1088
				</ul>
1089
			<?php endif; ?>
1090
1091
			<div class="wc-setup-shipping-units">
1092
				<p>
1093
					<?php
1094
						echo wp_kses(
1095
							sprintf(
1096
								/* translators: %1$s: weight unit dropdown, %2$s: dimension unit dropdown */
1097
								esc_html__( 'We\'ll use %1$s for product weight and %2$s for product dimensions.', 'woocommerce' ),
1098
								$this->get_product_weight_selection(),
1099
								$this->get_product_dimension_selection()
1100
							),
1101
							array(
1102
								'span'   => array(
1103
									'class' => array(),
1104
								),
1105
								'select' => array(
1106
									'id'    => array(),
1107
									'name'  => array(),
1108
									'class' => array(),
1109
								),
1110
								'option' => array(
1111
									'value'    => array(),
1112
									'selected' => array(),
1113
								),
1114
							)
1115
						);
1116
					?>
1117
				</p>
1118
			</div>
1119
1120
			<p class="wc-setup-actions step">
1121
				<?php $this->plugin_install_info(); ?>
1122
				<button class="button-primary button button-large button-next" value="<?php esc_attr_e( 'Continue', 'woocommerce' ); ?>" name="save_step"><?php esc_html_e( 'Continue', 'woocommerce' ); ?></button>
1123
				<?php wp_nonce_field( 'wc-setup' ); ?>
1124
			</p>
1125
		</form>
1126
		<?php
1127
	}
1128
1129
	/**
1130
	 * Save shipping options.
1131
	 */
1132
	public function wc_setup_shipping_save() {
1133
		check_admin_referer( 'wc-setup' );
1134
1135
		// @codingStandardsIgnoreStart
1136
		$setup_domestic   = isset( $_POST['shipping_zones']['domestic']['enabled'] ) && ( 'yes' === $_POST['shipping_zones']['domestic']['enabled'] );
1137
		$domestic_method  = isset( $_POST['shipping_zones']['domestic']['method'] ) ? sanitize_text_field( wp_unslash( $_POST['shipping_zones']['domestic']['method'] ) ) : '';
1138
		$setup_intl       = isset( $_POST['shipping_zones']['intl']['enabled'] ) && ( 'yes' === $_POST['shipping_zones']['intl']['enabled'] );
1139
		$intl_method      = isset( $_POST['shipping_zones']['intl']['method'] ) ? sanitize_text_field( wp_unslash( $_POST['shipping_zones']['intl']['method'] ) ) : '';
1140
		$weight_unit      = sanitize_text_field( wp_unslash( $_POST['weight_unit'] ) );
1141
		$dimension_unit   = sanitize_text_field( wp_unslash( $_POST['dimension_unit'] ) );
1142
		$existing_zones   = WC_Shipping_Zones::get_zones();
1143
		// @codingStandardsIgnoreEnd
1144
1145
		update_option( 'woocommerce_ship_to_countries', '' );
1146
		update_option( 'woocommerce_weight_unit', $weight_unit );
1147
		update_option( 'woocommerce_dimension_unit', $dimension_unit );
1148
1149
		$setup_wcs_labels  = isset( $_POST['setup_woocommerce_services'] ) && 'yes' === $_POST['setup_woocommerce_services'];
1150
		$setup_shipstation = isset( $_POST['setup_shipstation'] ) && 'yes' === $_POST['setup_shipstation'];
1151
1152
		update_option( 'woocommerce_setup_shipping_labels', $setup_wcs_labels );
1153
1154
		if ( $setup_wcs_labels ) {
1155
			$this->install_woocommerce_services();
1156
		}
1157
1158
		if ( $setup_shipstation ) {
1159
			$this->install_plugin(
1160
				'woocommerce-shipstation-integration',
1161
				array(
1162
					'name'      => __( 'ShipStation', 'woocommerce' ),
1163
					'repo-slug' => 'woocommerce-shipstation-integration',
1164
					'file'      => 'woocommerce-shipstation.php',
1165
				)
1166
			);
1167
		}
1168
1169
		// For now, limit this setup to the first run.
1170
		if ( ! empty( $existing_zones ) ) {
1171
			wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
1172
			exit;
1173
		}
1174
1175
		/*
1176
		 * If enabled, create a shipping zone containing the country the
1177
		 * store is located in, with the selected method preconfigured.
1178
		 */
1179
		if ( $setup_domestic ) {
1180
			$zone = new WC_Shipping_Zone( null );
1181
			$zone->set_zone_order( 0 );
1182
			$zone->add_location( WC()->countries->get_base_country(), 'country' );
1183
			$zone_id = $zone->save();
1184
1185
			// Save chosen shipping method settings (using REST controller for convenience).
1186 View Code Duplication
			if ( ! empty( $_POST['shipping_zones']['domestic'][ $domestic_method ] ) ) { // WPCS: input var ok.
1187
				$request = new WP_REST_Request( 'POST', "/wc/v3/shipping/zones/{$zone_id}/methods" );
1188
				$request->add_header( 'Content-Type', 'application/json' );
1189
				$request->set_body(
1190
					wp_json_encode(
1191
						array(
1192
							'method_id' => $domestic_method,
1193
							'settings'  => wc_clean( wp_unslash( $_POST['shipping_zones']['domestic'][ $domestic_method ] ) ),
1194
						)
1195
					)
1196
				);
1197
				rest_do_request( $request );
1198
			}
1199
		}
1200
1201
		// If enabled, set the selected method for the "rest of world" zone.
1202 View Code Duplication
		if ( $setup_intl ) {
1203
			// Save chosen shipping method settings (using REST controller for convenience).
1204
			if ( ! empty( $_POST['shipping_zones']['intl'][ $intl_method ] ) ) { // WPCS: input var ok.
1205
				$request = new WP_REST_Request( 'POST', '/wc/v3/shipping/zones/0/methods' );
1206
				$request->add_header( 'Content-Type', 'application/json' );
1207
				$request->set_body(
1208
					wp_json_encode(
1209
						array(
1210
							'method_id' => $intl_method,
1211
							'settings'  => wc_clean( wp_unslash( $_POST['shipping_zones']['intl'][ $intl_method ] ) ),
1212
						)
1213
					)
1214
				);
1215
				rest_do_request( $request );
1216
			}
1217
		}
1218
1219
		// Notify the user that no shipping methods are configured.
1220
		if ( ! $setup_domestic && ! $setup_intl ) {
1221
			WC_Admin_Notices::add_notice( 'no_shipping_methods' );
1222
		}
1223
1224
		wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
1225
		exit;
1226
	}
1227
1228
	/**
1229
	 * Is Stripe country supported
1230
	 * https://stripe.com/global .
1231
	 *
1232
	 * @param string $country_code Country code.
1233
	 */
1234 1
	protected function is_stripe_supported_country( $country_code ) {
1235
		$stripe_supported_countries = array(
1236 1
			'AU',
1237
			'AT',
1238
			'BE',
1239
			'CA',
1240
			'DK',
1241
			'FI',
1242
			'FR',
1243
			'DE',
1244
			'HK',
1245
			'IE',
1246
			'JP',
1247
			'LU',
1248
			'NL',
1249
			'NZ',
1250
			'NO',
1251
			'SG',
1252
			'ES',
1253
			'SE',
1254
			'CH',
1255
			'GB',
1256
			'US',
1257
		);
1258
1259 1
		return in_array( $country_code, $stripe_supported_countries, true );
1260
	}
1261
1262
	/**
1263
	 * Is PayPal currency supported.
1264
	 *
1265
	 * @param string $currency Currency code.
1266
	 * @return boolean
1267
	 */
1268 1
	protected function is_paypal_supported_currency( $currency ) {
1269
		$supported_currencies = array(
1270 1
			'AUD',
1271
			'BRL',
1272
			'CAD',
1273
			'MXN',
1274
			'NZD',
1275
			'HKD',
1276
			'SGD',
1277
			'USD',
1278
			'EUR',
1279
			'JPY',
1280
			'TRY',
1281
			'NOK',
1282
			'CZK',
1283
			'DKK',
1284
			'HUF',
1285
			'ILS',
1286
			'MYR',
1287
			'PHP',
1288
			'PLN',
1289
			'SEK',
1290
			'CHF',
1291
			'TWD',
1292
			'THB',
1293
			'GBP',
1294
			'RMB',
1295
			'RUB',
1296
			'INR',
1297
		);
1298 1
		return in_array( $currency, $supported_currencies, true );
1299
	}
1300
1301
	/**
1302
	 * Is Klarna Checkout country supported.
1303
	 *
1304
	 * @param string $country_code Country code.
1305
	 */
1306 1
	protected function is_klarna_checkout_supported_country( $country_code ) {
1307
		$supported_countries = array(
1308 1
			'SE', // Sweden.
1309
			'FI', // Finland.
1310
			'NO', // Norway.
1311
			'NL', // Netherlands.
1312
		);
1313 1
		return in_array( $country_code, $supported_countries, true );
1314
	}
1315
1316
	/**
1317
	 * Is Klarna Payments country supported.
1318
	 *
1319
	 * @param string $country_code Country code.
1320
	 */
1321 1
	protected function is_klarna_payments_supported_country( $country_code ) {
1322
		$supported_countries = array(
1323 1
			'DK', // Denmark.
1324
			'DE', // Germany.
1325
			'AT', // Austria.
1326
		);
1327 1
		return in_array( $country_code, $supported_countries, true );
1328
	}
1329
1330
	/**
1331
	 * Is Square country supported
1332
	 *
1333
	 * @param string $country_code Country code.
1334
	 */
1335 1
	protected function is_square_supported_country( $country_code ) {
1336
		$square_supported_countries = array(
1337 1
			'US',
1338
			'CA',
1339
			'JP',
1340
			'GB',
1341
			'AU',
1342
		);
1343 1
		return in_array( $country_code, $square_supported_countries, true );
1344
	}
1345
1346
	/**
1347
	 * Is eWAY Payments country supported
1348
	 *
1349
	 * @param string $country_code Country code.
1350
	 */
1351 1
	protected function is_eway_payments_supported_country( $country_code ) {
1352
		$supported_countries = array(
1353 1
			'AU', // Australia.
1354
			'NZ', // New Zealand.
1355
		);
1356 1
		return in_array( $country_code, $supported_countries, true );
1357
	}
1358
1359
	/**
1360
	 * Is ShipStation country supported
1361
	 *
1362
	 * @param string $country_code Country code.
1363
	 */
1364
	protected function is_shipstation_supported_country( $country_code ) {
1365
		$supported_countries = array(
1366
			'AU', // Australia.
1367
			'CA', // Canada.
1368
			'GB', // United Kingdom.
1369
		);
1370
		return in_array( $country_code, $supported_countries, true );
1371
	}
1372
1373
	/**
1374
	 * Is WooCommerce Services shipping label country supported
1375
	 *
1376
	 * @param string $country_code Country code.
1377
	 */
1378
	protected function is_wcs_shipping_labels_supported_country( $country_code ) {
1379
		$supported_countries = array(
1380
			'US', // United States.
1381
		);
1382
		return in_array( $country_code, $supported_countries, true );
1383
	}
1384
1385
	/**
1386
	 * Helper method to retrieve the current user's email address.
1387
	 *
1388
	 * @return string Email address
1389
	 */
1390 1
	protected function get_current_user_email() {
1391 1
		$current_user = wp_get_current_user();
1392 1
		$user_email   = $current_user->user_email;
1393
1394 1
		return $user_email;
1395
	}
1396
1397
	/**
1398
	 * Array of all possible "in cart" gateways that can be offered.
1399
	 *
1400
	 * @return array
1401
	 */
1402 1
	protected function get_wizard_available_in_cart_payment_gateways() {
1403 1
		$user_email = $this->get_current_user_email();
1404
1405 1
		$stripe_description = '<p>' . sprintf(
1406
			/* translators: %s: URL */
1407 1
			__( 'Accept debit and credit cards in 135+ currencies, methods such as Alipay, and one-touch checkout with Apple Pay. <a href="%s" target="_blank">Learn more</a>.', 'woocommerce' ),
1408 1
			'https://woocommerce.com/products/stripe/'
1409 1
		) . '</p>';
1410 1
		$paypal_checkout_description = '<p>' . sprintf(
1411
			/* translators: %s: URL */
1412 1
			__( 'Safe and secure payments using credit cards or your customer\'s PayPal account. <a href="%s" target="_blank">Learn more</a>.', 'woocommerce' ),
1413 1
			'https://woocommerce.com/products/woocommerce-gateway-paypal-checkout/'
1414 1
		) . '</p>';
1415 1
		$klarna_checkout_description = '<p>' . sprintf(
1416
			/* translators: %s: URL */
1417 1
			__( 'Full checkout experience with pay now, pay later and slice it. No credit card numbers, no passwords, no worries. <a href="%s" target="_blank">Learn more about Klarna</a>.', 'woocommerce' ),
1418 1
			'https://woocommerce.com/products/klarna-checkout/'
1419 1
		) . '</p>';
1420 1
		$klarna_payments_description = '<p>' . sprintf(
1421
			/* translators: %s: URL */
1422 1
			__( 'Choose the payment that you want, pay now, pay later or slice it. No credit card numbers, no passwords, no worries. <a href="%s" target="_blank">Learn more about Klarna</a>.', 'woocommerce' ),
1423 1
			'https://woocommerce.com/products/klarna-payments/ '
1424 1
		) . '</p>';
1425 1
		$square_description = '<p>' . sprintf(
1426
			/* translators: %s: URL */
1427 1
			__( 'Securely accept credit and debit cards with one low rate, no surprise fees (custom rates available). Sell online and in store and track sales and inventory in one place. <a href="%s" target="_blank">Learn more about Square</a>.', 'woocommerce' ),
1428 1
			'https://woocommerce.com/products/square/'
1429 1
		) . '</p>';
1430
1431
		return array(
1432
			'stripe'          => array(
1433 1
				'name'        => __( 'WooCommerce Stripe Gateway', 'woocommerce' ),
1434 1
				'image'       => WC()->plugin_url() . '/assets/images/stripe.png',
1435 1
				'description' => $stripe_description,
1436 1
				'class'       => 'checked stripe-logo',
1437 1
				'repo-slug'   => 'woocommerce-gateway-stripe',
1438
				'settings'    => array(
1439
					'create_account' => array(
1440 1
						'label'       => __( 'Set up Stripe for me using this email:', 'woocommerce' ),
1441 1
						'type'        => 'checkbox',
1442 1
						'value'       => 'yes',
1443 1
						'default'     => 'yes',
1444 1
						'placeholder' => '',
1445
						'required'    => false,
1446 1
						'plugins'     => $this->get_wcs_requisite_plugins(),
1447
					),
1448
					'email'          => array(
1449 1
						'label'       => __( 'Stripe email address:', 'woocommerce' ),
1450 1
						'type'        => 'email',
1451 1
						'value'       => $user_email,
1452 1
						'placeholder' => __( 'Stripe email address', 'woocommerce' ),
1453
						'required'    => true,
1454
					),
1455
				),
1456
			),
1457
			'ppec_paypal'     => array(
1458 1
				'name'        => __( 'WooCommerce PayPal Checkout Gateway', 'woocommerce' ),
1459 1
				'image'       => WC()->plugin_url() . '/assets/images/paypal.png',
1460 1
				'description' => $paypal_checkout_description,
1461
				'enabled'     => false,
1462 1
				'class'       => 'checked paypal-logo',
1463 1
				'repo-slug'   => 'woocommerce-gateway-paypal-express-checkout',
1464
				'settings'    => array(
1465
					'reroute_requests' => array(
1466 1
						'label'       => __( 'Set up PayPal for me using this email:', 'woocommerce' ),
1467 1
						'type'        => 'checkbox',
1468 1
						'value'       => 'yes',
1469 1
						'default'     => 'yes',
1470 1
						'placeholder' => '',
1471
						'required'    => false,
1472 1
						'plugins'     => $this->get_wcs_requisite_plugins(),
1473
					),
1474
					'email'            => array(
1475 1
						'label'       => __( 'Direct payments to email address:', 'woocommerce' ),
1476 1
						'type'        => 'email',
1477 1
						'value'       => $user_email,
1478 1
						'placeholder' => __( 'Email address to receive payments', 'woocommerce' ),
1479
						'required'    => true,
1480
					),
1481
				),
1482
			),
1483
			'paypal'          => array(
1484 1
				'name'        => __( 'PayPal Standard', 'woocommerce' ),
1485 1
				'description' => __( 'Accept payments via PayPal using account balance or credit card.', 'woocommerce' ),
1486 1
				'image'       => '',
1487
				'settings'    => array(
1488
					'email' => array(
1489 1
						'label'       => __( 'PayPal email address:', 'woocommerce' ),
1490 1
						'type'        => 'email',
1491 1
						'value'       => $user_email,
1492 1
						'placeholder' => __( 'PayPal email address', 'woocommerce' ),
1493
						'required'    => true,
1494
					),
1495
				),
1496
			),
1497
			'klarna_checkout' => array(
1498 1
				'name'        => __( 'Klarna Checkout for WooCommerce', 'woocommerce' ),
1499 1
				'description' => $klarna_checkout_description,
1500 1
				'image'       => WC()->plugin_url() . '/assets/images/klarna-black.png',
1501
				'enabled'     => true,
1502 1
				'class'       => 'klarna-logo',
1503 1
				'repo-slug'   => 'klarna-checkout-for-woocommerce',
1504
			),
1505
			'klarna_payments' => array(
1506 1
				'name'        => __( 'Klarna Payments for WooCommerce', 'woocommerce' ),
1507 1
				'description' => $klarna_payments_description,
1508 1
				'image'       => WC()->plugin_url() . '/assets/images/klarna-black.png',
1509
				'enabled'     => true,
1510 1
				'class'       => 'klarna-logo',
1511 1
				'repo-slug'   => 'klarna-payments-for-woocommerce',
1512
			),
1513
			'square'          => array(
1514 1
				'name'        => __( 'WooCommerce Square', 'woocommerce' ),
1515 1
				'description' => $square_description,
1516 1
				'image'       => WC()->plugin_url() . '/assets/images/square-black.png',
1517 1
				'class'       => 'square-logo',
1518
				'enabled'     => false,
1519 1
				'repo-slug'   => 'woocommerce-square',
1520
			),
1521
			'eway'            => array(
1522 1
				'name'        => __( 'WooCommerce eWAY Gateway', 'woocommerce' ),
1523 1
				'description' => __( 'The eWAY extension for WooCommerce allows you to take credit card payments directly on your store without redirecting your customers to a third party site to make payment.', 'woocommerce' ),
1524 1
				'image'       => WC()->plugin_url() . '/assets/images/eway-logo.jpg',
1525
				'enabled'     => false,
1526 1
				'class'       => 'eway-logo',
1527 1
				'repo-slug'   => 'woocommerce-gateway-eway',
1528
			),
1529
			'payfast'         => array(
1530 1
				'name'        => __( 'WooCommerce PayFast Gateway', 'woocommerce' ),
1531 1
				'description' => __( 'The PayFast extension for WooCommerce enables you to accept payments by Credit Card and EFT via one of South Africa’s most popular payment gateways. No setup fees or monthly subscription costs.', 'woocommerce' ),
1532 1
				'image'       => WC()->plugin_url() . '/assets/images/payfast.png',
1533 1
				'class'       => 'payfast-logo',
1534
				'enabled'     => false,
1535 1
				'repo-slug'   => 'woocommerce-payfast-gateway',
1536 1
				'file'        => 'gateway-payfast.php',
1537
			),
1538
		);
1539
	}
1540
1541
	/**
1542
	 * Simple array of "in cart" gateways to show in wizard.
1543
	 *
1544
	 * @return array
1545
	 */
1546 1
	public function get_wizard_in_cart_payment_gateways() {
1547 1
		$gateways = $this->get_wizard_available_in_cart_payment_gateways();
1548 1
		$country  = WC()->countries->get_base_country();
1549 1
		$currency = get_woocommerce_currency();
1550
1551 1
		$can_stripe  = $this->is_stripe_supported_country( $country );
1552 1
		$can_eway    = $this->is_eway_payments_supported_country( $country );
1553 1
		$can_payfast = ( 'ZA' === $country ); // South Africa.
1554 1
		$can_paypal  = $this->is_paypal_supported_currency( $currency );
1555
1556 1
		if ( ! current_user_can( 'install_plugins' ) ) {
1557 1
			return $can_paypal ? array( 'paypal' => $gateways['paypal'] ) : array();
1558
		}
1559
1560 1
		$klarna_or_square = false;
1561
1562 1
		if ( $this->is_klarna_checkout_supported_country( $country ) ) {
1563 1
			$klarna_or_square = 'klarna_checkout';
1564 1
		} elseif ( $this->is_klarna_payments_supported_country( $country ) ) {
1565 1
			$klarna_or_square = 'klarna_payments';
1566 1
		} elseif ( $this->is_square_supported_country( $country ) && get_option( 'woocommerce_sell_in_person' ) ) {
1567 1
			$klarna_or_square = 'square';
1568
		}
1569
1570 1
		$offered_gateways = array();
1571
1572 1
		if ( $can_stripe ) {
1573 1
			$gateways['stripe']['enabled']  = true;
1574 1
			$gateways['stripe']['featured'] = true;
1575 1
			$offered_gateways              += array( 'stripe' => $gateways['stripe'] );
1576 1
		} elseif ( $can_paypal ) {
1577 1
			$gateways['ppec_paypal']['enabled'] = true;
1578
		}
1579
1580 1
		if ( $klarna_or_square ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $klarna_or_square of type string|false is loosely compared to true; 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...
1581 1
			if ( in_array( $klarna_or_square, array( 'klarna_checkout', 'klarna_payments' ), true ) ) {
1582 1
				$gateways[ $klarna_or_square ]['enabled']  = true;
1583 1
				$gateways[ $klarna_or_square ]['featured'] = false;
1584
				$offered_gateways                          += array(
1585 1
					$klarna_or_square => $gateways[ $klarna_or_square ],
1586
				);
1587
			} else {
1588
				$offered_gateways += array(
1589 1
					$klarna_or_square => $gateways[ $klarna_or_square ],
1590
				);
1591
			}
1592
		}
1593
1594 1
		if ( $can_paypal ) {
1595 1
			$offered_gateways += array( 'ppec_paypal' => $gateways['ppec_paypal'] );
1596
		}
1597
1598 1
		if ( $can_eway ) {
1599
			$offered_gateways += array( 'eway' => $gateways['eway'] );
1600
		}
1601
1602 1
		if ( $can_payfast ) {
1603
			$offered_gateways += array( 'payfast' => $gateways['payfast'] );
1604
		}
1605
1606 1
		return $offered_gateways;
1607
	}
1608
1609
	/**
1610
	 * Simple array of "manual" gateways to show in wizard.
1611
	 *
1612
	 * @return array
1613
	 */
1614
	public function get_wizard_manual_payment_gateways() {
1615
		$gateways = array(
1616
			'cheque' => array(
1617
				'name'        => _x( 'Check payments', 'Check payment method', 'woocommerce' ),
1618
				'description' => __( 'A simple offline gateway that lets you accept a check as method of payment.', 'woocommerce' ),
1619
				'image'       => '',
1620
				'class'       => '',
1621
			),
1622
			'bacs'   => array(
1623
				'name'        => __( 'Bank transfer (BACS) payments', 'woocommerce' ),
1624
				'description' => __( 'A simple offline gateway that lets you accept BACS payment.', 'woocommerce' ),
1625
				'image'       => '',
1626
				'class'       => '',
1627
			),
1628
			'cod'    => array(
1629
				'name'        => __( 'Cash on delivery', 'woocommerce' ),
1630
				'description' => __( 'A simple offline gateway that lets you accept cash on delivery.', 'woocommerce' ),
1631
				'image'       => '',
1632
				'class'       => '',
1633
			),
1634
		);
1635
1636
		return $gateways;
1637
	}
1638
1639
	/**
1640
	 * Display service item in list.
1641
	 *
1642
	 * @param int   $item_id Item ID.
1643
	 * @param array $item_info Item info array.
1644
	 */
1645
	public function display_service_item( $item_id, $item_info ) {
1646
		$item_class = 'wc-wizard-service-item';
1647
		if ( isset( $item_info['class'] ) ) {
1648
			$item_class .= ' ' . $item_info['class'];
1649
		}
1650
1651
		$previously_saved_settings = get_option( 'woocommerce_' . $item_id . '_settings' );
1652
1653
		// Show the user-saved state if it was previously saved.
1654
		// Otherwise, rely on the item info.
1655
		if ( is_array( $previously_saved_settings ) ) {
1656
			$should_enable_toggle = ( isset( $previously_saved_settings['enabled'] ) && 'yes' === $previously_saved_settings['enabled'] ) ? true : ( isset( $item_info['enabled'] ) && $item_info['enabled'] );
1657
		} else {
1658
			$should_enable_toggle = isset( $item_info['enabled'] ) && $item_info['enabled'];
1659
		}
1660
1661
		$plugins = null;
1662
		if ( isset( $item_info['repo-slug'] ) ) {
1663
			$plugin  = array(
1664
				'slug' => $item_info['repo-slug'],
1665
				'name' => $item_info['name'],
1666
			);
1667
			$plugins = array( $plugin );
1668
		}
1669
1670
		?>
1671
		<li class="<?php echo esc_attr( $item_class ); ?>">
1672
			<div class="wc-wizard-service-name">
1673 View Code Duplication
				<?php if ( ! empty( $item_info['image'] ) ) : ?>
1674
					<img src="<?php echo esc_attr( $item_info['image'] ); ?>" alt="<?php echo esc_attr( $item_info['name'] ); ?>" />
1675
				<?php else : ?>
1676
					<p><?php echo esc_html( $item_info['name'] ); ?></p>
1677
				<?php endif; ?>
1678
			</div>
1679
			<div class="wc-wizard-service-enable">
1680
				<span class="wc-wizard-service-toggle <?php echo esc_attr( $should_enable_toggle ? '' : 'disabled' ); ?>" tabindex="0">
1681
					<input
1682
						id="wc-wizard-service-<?php echo esc_attr( $item_id ); ?>"
1683
						type="checkbox"
1684
						name="wc-wizard-service-<?php echo esc_attr( $item_id ); ?>-enabled"
1685
						value="yes" <?php checked( $should_enable_toggle ); ?>
1686
						data-plugins="<?php echo wc_esc_json( wp_json_encode( $plugins ) ); ?>"
1687
					/>
1688
					<label for="wc-wizard-service-<?php echo esc_attr( $item_id ); ?>">
1689
				</span>
1690
			</div>
1691
			<div class="wc-wizard-service-description">
1692
				<?php echo wp_kses_post( wpautop( $item_info['description'] ) ); ?>
1693
				<?php if ( ! empty( $item_info['settings'] ) ) : ?>
1694
					<div class="wc-wizard-service-settings <?php echo $should_enable_toggle ? '' : 'hide'; ?>">
1695
						<?php foreach ( $item_info['settings'] as $setting_id => $setting ) : ?>
1696
							<?php
1697
							$is_checkbox = 'checkbox' === $setting['type'];
1698
1699
							if ( $is_checkbox ) {
1700
								$checked = false;
1701
								if ( isset( $previously_saved_settings[ $setting_id ] ) ) {
1702
									$checked = 'yes' === $previously_saved_settings[ $setting_id ];
1703
								} elseif ( false === $previously_saved_settings && isset( $setting['default'] ) ) {
1704
									$checked = 'yes' === $setting['default'];
1705
								}
1706
							}
1707
							if ( 'email' === $setting['type'] ) {
1708
								$value = empty( $previously_saved_settings[ $setting_id ] )
1709
									? $setting['value']
1710
									: $previously_saved_settings[ $setting_id ];
1711
							}
1712
							?>
1713
							<?php $input_id = $item_id . '_' . $setting_id; ?>
1714
							<div class="<?php echo esc_attr( 'wc-wizard-service-setting-' . $input_id ); ?>">
1715
								<label
1716
									for="<?php echo esc_attr( $input_id ); ?>"
1717
									class="<?php echo esc_attr( $input_id ); ?>"
1718
								>
1719
									<?php echo esc_html( $setting['label'] ); ?>
1720
								</label>
1721
								<input
1722
									type="<?php echo esc_attr( $setting['type'] ); ?>"
1723
									id="<?php echo esc_attr( $input_id ); ?>"
1724
									class="<?php echo esc_attr( 'payment-' . $setting['type'] . '-input' ); ?>"
1725
									name="<?php echo esc_attr( $input_id ); ?>"
1726
									value="<?php echo esc_attr( isset( $value ) ? $value : $setting['value'] ); ?>"
1727
									placeholder="<?php echo esc_attr( $setting['placeholder'] ); ?>"
1728
									<?php echo ( $setting['required'] ) ? 'required' : ''; ?>
1729
									<?php echo $is_checkbox ? checked( isset( $checked ) && $checked, true, false ) : ''; ?>
1730
									data-plugins="<?php echo wc_esc_json( wp_json_encode( isset( $setting['plugins'] ) ? $setting['plugins'] : null ) ); ?>"
1731
								/>
1732
								<?php if ( ! empty( $setting['description'] ) ) : ?>
1733
									<span class="wc-wizard-service-settings-description"><?php echo esc_html( $setting['description'] ); ?></span>
1734
								<?php endif; ?>
1735
							</div>
1736
						<?php endforeach; ?>
1737
					</div>
1738
				<?php endif; ?>
1739
			</div>
1740
		</li>
1741
		<?php
1742
	}
1743
1744
	/**
1745
	 * Is it a featured service?
1746
	 *
1747
	 * @param array $service Service info array.
1748
	 * @return boolean
1749
	 */
1750
	public function is_featured_service( $service ) {
1751
		return ! empty( $service['featured'] );
1752
	}
1753
1754
	/**
1755
	 * Is this a non featured service?
1756
	 *
1757
	 * @param array $service Service info array.
1758
	 * @return boolean
1759
	 */
1760
	public function is_not_featured_service( $service ) {
1761
		return ! $this->is_featured_service( $service );
1762
	}
1763
1764
	/**
1765
	 * Payment Step.
1766
	 */
1767
	public function wc_setup_payment() {
1768
		$featured_gateways = array_filter( $this->get_wizard_in_cart_payment_gateways(), array( $this, 'is_featured_service' ) );
1769
		$in_cart_gateways  = array_filter( $this->get_wizard_in_cart_payment_gateways(), array( $this, 'is_not_featured_service' ) );
1770
		$manual_gateways   = $this->get_wizard_manual_payment_gateways();
1771
		?>
1772
		<h1><?php esc_html_e( 'Payment', 'woocommerce' ); ?></h1>
1773
		<form method="post" class="wc-wizard-payment-gateway-form">
1774
			<p>
1775
				<?php
1776
				printf(
1777
					wp_kses(
1778
						/* translators: %s: Link */
1779
						__( 'WooCommerce can accept both online and offline payments. <a href="%s" target="_blank">Additional payment methods</a> can be installed later.', 'woocommerce' ),
1780
						array(
1781
							'a' => array(
1782
								'href'   => array(),
1783
								'target' => array(),
1784
							),
1785
						)
1786
					),
1787
					esc_url( admin_url( 'admin.php?page=wc-addons&section=payment-gateways' ) )
1788
				);
1789
				?>
1790
			</p>
1791
			<?php if ( $featured_gateways ) : ?>
0 ignored issues
show
Bug Best Practice introduced by
The expression $featured_gateways of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1792
			<ul class="wc-wizard-services featured">
1793
				<?php
1794
				foreach ( $featured_gateways as $gateway_id => $gateway ) {
1795
					$this->display_service_item( $gateway_id, $gateway );
1796
				}
1797
				?>
1798
			</ul>
1799
			<?php endif; ?>
1800
			<?php if ( $in_cart_gateways ) : ?>
0 ignored issues
show
Bug Best Practice introduced by
The expression $in_cart_gateways of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1801
			<ul class="wc-wizard-services in-cart">
1802
				<?php
1803
				foreach ( $in_cart_gateways as $gateway_id => $gateway ) {
1804
					$this->display_service_item( $gateway_id, $gateway );
1805
				}
1806
				?>
1807
			</ul>
1808
			<?php endif; ?>
1809
			<ul class="wc-wizard-services manual">
1810
				<li class="wc-wizard-services-list-toggle closed">
1811
					<div class="wc-wizard-service-name">
1812
						<?php esc_html_e( 'Offline Payments', 'woocommerce' ); ?>
1813
					</div>
1814
					<div class="wc-wizard-service-description">
1815
						<?php esc_html_e( 'Collect payments from customers offline.', 'woocommerce' ); ?>
1816
					</div>
1817
					<div class="wc-wizard-service-enable" tabindex="0">
1818
						<input class="wc-wizard-service-list-toggle" id="wc-wizard-service-list-toggle" type="checkbox">
1819
						<label for="wc-wizard-service-list-toggle"></label>
1820
					</div>
1821
				</li>
1822
				<?php
1823
				foreach ( $manual_gateways as $gateway_id => $gateway ) {
1824
					$this->display_service_item( $gateway_id, $gateway );
1825
				}
1826
				?>
1827
			</ul>
1828
			<p class="wc-setup-actions step">
1829
				<?php $this->plugin_install_info(); ?>
1830
				<button type="submit" class="button-primary button button-large button-next" value="<?php esc_attr_e( 'Continue', 'woocommerce' ); ?>" name="save_step"><?php esc_html_e( 'Continue', 'woocommerce' ); ?></button>
1831
				<?php wp_nonce_field( 'wc-setup' ); ?>
1832
			</p>
1833
		</form>
1834
		<?php
1835
	}
1836
1837
	/**
1838
	 * Payment Step save.
1839
	 */
1840
	public function wc_setup_payment_save() {
1841
		check_admin_referer( 'wc-setup' );
1842
1843
		if (
1844
			(
1845
				// Install WooCommerce Services with Stripe to enable deferred account creation.
1846
				! empty( $_POST['wc-wizard-service-stripe-enabled'] ) && // WPCS: CSRF ok, input var ok.
1847
				! empty( $_POST['stripe_create_account'] ) // WPCS: CSRF ok, input var ok.
1848
			) || (
1849
				// Install WooCommerce Services with PayPal EC to enable proxied payments.
1850
				! empty( $_POST['wc-wizard-service-ppec_paypal-enabled'] ) && // WPCS: CSRF ok, input var ok.
1851
				! empty( $_POST['ppec_paypal_reroute_requests'] ) // WPCS: CSRF ok, input var ok.
1852
			)
1853
		) {
1854
			$this->install_woocommerce_services();
1855
		}
1856
1857
		$gateways = array_merge( $this->get_wizard_in_cart_payment_gateways(), $this->get_wizard_manual_payment_gateways() );
1858
1859
		foreach ( $gateways as $gateway_id => $gateway ) {
1860
			// If repo-slug is defined, download and install plugin from .org.
1861
			if ( ! empty( $gateway['repo-slug'] ) && ! empty( $_POST[ 'wc-wizard-service-' . $gateway_id . '-enabled' ] ) ) { // WPCS: CSRF ok, input var ok.
1862
				$this->install_plugin( $gateway_id, $gateway );
1863
			}
1864
1865
			$settings = array( 'enabled' => ! empty( $_POST[ 'wc-wizard-service-' . $gateway_id . '-enabled' ] ) ? 'yes' : 'no' );  // WPCS: CSRF ok, input var ok.
1866
1867
			// @codingStandardsIgnoreStart
1868
			if ( ! empty( $gateway['settings'] ) ) {
1869
				foreach ( $gateway['settings'] as $setting_id => $setting ) {
1870
					$settings[ $setting_id ] = 'yes' === $settings['enabled'] && isset( $_POST[ $gateway_id . '_' . $setting_id ] )
1871
						? wc_clean( wp_unslash( $_POST[ $gateway_id . '_' . $setting_id ] ) )
1872
						: false;
1873
				}
1874
			}
1875
			// @codingStandardsIgnoreSEnd
1876
1877
			if ( 'ppec_paypal' === $gateway_id && empty( $settings['reroute_requests'] ) ) {
1878
				unset( $settings['enabled'] );
1879
			}
1880
1881
			$settings_key = 'woocommerce_' . $gateway_id . '_settings';
1882
			$previously_saved_settings = array_filter( (array) get_option( $settings_key, array() ) );
1883
			update_option( $settings_key, array_merge( $previously_saved_settings, $settings ) );
1884
		}
1885
1886
		wp_redirect( esc_url_raw( $this->get_next_step_link() ) );
1887
		exit;
1888
	}
1889
1890
	protected function display_recommended_item( $item_info ) {
1891
		$type        = $item_info['type'];
1892
		$title       = $item_info['title'];
1893
		$description = $item_info['description'];
1894
		$img_url     = $item_info['img_url'];
1895
		$img_alt     = $item_info['img_alt'];
1896
		?>
1897
		<li class="recommended-item checkbox">
1898
			<input
1899
				id="<?php echo esc_attr( 'wc_recommended_' . $type ); ?>"
1900
				type="checkbox"
1901
				name="<?php echo esc_attr( 'setup_' . $type ); ?>"
1902
				value="yes"
1903
				checked
1904
				data-plugins="<?php echo wc_esc_json( wp_json_encode( isset( $item_info['plugins'] ) ? $item_info['plugins'] : null ) ); ?>"
1905
			/>
1906
			<label for="<?php echo esc_attr( 'wc_recommended_' . $type ); ?>">
1907
				<img
1908
					src="<?php echo esc_url( $img_url ); ?>"
1909
					class="<?php echo esc_attr( 'recommended-item-icon-' . $type ); ?> recommended-item-icon"
1910
					alt="<?php echo esc_attr( $img_alt ); ?>" />
1911
				<div class="recommended-item-description-container">
1912
					<h3><?php echo esc_html( $title ); ?></h3>
1913
					<p><?php echo wp_kses( $description, array(
1914
						'a' => array(
1915
							'href'   => array(),
1916
							'target' => array(),
1917
							'rel'    => array(),
1918
						),
1919
						'em' => array(),
1920
					) ); ?></p>
1921
				</div>
1922
			</label>
1923
		</li>
1924
		<?php
1925
	}
1926
1927
	/**
1928
	 * Recommended step
1929
	 */
1930
	public function wc_setup_recommended() {
1931
		?>
1932
		<h1><?php esc_html_e( 'Recommended for All WooCommerce Stores', 'woocommerce' ); ?></h1>
1933
		<p>
1934
			<?php esc_html_e( 'Enhance your store with these recommended free features.', 'woocommerce' ); ?>
1935
		</p>
1936
		<form method="post">
1937
			<ul class="recommended-step">
1938
				<?php
1939
				if ( $this->should_show_theme() ) :
1940
					$theme      = wp_get_theme();
1941
					$theme_name = $theme['Name'];
1942
					$this->display_recommended_item( array(
1943
						'type'        => 'storefront_theme',
1944
						'title'       => __( 'Storefront Theme', 'woocommerce' ),
1945
						'description' => sprintf( __(
1946
								'Design your store with deep WooCommerce integration. If toggled on, we’ll install <a href="https://woocommerce.com/storefront/" target="_blank" rel="noopener noreferrer">Storefront</a>, and your current theme <em>%s</em> will be deactivated.', 'woocommerce' ),
1947
								$theme_name
1948
						),
1949
						'img_url'     => WC()->plugin_url() . '/assets/images/obw-storefront-icon.svg',
1950
						'img_alt'     => __( 'Storefront icon', 'woocommerce' ),
1951
					) );
1952
				endif;
1953
1954
				if ( $this->should_show_automated_tax() ) :
1955
					$this->display_recommended_item( array(
1956
						'type'        => 'automated_taxes',
1957
						'title'       => __( 'Automated Taxes', 'woocommerce' ),
1958
						'description' => __( 'Save time and errors with automated tax calculation and collection at checkout. Powered by WooCommerce Services and Jetpack.', 'woocommerce' ),
1959
						'img_url'     => WC()->plugin_url() . '/assets/images/obw-taxes-icon.svg',
1960
						'img_alt'     => __( 'automated taxes icon', 'woocommerce' ),
1961
						'plugins'     => $this->get_wcs_requisite_plugins(),
1962
					) );
1963
				endif;
1964
1965 View Code Duplication
				if ( $this->should_show_wc_admin() ) :
1966
					$this->display_recommended_item( array(
1967
						'type'        => 'wc_admin',
1968
						'title'       => __( 'WooCommerce Admin', 'woocommerce' ),
1969
						'description' => __( 'Manage your store\'s reports and monitor key metrics with a new and improved interface and dashboard.', 'woocommerce' ),
1970
						'img_url'     => WC()->plugin_url() . '/assets/images/obw-woocommerce-admin-icon.svg',
1971
						'img_alt'     => __( 'WooCommerce Admin icon', 'woocommerce' ),
1972
						'plugins'     => array( array( 'name' => __( 'WooCommerce Admin', 'woocommerce' ), 'slug' => 'woocommerce-admin' ) ),
1973
					) );
1974
				endif;
1975
1976 View Code Duplication
				if ( $this->should_show_mailchimp() ) :
1977
					$this->display_recommended_item( array(
1978
						'type'        => 'mailchimp',
1979
						'title'       => __( 'Mailchimp', 'woocommerce' ),
1980
						'description' => __( 'Join the 16 million customers who use Mailchimp. Sync list and store data to send automated emails, and targeted campaigns.', 'woocommerce' ),
1981
						'img_url'     => WC()->plugin_url() . '/assets/images/obw-mailchimp-icon.svg',
1982
						'img_alt'     => __( 'Mailchimp icon', 'woocommerce' ),
1983
						'plugins'     => array( array( 'name' => __( 'Mailchimp for WooCommerce', 'woocommerce' ), 'slug' => 'mailchimp-for-woocommerce' ) ),
1984
					) );
1985
				endif;
1986
1987 View Code Duplication
				if ( $this->should_show_facebook() ) :
1988
					$this->display_recommended_item( array(
1989
						'type'        => 'facebook',
1990
						'title'       => __( 'Facebook', 'woocommerce' ),
1991
						'description' => __( 'Enjoy all Facebook products combined in one extension: pixel tracking, catalog sync, messenger chat, shop functionality and Instagram shopping (coming soon)!', 'woocommerce' ),
1992
						'img_url'     => WC()->plugin_url() . '/assets/images/obw-facebook-icon.svg',
1993
						'img_alt'     => __( 'Facebook icon', 'woocommerce' ),
1994
						'plugins'     => array( array( 'name' => __( 'Facebook for WooCommerce', 'woocommerce' ), 'slug' => 'facebook-for-woocommerce' ) ),
1995
					) );
1996
				endif;
1997
			?>
1998
		</ul>
1999
			<p class="wc-setup-actions step">
2000
				<?php $this->plugin_install_info(); ?>
2001
				<button type="submit" class="button-primary button button-large button-next" value="<?php esc_attr_e( 'Continue', 'woocommerce' ); ?>" name="save_step"><?php esc_html_e( 'Continue', 'woocommerce' ); ?></button>
2002
				<?php wp_nonce_field( 'wc-setup' ); ?>
2003
			</p>
2004
		</form>
2005
		<?php
2006
	}
2007
2008
	/**
2009
	 * Recommended step save.
2010
	 */
2011
	public function wc_setup_recommended_save() {
2012
		check_admin_referer( 'wc-setup' );
2013
2014
		$setup_storefront       = isset( $_POST['setup_storefront_theme'] ) && 'yes' === $_POST['setup_storefront_theme'];
2015
		$setup_automated_tax    = isset( $_POST['setup_automated_taxes'] ) && 'yes' === $_POST['setup_automated_taxes'];
2016
		$setup_mailchimp        = isset( $_POST['setup_mailchimp'] ) && 'yes' === $_POST['setup_mailchimp'];
2017
		$setup_facebook         = isset( $_POST['setup_facebook'] ) && 'yes' === $_POST['setup_facebook'];
2018
		$setup_wc_admin         = isset( $_POST['setup_wc_admin'] ) && 'yes' === $_POST['setup_wc_admin'];
2019
2020
		update_option( 'woocommerce_calc_taxes', $setup_automated_tax ? 'yes' : 'no' );
2021
		update_option( 'woocommerce_setup_automated_taxes', $setup_automated_tax );
2022
2023
		if ( $setup_storefront ) {
2024
			$this->install_theme( 'storefront' );
2025
		}
2026
2027
		if ( $setup_automated_tax ) {
2028
			$this->install_woocommerce_services();
2029
		}
2030
2031
		if ( $setup_mailchimp ) {
2032
			// Prevent MailChimp from redirecting to its settings page during the OBW flow.
2033
			add_option( 'mailchimp_woocommerce_plugin_do_activation_redirect', false );
2034
2035
			$this->install_plugin(
2036
				'mailchimp-for-woocommerce',
2037
				array(
2038
					'name'      => __( 'MailChimp for WooCommerce', 'woocommerce' ),
2039
					'repo-slug' => 'mailchimp-for-woocommerce',
2040
					'file'      => 'mailchimp-woocommerce.php',
2041
				)
2042
			);
2043
		}
2044
2045
		if ( $setup_facebook ) {
2046
			$this->install_plugin(
2047
				'facebook-for-woocommerce',
2048
				array(
2049
					'name'      => __( 'Facebook for WooCommerce', 'woocommerce' ),
2050
					'repo-slug' => 'facebook-for-woocommerce',
2051
				)
2052
			);
2053
		}
2054
2055
		if ( $setup_wc_admin ) {
2056
			$this->install_plugin(
2057
				'woocommerce-admin',
2058
				array(
2059
					'name'      => __( 'WooCommerce Admin', 'woocommerce' ),
2060
					'repo-slug' => 'woocommerce-admin',
2061
				)
2062
			);
2063
		}
2064
2065
		wp_redirect( esc_url_raw( $this->get_next_step_link() ) );
2066
		exit;
2067
	}
2068
2069
	/**
2070
	 * Go to the next step if Jetpack was connected.
2071
	 */
2072
	protected function wc_setup_activate_actions() {
2073
		if (
2074
			isset( $_GET['from'] ) &&
2075
			'wpcom' === $_GET['from'] &&
2076
			class_exists( 'Jetpack' ) &&
2077
			Jetpack::is_active()
2078
		) {
2079
			wp_redirect( esc_url_raw( remove_query_arg( 'from', $this->get_next_step_link() ) ) );
2080
			exit;
2081
		}
2082
	}
2083
2084
	protected function wc_setup_activate_get_feature_list() {
2085
		$features = array();
2086
2087
		$stripe_settings = get_option( 'woocommerce_stripe_settings', false );
2088
		$stripe_enabled  = is_array( $stripe_settings )
2089
			&& isset( $stripe_settings['create_account'] ) && 'yes' === $stripe_settings['create_account']
2090
			&& isset( $stripe_settings['enabled'] ) && 'yes' === $stripe_settings['enabled'];
2091
		$ppec_settings   = get_option( 'woocommerce_ppec_paypal_settings', false );
2092
		$ppec_enabled    = is_array( $ppec_settings )
2093
			&& isset( $ppec_settings['reroute_requests'] ) && 'yes' === $ppec_settings['reroute_requests']
2094
			&& isset( $ppec_settings['enabled'] ) && 'yes' === $ppec_settings['enabled'];
2095
2096
		$features['payment'] = $stripe_enabled || $ppec_enabled;
2097
		$features['taxes']   = (bool) get_option( 'woocommerce_setup_automated_taxes', false );
2098
		$features['labels']  = (bool) get_option( 'woocommerce_setup_shipping_labels', false );
2099
2100
		return $features;
2101
	}
2102
2103
	protected function wc_setup_activate_get_feature_list_str() {
2104
		$features = $this->wc_setup_activate_get_feature_list();
2105
		if ( $features['payment'] && $features['taxes'] && $features['labels'] ) {
2106
			return __( 'payment setup, automated taxes and discounted shipping labels', 'woocommerce' );
2107
		} else if ( $features['payment'] && $features['taxes'] ) {
2108
			return __( 'payment setup and automated taxes', 'woocommerce' );
2109
		} else if ( $features['payment'] && $features['labels'] ) {
2110
			return __( 'payment setup and discounted shipping labels', 'woocommerce' );
2111
		} else if ( $features['payment'] ) {
2112
			return __( 'payment setup', 'woocommerce' );
2113
		} else if ( $features['taxes'] && $features['labels'] ) {
2114
			return __( 'automated taxes and discounted shipping labels', 'woocommerce' );
2115
		} else if ( $features['taxes'] ) {
2116
			return __( 'automated taxes', 'woocommerce' );
2117
		} else if ( $features['labels'] ) {
2118
			return __( 'discounted shipping labels', 'woocommerce' );
2119
		}
2120
		return false;
2121
	}
2122
2123
	/**
2124
	 * Activate step.
2125
	 */
2126
	public function wc_setup_activate() {
2127
		$this->wc_setup_activate_actions();
2128
2129
		$jetpack_connected = class_exists( 'Jetpack' ) && Jetpack::is_active();
2130
2131
		$has_jetpack_error = false;
2132
		if ( isset( $_GET['activate_error'] ) ) {
2133
			$has_jetpack_error = true;
2134
2135
			$title = __( "Sorry, we couldn't connect your store to Jetpack", 'woocommerce' );
2136
2137
			$error_message = $this->get_activate_error_message( sanitize_text_field( wp_unslash( $_GET['activate_error'] ) ) );
2138
			$description = $error_message;
2139
		} else {
2140
			$feature_list = $this->wc_setup_activate_get_feature_list_str();
2141
2142
			$description = false;
2143
2144
			if ( $feature_list ) {
2145
				if ( ! $jetpack_connected ) {
2146
					/* translators: %s: list of features, potentially comma separated */
2147
					$description_base = __( 'Your store is almost ready! To activate services like %s, just connect with Jetpack.', 'woocommerce' );
2148
				} else {
2149
					$description_base = __( 'Thanks for using Jetpack! Your store is almost ready: to activate services like %s, just connect your store.', 'woocommerce' );
2150
				}
2151
				$description = sprintf( $description_base, $feature_list );
2152
			}
2153
2154
			if ( ! $jetpack_connected ) {
2155
				$title = $feature_list ?
2156
					__( 'Connect your store to Jetpack', 'woocommerce' ) :
2157
					__( 'Connect your store to Jetpack to enable extra features', 'woocommerce' );
2158
				$button_text = __( 'Continue with Jetpack', 'woocommerce' );
2159
			} elseif ( $feature_list ) {
2160
				$title = __( 'Connect your store to activate WooCommerce Services', 'woocommerce' );
2161
				$button_text = __( 'Continue with WooCommerce Services', 'woocommerce' );
2162
			} else {
2163
				wp_redirect( esc_url_raw( $this->get_next_step_link() ) );
2164
				exit;
2165
			}
2166
		}
2167
		?>
2168
		<h1><?php echo esc_html( $title ); ?></h1>
2169
		<p><?php echo esc_html( $description ); ?></p>
2170
2171
		<?php if ( $jetpack_connected ) : ?>
2172
			<div class="activate-splash">
2173
				<img
2174
					class="jetpack-logo"
2175
					src="<?php echo esc_url( WC()->plugin_url() . '/assets/images/jetpack_horizontal_logo.png' ); ?>"
2176
					alt="<?php esc_attr_e( 'Jetpack logo', 'woocommerce' ); ?>"
2177
				/>
2178
				<img
2179
					class="wcs-notice"
2180
					src="<?php echo esc_url( WC()->plugin_url() . '/assets/images/wcs-notice.png' ); ?>"
2181
				/>
2182
			</div>
2183
		<?php else : ?>
2184
			<img
2185
				class="jetpack-logo"
2186
				src="<?php echo esc_url( WC()->plugin_url() . '/assets/images/jetpack_vertical_logo.png' ); ?>"
2187
				alt="<?php esc_attr_e( 'Jetpack logo', 'woocommerce' ); ?>"
2188
			/>
2189
		<?php endif; ?>
2190
2191
		<?php if ( $has_jetpack_error ) : ?>
2192
			<p class="wc-setup-actions step">
2193
				<a
2194
					href="<?php echo esc_url( $this->get_next_step_link() ); ?>"
2195
					class="button-primary button button-large"
2196
				>
2197
					<?php esc_html_e( 'Finish setting up your store', 'woocommerce' ); ?>
2198
				</a>
2199
			</p>
2200
		<?php else : ?>
2201
			<p class="jetpack-terms">
2202
				<?php
2203
					printf(
2204
						wp_kses_post( __( 'By connecting your site you agree to our fascinating <a href="%1$s" target="_blank">Terms of Service</a> and to <a href="%2$s" target="_blank">share details</a> with WordPress.com', 'woocommerce' ) ),
2205
						'https://wordpress.com/tos',
2206
						'https://jetpack.com/support/what-data-does-jetpack-sync'
2207
					);
2208
				?>
2209
			</p>
2210
			<form method="post" class="activate-jetpack">
2211
				<p class="wc-setup-actions step">
2212
					<button type="submit" class="button-primary button button-large" value="<?php echo esc_attr( $button_text ); ?>"><?php echo esc_html( $button_text ); ?></button>
2213
				</p>
2214
				<input type="hidden" name="save_step" value="activate" />
2215
				<?php wp_nonce_field( 'wc-setup' ); ?>
2216
			</form>
2217
			<?php if ( ! $jetpack_connected ) : ?>
2218
				<h3 class="jetpack-reasons">
2219
					<?php
2220
						echo esc_html( $description ?
2221
							__( "Bonus reasons you'll love Jetpack", 'woocommerce' ) :
2222
							__( "Reasons you'll love Jetpack", 'woocommerce' )
2223
						);
2224
					?>
2225
				</h3>
2226
				<ul class="wc-wizard-features">
2227
					<li class="wc-wizard-feature-item">
2228
						<p class="wc-wizard-feature-name">
2229
							<strong><?php esc_html_e( 'Better security', 'woocommerce' ); ?></strong>
2230
						</p>
2231
						<p class="wc-wizard-feature-description">
2232
							<?php esc_html_e( 'Protect your store from unauthorized access.', 'woocommerce' ); ?>
2233
						</p>
2234
					</li>
2235
					<li class="wc-wizard-feature-item">
2236
						<p class="wc-wizard-feature-name">
2237
							<strong><?php esc_html_e( 'Store stats', 'woocommerce' ); ?></strong>
2238
						</p>
2239
						<p class="wc-wizard-feature-description">
2240
							<?php esc_html_e( 'Get insights on how your store is doing, including total sales, top products, and more.', 'woocommerce' ); ?>
2241
						</p>
2242
					</li>
2243
					<li class="wc-wizard-feature-item">
2244
						<p class="wc-wizard-feature-name">
2245
							<strong><?php esc_html_e( 'Store monitoring', 'woocommerce' ); ?></strong>
2246
						</p>
2247
						<p class="wc-wizard-feature-description">
2248
							<?php esc_html_e( 'Get an alert if your store is down for even a few minutes.', 'woocommerce' ); ?>
2249
						</p>
2250
					</li>
2251
					<li class="wc-wizard-feature-item">
2252
						<p class="wc-wizard-feature-name">
2253
							<strong><?php esc_html_e( 'Product promotion', 'woocommerce' ); ?></strong>
2254
						</p>
2255
						<p class="wc-wizard-feature-description">
2256
							<?php esc_html_e( "Share new items on social media the moment they're live in your store.", 'woocommerce' ); ?>
2257
						</p>
2258
					</li>
2259
				</ul>
2260
			<?php endif; ?>
2261
		<?php endif; ?>
2262
	<?php
2263
	}
2264
2265
	protected function get_all_activate_errors() {
2266
		return array(
2267
			'default' => __( "Sorry! We tried, but we couldn't connect Jetpack just now 😭. Please go to the Plugins tab to connect Jetpack, so that you can finish setting up your store.", 'woocommerce' ),
2268
			'jetpack_cant_be_installed' => __( "Sorry! We tried, but we couldn't install Jetpack for you 😭. Please go to the Plugins tab to install it, and finish setting up your store.", 'woocommerce' ),
2269
			'register_http_request_failed' => __( "Sorry! We couldn't contact Jetpack just now 😭. Please make sure that your site is visible over the internet, and that it accepts incoming and outgoing requests via curl. You can also try to connect to Jetpack again, and if you run into any more issues, please contact support.", 'woocommerce' ),
2270
			'siteurl_private_ip_dev' => __( "Your site might be on a private network. Jetpack can only connect to public sites. Please make sure your site is visible over the internet, and then try connecting again 🙏." , 'woocommerce' ),
2271
		);
2272
	}
2273
2274
	protected function get_activate_error_message( $code = '' ) {
2275
		$errors = $this->get_all_activate_errors();
2276
		return array_key_exists( $code, $errors ) ? $errors[ $code ] : $errors['default'];
2277
	}
2278
2279
	/**
2280
	 * Activate step save.
2281
	 *
2282
	 * Install, activate, and launch connection flow for Jetpack.
2283
	 */
2284
	public function wc_setup_activate_save() {
2285
		check_admin_referer( 'wc-setup' );
2286
2287
		set_transient( 'wc_setup_activated', 'yes', MINUTE_IN_SECONDS * 10 );
2288
2289
		// Leave a note for WooCommerce Services that Jetpack has been opted into.
2290
		update_option( 'woocommerce_setup_jetpack_opted_in', true );
2291
2292
		if ( class_exists( 'Jetpack' ) && Jetpack::is_active() ) {
2293
			wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
2294
			exit;
2295
		}
2296
2297
		WC_Install::background_installer( 'jetpack', array(
2298
			'name'      => __( 'Jetpack', 'woocommerce' ),
2299
			'repo-slug' => 'jetpack',
2300
		) );
2301
2302
		// Did Jetpack get successfully installed?
2303
		if ( ! class_exists( 'Jetpack' ) ) {
2304
			wp_redirect( esc_url_raw( add_query_arg( 'activate_error', 'jetpack_cant_be_installed' ) ) );
2305
			exit;
2306
		}
2307
2308
		Jetpack::maybe_set_version_option();
2309
		$register_result = Jetpack::try_registration();
2310
2311
		if ( is_wp_error( $register_result ) ) {
2312
			$result_error_code = $register_result->get_error_code();
2313
			$jetpack_error_code = array_key_exists( $result_error_code, $this->get_all_activate_errors() ) ? $result_error_code : 'register';
2314
			wp_redirect( esc_url_raw( add_query_arg( 'activate_error', $jetpack_error_code ) ) );
2315
			exit;
2316
		}
2317
2318
		$redirect_url = esc_url_raw( add_query_arg( array(
2319
			'page'           => 'wc-setup',
2320
			'step'           => 'activate',
2321
			'from'           => 'wpcom',
2322
			'activate_error' => false,
2323
		), admin_url() ) );
2324
		$connection_url = Jetpack::init()->build_connect_url( true, $redirect_url, 'woocommerce-setup-wizard' );
2325
2326
		wp_redirect( esc_url_raw( $connection_url ) );
2327
		exit;
2328
	}
2329
2330
	/**
2331
	 * Final step.
2332
	 */
2333
	public function wc_setup_ready() {
2334
		// We've made it! Don't prompt the user to run the wizard again.
2335
		WC_Admin_Notices::remove_notice( 'install' );
2336
2337
		$user_email   = $this->get_current_user_email();
2338
		$videos_url   = 'https://docs.woocommerce.com/document/woocommerce-guided-tour-videos/?utm_source=setupwizard&utm_medium=product&utm_content=videos&utm_campaign=woocommerceplugin';
2339
		$docs_url     = 'https://docs.woocommerce.com/documentation/plugins/woocommerce/getting-started/?utm_source=setupwizard&utm_medium=product&utm_content=docs&utm_campaign=woocommerceplugin';
2340
		$help_text    = sprintf(
2341
			/* translators: %1$s: link to videos, %2$s: link to docs */
2342
			__( 'Watch our <a href="%1$s" target="_blank">guided tour videos</a> to learn more about WooCommerce, and visit WooCommerce.com to learn more about <a href="%2$s" target="_blank">getting started</a>.', 'woocommerce' ),
2343
			$videos_url,
2344
			$docs_url
2345
		);
2346
		?>
2347
		<h1><?php esc_html_e( "You're ready to start selling!", 'woocommerce' ); ?></h1>
2348
2349
		<div class="woocommerce-message woocommerce-newsletter">
2350
			<p><?php esc_html_e( "We're here for you — get tips, product updates, and inspiration straight to your mailbox.", 'woocommerce' ); ?></p>
2351
			<form action="//woocommerce.us8.list-manage.com/subscribe/post?u=2c1434dc56f9506bf3c3ecd21&amp;id=13860df971&amp;SIGNUPPAGE=plugin" method="post" target="_blank" novalidate>
2352
				<div class="newsletter-form-container">
2353
					<input
2354
						class="newsletter-form-email"
2355
						type="email"
2356
						value="<?php echo esc_attr( $user_email ); ?>"
2357
						name="EMAIL"
2358
						placeholder="<?php esc_attr_e( 'Email address', 'woocommerce' ); ?>"
2359
						required
2360
					>
2361
					<p class="wc-setup-actions step newsletter-form-button-container">
2362
						<button
2363
							type="submit"
2364
							value="<?php esc_attr_e( 'Yes please!', 'woocommerce' ); ?>"
2365
							name="subscribe"
2366
							id="mc-embedded-subscribe"
2367
							class="button-primary button newsletter-form-button"
2368
						><?php esc_html_e( 'Yes please!', 'woocommerce' ); ?></button>
2369
					</p>
2370
				</div>
2371
			</form>
2372
		</div>
2373
2374
		<ul class="wc-wizard-next-steps">
2375
			<li class="wc-wizard-next-step-item">
2376
				<div class="wc-wizard-next-step-description">
2377
					<p class="next-step-heading"><?php esc_html_e( 'Next step', 'woocommerce' ); ?></p>
2378
					<h3 class="next-step-description"><?php esc_html_e( 'Create some products', 'woocommerce' ); ?></h3>
2379
					<p class="next-step-extra-info"><?php esc_html_e( "You're ready to add products to your store.", 'woocommerce' ); ?></p>
2380
				</div>
2381
				<div class="wc-wizard-next-step-action">
2382
					<p class="wc-setup-actions step">
2383
						<a class="button button-primary button-large" href="<?php echo esc_url( admin_url( 'post-new.php?post_type=product&tutorial=true' ) ); ?>">
2384
							<?php esc_html_e( 'Create a product', 'woocommerce' ); ?>
2385
						</a>
2386
					</p>
2387
				</div>
2388
			</li>
2389
			<li class="wc-wizard-next-step-item">
2390
				<div class="wc-wizard-next-step-description">
2391
					<p class="next-step-heading"><?php esc_html_e( 'Have an existing store?', 'woocommerce' ); ?></p>
2392
					<h3 class="next-step-description"><?php esc_html_e( 'Import products', 'woocommerce' ); ?></h3>
2393
					<p class="next-step-extra-info"><?php esc_html_e( 'Transfer existing products to your new store — just import a CSV file.', 'woocommerce' ); ?></p>
2394
				</div>
2395
				<div class="wc-wizard-next-step-action">
2396
					<p class="wc-setup-actions step">
2397
						<a class="button button-large" href="<?php echo esc_url( admin_url( 'edit.php?post_type=product&page=product_importer' ) ); ?>">
2398
							<?php esc_html_e( 'Import products', 'woocommerce' ); ?>
2399
						</a>
2400
					</p>
2401
				</div>
2402
			</li>
2403
			<li class="wc-wizard-additional-steps">
2404
				<div class="wc-wizard-next-step-description">
2405
					<p class="next-step-heading"><?php esc_html_e( 'You can also:', 'woocommerce' ); ?></p>
2406
				</div>
2407
				<div class="wc-wizard-next-step-action">
2408
					<p class="wc-setup-actions step">
2409
						<a class="button button-large" href="<?php echo esc_url( admin_url() ); ?>">
2410
							<?php esc_html_e( 'Visit Dashboard', 'woocommerce' ); ?>
2411
						</a>
2412
						<a class="button button-large" href="<?php echo esc_url( admin_url( 'admin.php?page=wc-settings' ) ); ?>">
2413
							<?php esc_html_e( 'Review Settings', 'woocommerce' ); ?>
2414
						</a>
2415
						<a class="button button-large" href="<?php echo esc_url( add_query_arg( array( 'autofocus' => array( 'panel' => 'woocommerce' ), 'url' => wc_get_page_permalink( 'shop' ) ), admin_url( 'customize.php' ) ) ); ?>">
2416
							<?php esc_html_e( 'View &amp; Customize', 'woocommerce' ); ?>
2417
						</a>
2418
					</p>
2419
				</div>
2420
			</li>
2421
		</ul>
2422
		<p class="next-steps-help-text"><?php echo wp_kses_post( $help_text ); ?></p>
2423
		<?php
2424
	}
2425
}
2426
2427
new WC_Admin_Setup_Wizard();
2428