WC_Admin_Setup_Wizard::wc_setup_recommended_save()   F
last analyzed

Complexity

Conditions 12
Paths 1024

Size

Total Lines 57

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 156

Importance

Changes 0
Metric Value
cc 12
nc 1024
nop 0
dl 0
loc 57
ccs 0
cts 32
cp 0
crap 156
rs 3.1781
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

1
<?php
2
/**
3
 * 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
			<div class="sell-in-person-container">
542
			<input
543
				type="checkbox"
544
				id="woocommerce_sell_in_person"
545
				name="sell_in_person"
546
				value="yes"
547
				<?php checked( $sell_in_person, true ); ?>
548
			/>
549
			<label class="location-prompt" for="woocommerce_sell_in_person">
550
				<?php esc_html_e( 'I will also be selling products or services in person.', 'woocommerce' ); ?>
551
			</label>
552
			</div>
553
554
			<input type="checkbox" id="wc_tracker_checkbox" name="wc_tracker_checkbox" value="yes" <?php checked( 'yes', get_option( 'woocommerce_allow_tracking', 'no' ) ); ?> />
555
556
			<?php $this->tracking_modal(); ?>
557
558
			<p class="wc-setup-actions step">
559
				<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>
560
			</p>
561
		</form>
562
		<?php
563
	}
564
565
	/**
566
	 * Template for the usage tracking modal.
567
	 */
568
	public function tracking_modal() {
569
		?>
570
		<script type="text/template" id="tmpl-wc-modal-tracking-setup">
571
			<div class="wc-backbone-modal woocommerce-tracker">
572
				<div class="wc-backbone-modal-content">
573
					<section class="wc-backbone-modal-main" role="main">
574
						<header class="wc-backbone-modal-header">
575
							<h1><?php esc_html_e( 'Help improve WooCommerce with usage tracking', 'woocommerce' ); ?></h1>
576
						</header>
577
						<article>
578
							<p>
579
							<?php
580
								printf(
581
									wp_kses(
582
										/* translators: %1$s: usage tracking help link */
583
										__( 'Learn more about how usage tracking works, and how you\'ll be helping <a href="%1$s" target="_blank">here</a>.', 'woocommerce' ),
584
										array(
585
											'a'    => array(
586
												'href'   => array(),
587
												'target' => array(),
588
											),
589
										)
590
									),
591
									'https://woocommerce.com/usage-tracking/'
592
								);
593
							?>
594
							</p>
595
							<p class="woocommerce-tracker-checkbox">
596
								<input type="checkbox" id="wc_tracker_checkbox_dialog" name="wc_tracker_checkbox_dialog" value="yes" <?php checked( 'yes', get_option( 'woocommerce_allow_tracking', 'no' ) ); ?> />
597
								<label for="wc_tracker_checkbox_dialog"><?php esc_html_e( 'Enable usage tracking and help improve WooCommerce', 'woocommerce' ); ?></label>
598
							</p>
599
						</article>
600
						<footer>
601
							<div class="inner">
602
								<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>
603
							</div>
604
						</footer>
605
					</section>
606
				</div>
607
			</div>
608
			<div class="wc-backbone-modal-backdrop modal-close"></div>
609
		</script>
610
		<?php
611
	}
612
613
	/**
614
	 * Save initial store settings.
615
	 */
616
	public function wc_setup_store_setup_save() {
617
		check_admin_referer( 'wc-setup' );
618
619
		$address        = isset( $_POST['store_address'] ) ? wc_clean( wp_unslash( $_POST['store_address'] ) ) : '';
620
		$address_2      = isset( $_POST['store_address_2'] ) ? wc_clean( wp_unslash( $_POST['store_address_2'] ) ) : '';
621
		$city           = isset( $_POST['store_city'] ) ? wc_clean( wp_unslash( $_POST['store_city'] ) ) : '';
622
		$country        = isset( $_POST['store_country'] ) ? wc_clean( wp_unslash( $_POST['store_country'] ) ) : '';
623
		$state          = isset( $_POST['store_state'] ) ? wc_clean( wp_unslash( $_POST['store_state'] ) ) : '*';
624
		$postcode       = isset( $_POST['store_postcode'] ) ? wc_clean( wp_unslash( $_POST['store_postcode'] ) ) : '';
625
		$currency_code  = isset( $_POST['currency_code'] ) ? wc_clean( wp_unslash( $_POST['currency_code'] ) ) : '';
626
		$product_type   = isset( $_POST['product_type'] ) ? wc_clean( wp_unslash( $_POST['product_type'] ) ) : '';
627
		$sell_in_person = isset( $_POST['sell_in_person'] ) && ( 'yes' === wc_clean( wp_unslash( $_POST['sell_in_person'] ) ) );
628
		$tracking       = isset( $_POST['wc_tracker_checkbox'] ) && ( 'yes' === wc_clean( wp_unslash( $_POST['wc_tracker_checkbox'] ) ) );
629
630
		update_option( 'woocommerce_store_address', $address );
631
		update_option( 'woocommerce_store_address_2', $address_2 );
632
		update_option( 'woocommerce_store_city', $city );
633
		update_option( 'woocommerce_default_country', $country . ':' . $state );
634
		update_option( 'woocommerce_store_postcode', $postcode );
635
		update_option( 'woocommerce_currency', $currency_code );
636
		update_option( 'woocommerce_product_type', $product_type );
637
		update_option( 'woocommerce_sell_in_person', $sell_in_person );
638
639
		$locale_info = include WC()->plugin_path() . '/i18n/locale-info.php';
640
641
		if ( isset( $locale_info[ $country ] ) ) {
642
			update_option( 'woocommerce_weight_unit', $locale_info[ $country ]['weight_unit'] );
643
			update_option( 'woocommerce_dimension_unit', $locale_info[ $country ]['dimension_unit'] );
644
645
			// Set currency formatting options based on chosen location and currency.
646
			if ( $locale_info[ $country ]['currency_code'] === $currency_code ) {
647
				update_option( 'woocommerce_currency_pos', $locale_info[ $country ]['currency_pos'] );
648
				update_option( 'woocommerce_price_decimal_sep', $locale_info[ $country ]['decimal_sep'] );
649
				update_option( 'woocommerce_price_num_decimals', $locale_info[ $country ]['num_decimals'] );
650
				update_option( 'woocommerce_price_thousand_sep', $locale_info[ $country ]['thousand_sep'] );
651
			}
652
		}
653
654
		if ( $tracking ) {
655
			update_option( 'woocommerce_allow_tracking', 'yes' );
656
			wp_schedule_single_event( time() + 10, 'woocommerce_tracker_send_event', array( true ) );
657
		} else {
658
			update_option( 'woocommerce_allow_tracking', 'no' );
659
		}
660
661
		WC_Install::create_pages();
662
		wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
663
		exit;
664
	}
665
666
	/**
667
	 * Finishes replying to the client, but keeps the process running for further (async) code execution.
668
	 *
669
	 * @see https://core.trac.wordpress.org/ticket/41358 .
670
	 */
671 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...
672
		// Only 1 PHP process can access a session object at a time, close this so the next request isn't kept waiting.
673
		// @codingStandardsIgnoreStart
674
		if ( session_id() ) {
675
			session_write_close();
676
		}
677
		// @codingStandardsIgnoreEnd
678
679
		wc_set_time_limit( 0 );
680
681
		// fastcgi_finish_request is the cleanest way to send the response and keep the script running, but not every server has it.
682
		if ( is_callable( 'fastcgi_finish_request' ) ) {
683
			fastcgi_finish_request();
684
		} else {
685
			// Fallback: send headers and flush buffers.
686
			if ( ! headers_sent() ) {
687
				header( 'Connection: close' );
688
			}
689
			@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...
690
			flush();
691
		}
692
	}
693
694
	/**
695
	 * Function called after the HTTP request is finished, so it's executed without the client having to wait for it.
696
	 *
697
	 * @see WC_Admin_Setup_Wizard::install_plugin
698
	 * @see WC_Admin_Setup_Wizard::install_theme
699
	 */
700
	public function run_deferred_actions() {
701
		$this->close_http_connection();
702
		foreach ( $this->deferred_actions as $action ) {
703
			call_user_func_array( $action['func'], $action['args'] );
704
705
			// Clear the background installation flag if this is a plugin.
706
			if (
707
				isset( $action['func'][1] ) &&
708
				'background_installer' === $action['func'][1] &&
709
				isset( $action['args'][0] )
710
			) {
711
				delete_option( 'woocommerce_setup_background_installing_' . $action['args'][0] );
712
			}
713
		}
714
	}
715
716
	/**
717
	 * Helper method to queue the background install of a plugin.
718
	 *
719
	 * @param string $plugin_id  Plugin id used for background install.
720
	 * @param array  $plugin_info Plugin info array containing name and repo-slug, and optionally file if different from [repo-slug].php.
721
	 */
722
	protected function install_plugin( $plugin_id, $plugin_info ) {
723
		// Make sure we don't trigger multiple simultaneous installs.
724
		if ( get_option( 'woocommerce_setup_background_installing_' . $plugin_id ) ) {
725
			return;
726
		}
727
728
		$plugin_file = isset( $plugin_info['file'] ) ? $plugin_info['file'] : $plugin_info['repo-slug'] . '.php';
729
		if ( is_plugin_active( $plugin_info['repo-slug'] . '/' . $plugin_file ) ) {
730
			return;
731
		}
732
733
		if ( empty( $this->deferred_actions ) ) {
734
			add_action( 'shutdown', array( $this, 'run_deferred_actions' ) );
735
		}
736
737
		array_push(
738
			$this->deferred_actions,
739
			array(
740
				'func' => array( 'WC_Install', 'background_installer' ),
741
				'args' => array( $plugin_id, $plugin_info ),
742
			)
743
		);
744
745
		// Set the background installation flag for this plugin.
746
		update_option( 'woocommerce_setup_background_installing_' . $plugin_id, true );
747
	}
748
749
750
	/**
751
	 * Helper method to queue the background install of a theme.
752
	 *
753
	 * @param string $theme_id  Theme id used for background install.
754
	 */
755
	protected function install_theme( $theme_id ) {
756
		if ( empty( $this->deferred_actions ) ) {
757
			add_action( 'shutdown', array( $this, 'run_deferred_actions' ) );
758
		}
759
		array_push(
760
			$this->deferred_actions,
761
			array(
762
				'func' => array( 'WC_Install', 'theme_background_installer' ),
763
				'args' => array( $theme_id ),
764
			)
765
		);
766
	}
767
768
	/**
769
	 * Helper method to install Jetpack.
770
	 */
771
	protected function install_jetpack() {
772
		$this->install_plugin(
773
			'jetpack',
774
			array(
775
				'name'      => __( 'Jetpack', 'woocommerce' ),
776
				'repo-slug' => 'jetpack',
777
			)
778
		);
779
	}
780
781
	/**
782
	 * Helper method to install WooCommerce Services and its Jetpack dependency.
783
	 */
784
	protected function install_woocommerce_services() {
785
		$this->install_jetpack();
786
		$this->install_plugin(
787
			'woocommerce-services',
788
			array(
789
				'name'      => __( 'WooCommerce Services', 'woocommerce' ),
790
				'repo-slug' => 'woocommerce-services',
791
			)
792
		);
793
	}
794
795
	/**
796
	 * Retrieve info for missing WooCommerce Services and/or Jetpack plugin.
797
	 *
798
	 * @return array
799
	 */
800 1
	protected function get_wcs_requisite_plugins() {
801 1
		$plugins = array();
802 1 View Code Duplication
		if ( ! is_plugin_active( 'woocommerce-services/woocommerce-services.php' ) && ! get_option( 'woocommerce_setup_background_installing_woocommerce-services' ) ) {
803 1
			$plugins[] = array(
804 1
				'name' => __( 'WooCommerce Services', 'woocommerce' ),
805 1
				'slug' => 'woocommerce-services',
806
			);
807
		}
808 1 View Code Duplication
		if ( ! is_plugin_active( 'jetpack/jetpack.php' ) && ! get_option( 'woocommerce_setup_background_installing_jetpack' ) ) {
809 1
			$plugins[] = array(
810 1
				'name' => __( 'Jetpack', 'woocommerce' ),
811 1
				'slug' => 'jetpack',
812
			);
813
		}
814 1
		return $plugins;
815
	}
816
817
	/**
818
	 * Plugin install info message markup with heading.
819
	 */
820
	public function plugin_install_info() {
821
		?>
822
		<span class="plugin-install-info">
823
			<span class="plugin-install-info-label"><?php esc_html_e( 'The following plugins will be installed and activated for you:', 'woocommerce' ); ?></span>
824
			<span class="plugin-install-info-list"></span>
825
		</span>
826
		<?php
827
	}
828
829
	/**
830
	 * Get shipping methods based on country code.
831
	 *
832
	 * @param string $country_code Country code.
833
	 * @param string $currency_code Currency code.
834
	 * @return array
835
	 */
836
	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...
837
		$shipping_methods = array(
838
			'flat_rate'     => array(
839
				'name'        => __( 'Flat Rate', 'woocommerce' ),
840
				'description' => __( 'Set a fixed price to cover shipping costs.', 'woocommerce' ),
841
				'settings'    => array(
842
					'cost' => array(
843
						'type'          => 'text',
844
						'default_value' => __( 'Cost', 'woocommerce' ),
845
						'description'   => __( 'What would you like to charge for flat rate shipping?', 'woocommerce' ),
846
						'required'      => true,
847
					),
848
				),
849
			),
850
			'free_shipping' => array(
851
				'name'        => __( 'Free Shipping', 'woocommerce' ),
852
				'description' => __( "Don't charge for shipping.", 'woocommerce' ),
853
			),
854
		);
855
856
		return $shipping_methods;
857
	}
858
859
	/**
860
	 * Render the available shipping methods for a given country code.
861
	 *
862
	 * @param string $country_code Country code.
863
	 * @param string $currency_code Currency code.
864
	 * @param string $input_prefix Input prefix.
865
	 */
866
	protected function shipping_method_selection_form( $country_code, $currency_code, $input_prefix ) {
867
		$selected         = 'flat_rate';
868
		$shipping_methods = $this->get_wizard_shipping_methods( $country_code, $currency_code );
869
		?>
870
		<div class="wc-wizard-shipping-method-select">
871
			<div class="wc-wizard-shipping-method-dropdown">
872
				<select
873
					id="<?php echo esc_attr( "{$input_prefix}[method]" ); ?>"
874
					name="<?php echo esc_attr( "{$input_prefix}[method]" ); ?>"
875
					class="method wc-enhanced-select"
876
					data-plugins="<?php echo wc_esc_json( wp_json_encode( $this->get_wcs_requisite_plugins() ) ); ?>"
877
				>
878 View Code Duplication
				<?php foreach ( $shipping_methods as $method_id => $method ) : ?>
879
					<option value="<?php echo esc_attr( $method_id ); ?>" <?php selected( $selected, $method_id ); ?>><?php echo esc_html( $method['name'] ); ?></option>
880
				<?php endforeach; ?>
881
				</select>
882
			</div>
883
			<div class="shipping-method-descriptions">
884 View Code Duplication
				<?php foreach ( $shipping_methods as $method_id => $method ) : ?>
885
					<p class="shipping-method-description <?php echo esc_attr( $method_id ); ?> <?php echo $method_id !== $selected ? 'hide' : ''; ?>">
886
						<?php echo esc_html( $method['description'] ); ?>
887
					</p>
888
				<?php endforeach; ?>
889
			</div>
890
		</div>
891
892
		<div class="shipping-method-settings">
893
		<?php foreach ( $shipping_methods as $method_id => $method ) : ?>
894
			<?php
895
			if ( empty( $method['settings'] ) ) {
896
				continue;
897
			}
898
			?>
899
			<div class="shipping-method-setting <?php echo esc_attr( $method_id ); ?> <?php echo $method_id !== $selected ? 'hide' : ''; ?>">
900
			<?php foreach ( $method['settings'] as $setting_id => $setting ) : ?>
901
				<?php $method_setting_id = "{$input_prefix}[{$method_id}][{$setting_id}]"; ?>
902
				<input
903
					type="<?php echo esc_attr( $setting['type'] ); ?>"
904
					placeholder="<?php echo esc_attr( $setting['default_value'] ); ?>"
905
					id="<?php echo esc_attr( $method_setting_id ); ?>"
906
					name="<?php echo esc_attr( $method_setting_id ); ?>"
907
					class="<?php echo esc_attr( $setting['required'] ? 'shipping-method-required-field' : '' ); ?>"
908
					<?php echo ( $method_id === $selected && $setting['required'] ) ? 'required' : ''; ?>
909
				/>
910
				<p class="description">
911
					<?php echo esc_html( $setting['description'] ); ?>
912
				</p>
913
			<?php endforeach; ?>
914
			</div>
915
		<?php endforeach; ?>
916
		</div>
917
		<?php
918
	}
919
920
	/**
921
	 * Render a product weight unit dropdown.
922
	 *
923
	 * @return string
924
	 */
925
	protected function get_product_weight_selection() {
926
		$weight_unit = get_option( 'woocommerce_weight_unit' );
927
		ob_start();
928
		?>
929
		<span class="wc-setup-shipping-unit">
930
			<select id="weight_unit" name="weight_unit" class="wc-enhanced-select">
931
				<option value="kg" <?php selected( $weight_unit, 'kg' ); ?>><?php esc_html_e( 'Kilograms', 'woocommerce' ); ?></option>
932
				<option value="g" <?php selected( $weight_unit, 'g' ); ?>><?php esc_html_e( 'Grams', 'woocommerce' ); ?></option>
933
				<option value="lbs" <?php selected( $weight_unit, 'lbs' ); ?>><?php esc_html_e( 'Pounds', 'woocommerce' ); ?></option>
934
				<option value="oz" <?php selected( $weight_unit, 'oz' ); ?>><?php esc_html_e( 'Ounces', 'woocommerce' ); ?></option>
935
			</select>
936
		</span>
937
		<?php
938
939
		return ob_get_clean();
940
	}
941
942
	/**
943
	 * Render a product dimension unit dropdown.
944
	 *
945
	 * @return string
946
	 */
947
	protected function get_product_dimension_selection() {
948
		$dimension_unit = get_option( 'woocommerce_dimension_unit' );
949
		ob_start();
950
		?>
951
		<span class="wc-setup-shipping-unit">
952
			<select id="dimension_unit" name="dimension_unit" class="wc-enhanced-select">
953
				<option value="m" <?php selected( $dimension_unit, 'm' ); ?>><?php esc_html_e( 'Meters', 'woocommerce' ); ?></option>
954
				<option value="cm" <?php selected( $dimension_unit, 'cm' ); ?>><?php esc_html_e( 'Centimeters', 'woocommerce' ); ?></option>
955
				<option value="mm" <?php selected( $dimension_unit, 'mm' ); ?>><?php esc_html_e( 'Millimeters', 'woocommerce' ); ?></option>
956
				<option value="in" <?php selected( $dimension_unit, 'in' ); ?>><?php esc_html_e( 'Inches', 'woocommerce' ); ?></option>
957
				<option value="yd" <?php selected( $dimension_unit, 'yd' ); ?>><?php esc_html_e( 'Yards', 'woocommerce' ); ?></option>
958
			</select>
959
		</span>
960
		<?php
961
962
		return ob_get_clean();
963
	}
964
965
	/**
966
	 * Shipping.
967
	 */
968
	public function wc_setup_shipping() {
969
		$country_code          = WC()->countries->get_base_country();
970
		$country_name          = WC()->countries->countries[ $country_code ];
971
		$prefixed_country_name = WC()->countries->estimated_for_prefix( $country_code ) . $country_name;
972
		$currency_code         = get_woocommerce_currency();
973
		$existing_zones        = WC_Shipping_Zones::get_zones();
974
		$intro_text            = '';
975
976
		if ( empty( $existing_zones ) ) {
977
			$intro_text = sprintf(
978
				/* translators: %s: country name including the 'the' prefix if needed */
979
				__( "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' ),
980
				$prefixed_country_name
981
			);
982
		}
983
984
		$is_wcs_labels_supported  = $this->is_wcs_shipping_labels_supported_country( $country_code );
985
		$is_shipstation_supported = $this->is_shipstation_supported_country( $country_code );
986
987
		?>
988
		<h1><?php esc_html_e( 'Shipping', 'woocommerce' ); ?></h1>
989
		<?php if ( $intro_text ) : ?>
990
			<p><?php echo wp_kses_post( $intro_text ); ?></p>
991
		<?php endif; ?>
992
		<form method="post">
993
			<?php if ( $is_wcs_labels_supported || $is_shipstation_supported ) : ?>
994
				<ul class="wc-setup-shipping-recommended">
995
				<?php
996
				if ( $is_wcs_labels_supported ) :
997
					$this->display_recommended_item(
998
						array(
999
							'type'        => 'woocommerce_services',
1000
							'title'       => __( 'Did you know you can print shipping labels at home?', 'woocommerce' ),
1001
							'description' => __( 'Use WooCommerce Shipping (powered by WooCommerce Services & Jetpack) to save time at the post office by printing your shipping labels at home.', 'woocommerce' ),
1002
							'img_url'     => WC()->plugin_url() . '/assets/images/obw-woocommerce-services-icon.png',
1003
							'img_alt'     => __( 'WooCommerce Services icon', 'woocommerce' ),
1004
							'plugins'     => $this->get_wcs_requisite_plugins(),
1005
						)
1006
					);
1007 View Code Duplication
				elseif ( $is_shipstation_supported ) :
1008
					$this->display_recommended_item(
1009
						array(
1010
							'type'        => 'shipstation',
1011
							'title'       => __( 'Did you know you can print shipping labels at home?', 'woocommerce' ),
1012
							'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' ),
1013
							'img_url'     => WC()->plugin_url() . '/assets/images/obw-shipstation-icon.png',
1014
							'img_alt'     => __( 'ShipStation icon', 'woocommerce' ),
1015
							'plugins'     => array(
1016
								array(
1017
									'name' => __( 'ShipStation', 'woocommerce' ),
1018
									'slug' => 'woocommerce-shipstation-integration',
1019
								),
1020
							),
1021
						)
1022
					);
1023
				endif;
1024
				?>
1025
				</ul>
1026
			<?php endif; ?>
1027
1028
			<?php if ( empty( $existing_zones ) ) : ?>
1029
				<ul class="wc-wizard-services shipping">
1030
					<li class="wc-wizard-service-item">
1031
						<div class="wc-wizard-service-name">
1032
							<p><?php echo esc_html_e( 'Shipping Zone', 'woocommerce' ); ?></p>
1033
						</div>
1034
						<div class="wc-wizard-service-description">
1035
							<p><?php echo esc_html_e( 'Shipping Method', 'woocommerce' ); ?></p>
1036
						</div>
1037
					</li>
1038
					<li class="wc-wizard-service-item">
1039
						<div class="wc-wizard-service-name">
1040
							<p><?php echo esc_html( $country_name ); ?></p>
1041
						</div>
1042
						<div class="wc-wizard-service-description">
1043
							<?php $this->shipping_method_selection_form( $country_code, $currency_code, 'shipping_zones[domestic]' ); ?>
1044
						</div>
1045
						<div class="wc-wizard-service-enable">
1046
							<span class="wc-wizard-service-toggle">
1047
								<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" />
1048
								<label for="shipping_zones[domestic][enabled]">
1049
							</span>
1050
						</div>
1051
					</li>
1052
					<li class="wc-wizard-service-item">
1053
						<div class="wc-wizard-service-name">
1054
							<p><?php echo esc_html_e( 'Locations not covered by your other zones', 'woocommerce' ); ?></p>
1055
						</div>
1056
						<div class="wc-wizard-service-description">
1057
							<?php $this->shipping_method_selection_form( $country_code, $currency_code, 'shipping_zones[intl]' ); ?>
1058
						</div>
1059
						<div class="wc-wizard-service-enable">
1060
							<span class="wc-wizard-service-toggle">
1061
								<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" />
1062
								<label for="shipping_zones[intl][enabled]">
1063
							</span>
1064
						</div>
1065
					</li>
1066
					<li class="wc-wizard-service-info">
1067
						<p>
1068
						<?php
1069
						printf(
1070
							wp_kses(
1071
								/* translators: %1$s: live rates tooltip text, %2$s: shipping extensions URL */
1072
								__( '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' ),
1073
								array(
1074
									'span' => array(
1075
										'class'    => array(),
1076
										'data-tip' => array(),
1077
									),
1078
									'a'    => array(
1079
										'href'   => array(),
1080
										'target' => array(),
1081
									),
1082
								)
1083
							),
1084
							esc_attr__( 'A live rate is the exact cost to ship an order, quoted directly from the shipping carrier.', 'woocommerce' ),
1085
							'https://woocommerce.com/product-category/woocommerce-extensions/shipping-methods/shipping-carriers/'
1086
						);
1087
						?>
1088
						</p>
1089
					</li>
1090
				</ul>
1091
			<?php endif; ?>
1092
1093
			<div class="wc-setup-shipping-units">
1094
				<p>
1095
					<?php
1096
						echo wp_kses(
1097
							sprintf(
1098
								/* translators: %1$s: weight unit dropdown, %2$s: dimension unit dropdown */
1099
								esc_html__( 'We\'ll use %1$s for product weight and %2$s for product dimensions.', 'woocommerce' ),
1100
								$this->get_product_weight_selection(),
1101
								$this->get_product_dimension_selection()
1102
							),
1103
							array(
1104
								'span'   => array(
1105
									'class' => array(),
1106
								),
1107
								'select' => array(
1108
									'id'    => array(),
1109
									'name'  => array(),
1110
									'class' => array(),
1111
								),
1112
								'option' => array(
1113
									'value'    => array(),
1114
									'selected' => array(),
1115
								),
1116
							)
1117
						);
1118
					?>
1119
				</p>
1120
			</div>
1121
1122
			<p class="wc-setup-actions step">
1123
				<?php $this->plugin_install_info(); ?>
1124
				<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>
1125
				<?php wp_nonce_field( 'wc-setup' ); ?>
1126
			</p>
1127
		</form>
1128
		<?php
1129
	}
1130
1131
	/**
1132
	 * Save shipping options.
1133
	 */
1134
	public function wc_setup_shipping_save() {
1135
		check_admin_referer( 'wc-setup' );
1136
1137
		// @codingStandardsIgnoreStart
1138
		$setup_domestic   = isset( $_POST['shipping_zones']['domestic']['enabled'] ) && ( 'yes' === $_POST['shipping_zones']['domestic']['enabled'] );
1139
		$domestic_method  = isset( $_POST['shipping_zones']['domestic']['method'] ) ? sanitize_text_field( wp_unslash( $_POST['shipping_zones']['domestic']['method'] ) ) : '';
1140
		$setup_intl       = isset( $_POST['shipping_zones']['intl']['enabled'] ) && ( 'yes' === $_POST['shipping_zones']['intl']['enabled'] );
1141
		$intl_method      = isset( $_POST['shipping_zones']['intl']['method'] ) ? sanitize_text_field( wp_unslash( $_POST['shipping_zones']['intl']['method'] ) ) : '';
1142
		$weight_unit      = sanitize_text_field( wp_unslash( $_POST['weight_unit'] ) );
1143
		$dimension_unit   = sanitize_text_field( wp_unslash( $_POST['dimension_unit'] ) );
1144
		$existing_zones   = WC_Shipping_Zones::get_zones();
1145
		// @codingStandardsIgnoreEnd
1146
1147
		update_option( 'woocommerce_ship_to_countries', '' );
1148
		update_option( 'woocommerce_weight_unit', $weight_unit );
1149
		update_option( 'woocommerce_dimension_unit', $dimension_unit );
1150
1151
		$setup_wcs_labels  = isset( $_POST['setup_woocommerce_services'] ) && 'yes' === $_POST['setup_woocommerce_services'];
1152
		$setup_shipstation = isset( $_POST['setup_shipstation'] ) && 'yes' === $_POST['setup_shipstation'];
1153
1154
		update_option( 'woocommerce_setup_shipping_labels', $setup_wcs_labels );
1155
1156
		if ( $setup_wcs_labels ) {
1157
			$this->install_woocommerce_services();
1158
		}
1159
1160
		if ( $setup_shipstation ) {
1161
			$this->install_plugin(
1162
				'woocommerce-shipstation-integration',
1163
				array(
1164
					'name'      => __( 'ShipStation', 'woocommerce' ),
1165
					'repo-slug' => 'woocommerce-shipstation-integration',
1166
					'file'      => 'woocommerce-shipstation.php',
1167
				)
1168
			);
1169
		}
1170
1171
		// For now, limit this setup to the first run.
1172
		if ( ! empty( $existing_zones ) ) {
1173
			wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
1174
			exit;
1175
		}
1176
1177
		/*
1178
		 * If enabled, create a shipping zone containing the country the
1179
		 * store is located in, with the selected method preconfigured.
1180
		 */
1181
		if ( $setup_domestic ) {
1182
			$zone = new WC_Shipping_Zone( null );
1183
			$zone->set_zone_order( 0 );
1184
			$zone->add_location( WC()->countries->get_base_country(), 'country' );
1185
			$zone_id = $zone->save();
1186
1187
			// Save chosen shipping method settings (using REST controller for convenience).
1188 View Code Duplication
			if ( ! empty( $_POST['shipping_zones']['domestic'][ $domestic_method ] ) ) { // WPCS: input var ok.
1189
				$request = new WP_REST_Request( 'POST', "/wc/v3/shipping/zones/{$zone_id}/methods" );
1190
				$request->add_header( 'Content-Type', 'application/json' );
1191
				$request->set_body(
1192
					wp_json_encode(
1193
						array(
1194
							'method_id' => $domestic_method,
1195
							'settings'  => wc_clean( wp_unslash( $_POST['shipping_zones']['domestic'][ $domestic_method ] ) ),
1196
						)
1197
					)
1198
				);
1199
				rest_do_request( $request );
1200
			}
1201
		}
1202
1203
		// If enabled, set the selected method for the "rest of world" zone.
1204 View Code Duplication
		if ( $setup_intl ) {
1205
			// Save chosen shipping method settings (using REST controller for convenience).
1206
			if ( ! empty( $_POST['shipping_zones']['intl'][ $intl_method ] ) ) { // WPCS: input var ok.
1207
				$request = new WP_REST_Request( 'POST', '/wc/v3/shipping/zones/0/methods' );
1208
				$request->add_header( 'Content-Type', 'application/json' );
1209
				$request->set_body(
1210
					wp_json_encode(
1211
						array(
1212
							'method_id' => $intl_method,
1213
							'settings'  => wc_clean( wp_unslash( $_POST['shipping_zones']['intl'][ $intl_method ] ) ),
1214
						)
1215
					)
1216
				);
1217
				rest_do_request( $request );
1218
			}
1219
		}
1220
1221
		// Notify the user that no shipping methods are configured.
1222
		if ( ! $setup_domestic && ! $setup_intl ) {
1223
			WC_Admin_Notices::add_notice( 'no_shipping_methods' );
1224
		}
1225
1226
		wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
1227
		exit;
1228
	}
1229
1230
	/**
1231
	 * Is Stripe country supported
1232
	 * https://stripe.com/global .
1233
	 *
1234
	 * @param string $country_code Country code.
1235
	 */
1236 1
	protected function is_stripe_supported_country( $country_code ) {
1237
		$stripe_supported_countries = array(
1238 1
			'AU',
1239
			'AT',
1240
			'BE',
1241
			'CA',
1242
			'DK',
1243
			'FI',
1244
			'FR',
1245
			'DE',
1246
			'HK',
1247
			'IE',
1248
			'JP',
1249
			'LU',
1250
			'NL',
1251
			'NZ',
1252
			'NO',
1253
			'SG',
1254
			'ES',
1255
			'SE',
1256
			'CH',
1257
			'GB',
1258
			'US',
1259
		);
1260
1261 1
		return in_array( $country_code, $stripe_supported_countries, true );
1262
	}
1263
1264
	/**
1265
	 * Is PayPal currency supported.
1266
	 *
1267
	 * @param string $currency Currency code.
1268
	 * @return boolean
1269
	 */
1270 1
	protected function is_paypal_supported_currency( $currency ) {
1271
		$supported_currencies = array(
1272 1
			'AUD',
1273
			'BRL',
1274
			'CAD',
1275
			'MXN',
1276
			'NZD',
1277
			'HKD',
1278
			'SGD',
1279
			'USD',
1280
			'EUR',
1281
			'JPY',
1282
			'TRY',
1283
			'NOK',
1284
			'CZK',
1285
			'DKK',
1286
			'HUF',
1287
			'ILS',
1288
			'MYR',
1289
			'PHP',
1290
			'PLN',
1291
			'SEK',
1292
			'CHF',
1293
			'TWD',
1294
			'THB',
1295
			'GBP',
1296
			'RMB',
1297
			'RUB',
1298
			'INR',
1299
		);
1300 1
		return in_array( $currency, $supported_currencies, true );
1301
	}
1302
1303
	/**
1304
	 * Is Klarna Checkout country supported.
1305
	 *
1306
	 * @param string $country_code Country code.
1307
	 */
1308 1
	protected function is_klarna_checkout_supported_country( $country_code ) {
1309
		$supported_countries = array(
1310 1
			'SE', // Sweden.
1311
			'FI', // Finland.
1312
			'NO', // Norway.
1313
			'NL', // Netherlands.
1314
		);
1315 1
		return in_array( $country_code, $supported_countries, true );
1316
	}
1317
1318
	/**
1319
	 * Is Klarna Payments country supported.
1320
	 *
1321
	 * @param string $country_code Country code.
1322
	 */
1323 1
	protected function is_klarna_payments_supported_country( $country_code ) {
1324
		$supported_countries = array(
1325 1
			'DK', // Denmark.
1326
			'DE', // Germany.
1327
			'AT', // Austria.
1328
		);
1329 1
		return in_array( $country_code, $supported_countries, true );
1330
	}
1331
1332
	/**
1333
	 * Is Square country supported
1334
	 *
1335
	 * @param string $country_code Country code.
1336
	 */
1337 1
	protected function is_square_supported_country( $country_code ) {
1338
		$square_supported_countries = array(
1339 1
			'US',
1340
			'CA',
1341
			'JP',
1342
			'GB',
1343
			'AU',
1344
		);
1345 1
		return in_array( $country_code, $square_supported_countries, true );
1346
	}
1347
1348
	/**
1349
	 * Is eWAY Payments country supported
1350
	 *
1351
	 * @param string $country_code Country code.
1352
	 */
1353 1
	protected function is_eway_payments_supported_country( $country_code ) {
1354
		$supported_countries = array(
1355 1
			'AU', // Australia.
1356
			'NZ', // New Zealand.
1357
		);
1358 1
		return in_array( $country_code, $supported_countries, true );
1359
	}
1360
1361
	/**
1362
	 * Is ShipStation country supported
1363
	 *
1364
	 * @param string $country_code Country code.
1365
	 */
1366
	protected function is_shipstation_supported_country( $country_code ) {
1367
		$supported_countries = array(
1368
			'AU', // Australia.
1369
			'CA', // Canada.
1370
			'GB', // United Kingdom.
1371
		);
1372
		return in_array( $country_code, $supported_countries, true );
1373
	}
1374
1375
	/**
1376
	 * Is WooCommerce Services shipping label country supported
1377
	 *
1378
	 * @param string $country_code Country code.
1379
	 */
1380
	protected function is_wcs_shipping_labels_supported_country( $country_code ) {
1381
		$supported_countries = array(
1382
			'US', // United States.
1383
		);
1384
		return in_array( $country_code, $supported_countries, true );
1385
	}
1386
1387
	/**
1388
	 * Helper method to retrieve the current user's email address.
1389
	 *
1390
	 * @return string Email address
1391
	 */
1392 1
	protected function get_current_user_email() {
1393 1
		$current_user = wp_get_current_user();
1394 1
		$user_email   = $current_user->user_email;
1395
1396 1
		return $user_email;
1397
	}
1398
1399
	/**
1400
	 * Array of all possible "in cart" gateways that can be offered.
1401
	 *
1402
	 * @return array
1403
	 */
1404 1
	protected function get_wizard_available_in_cart_payment_gateways() {
1405 1
		$user_email = $this->get_current_user_email();
1406
1407 1
		$stripe_description = '<p>' . sprintf(
1408
			/* translators: %s: URL */
1409 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' ),
1410 1
			'https://woocommerce.com/products/stripe/'
1411 1
		) . '</p>';
1412 1
		$paypal_checkout_description = '<p>' . sprintf(
1413
			/* translators: %s: URL */
1414 1
			__( 'Safe and secure payments using credit cards or your customer\'s PayPal account. <a href="%s" target="_blank">Learn more</a>.', 'woocommerce' ),
1415 1
			'https://woocommerce.com/products/woocommerce-gateway-paypal-checkout/'
1416 1
		) . '</p>';
1417 1
		$klarna_checkout_description = '<p>' . sprintf(
1418
			/* translators: %s: URL */
1419 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' ),
1420 1
			'https://woocommerce.com/products/klarna-checkout/'
1421 1
		) . '</p>';
1422 1
		$klarna_payments_description = '<p>' . sprintf(
1423
			/* translators: %s: URL */
1424 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' ),
1425 1
			'https://woocommerce.com/products/klarna-payments/ '
1426 1
		) . '</p>';
1427 1
		$square_description = '<p>' . sprintf(
1428
			/* translators: %s: URL */
1429 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' ),
1430 1
			'https://woocommerce.com/products/square/'
1431 1
		) . '</p>';
1432
1433
		return array(
1434
			'stripe'          => array(
1435 1
				'name'        => __( 'WooCommerce Stripe Gateway', 'woocommerce' ),
1436 1
				'image'       => WC()->plugin_url() . '/assets/images/stripe.png',
1437 1
				'description' => $stripe_description,
1438 1
				'class'       => 'checked stripe-logo',
1439 1
				'repo-slug'   => 'woocommerce-gateway-stripe',
1440
				'settings'    => array(
1441
					'create_account' => array(
1442 1
						'label'       => __( 'Set up Stripe for me using this email:', 'woocommerce' ),
1443 1
						'type'        => 'checkbox',
1444 1
						'value'       => 'yes',
1445 1
						'default'     => 'yes',
1446 1
						'placeholder' => '',
1447
						'required'    => false,
1448 1
						'plugins'     => $this->get_wcs_requisite_plugins(),
1449
					),
1450
					'email'          => array(
1451 1
						'label'       => __( 'Stripe email address:', 'woocommerce' ),
1452 1
						'type'        => 'email',
1453 1
						'value'       => $user_email,
1454 1
						'placeholder' => __( 'Stripe email address', 'woocommerce' ),
1455
						'required'    => true,
1456
					),
1457
				),
1458
			),
1459
			'ppec_paypal'     => array(
1460 1
				'name'        => __( 'WooCommerce PayPal Checkout Gateway', 'woocommerce' ),
1461 1
				'image'       => WC()->plugin_url() . '/assets/images/paypal.png',
1462 1
				'description' => $paypal_checkout_description,
1463
				'enabled'     => false,
1464 1
				'class'       => 'checked paypal-logo',
1465 1
				'repo-slug'   => 'woocommerce-gateway-paypal-express-checkout',
1466
				'settings'    => array(
1467
					'reroute_requests' => array(
1468 1
						'label'       => __( 'Set up PayPal for me using this email:', 'woocommerce' ),
1469 1
						'type'        => 'checkbox',
1470 1
						'value'       => 'yes',
1471 1
						'default'     => 'yes',
1472 1
						'placeholder' => '',
1473
						'required'    => false,
1474 1
						'plugins'     => $this->get_wcs_requisite_plugins(),
1475
					),
1476
					'email'            => array(
1477 1
						'label'       => __( 'Direct payments to email address:', 'woocommerce' ),
1478 1
						'type'        => 'email',
1479 1
						'value'       => $user_email,
1480 1
						'placeholder' => __( 'Email address to receive payments', 'woocommerce' ),
1481
						'required'    => true,
1482
					),
1483
				),
1484
			),
1485
			'paypal'          => array(
1486 1
				'name'        => __( 'PayPal Standard', 'woocommerce' ),
1487 1
				'description' => __( 'Accept payments via PayPal using account balance or credit card.', 'woocommerce' ),
1488 1
				'image'       => '',
1489
				'settings'    => array(
1490
					'email' => array(
1491 1
						'label'       => __( 'PayPal email address:', 'woocommerce' ),
1492 1
						'type'        => 'email',
1493 1
						'value'       => $user_email,
1494 1
						'placeholder' => __( 'PayPal email address', 'woocommerce' ),
1495
						'required'    => true,
1496
					),
1497
				),
1498
			),
1499
			'klarna_checkout' => array(
1500 1
				'name'        => __( 'Klarna Checkout for WooCommerce', 'woocommerce' ),
1501 1
				'description' => $klarna_checkout_description,
1502 1
				'image'       => WC()->plugin_url() . '/assets/images/klarna-black.png',
1503
				'enabled'     => true,
1504 1
				'class'       => 'klarna-logo',
1505 1
				'repo-slug'   => 'klarna-checkout-for-woocommerce',
1506
			),
1507
			'klarna_payments' => array(
1508 1
				'name'        => __( 'Klarna Payments for WooCommerce', 'woocommerce' ),
1509 1
				'description' => $klarna_payments_description,
1510 1
				'image'       => WC()->plugin_url() . '/assets/images/klarna-black.png',
1511
				'enabled'     => true,
1512 1
				'class'       => 'klarna-logo',
1513 1
				'repo-slug'   => 'klarna-payments-for-woocommerce',
1514
			),
1515
			'square'          => array(
1516 1
				'name'        => __( 'WooCommerce Square', 'woocommerce' ),
1517 1
				'description' => $square_description,
1518 1
				'image'       => WC()->plugin_url() . '/assets/images/square-black.png',
1519 1
				'class'       => 'square-logo',
1520
				'enabled'     => false,
1521 1
				'repo-slug'   => 'woocommerce-square',
1522
			),
1523
			'eway'            => array(
1524 1
				'name'        => __( 'WooCommerce eWAY Gateway', 'woocommerce' ),
1525 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' ),
1526 1
				'image'       => WC()->plugin_url() . '/assets/images/eway-logo.jpg',
1527
				'enabled'     => false,
1528 1
				'class'       => 'eway-logo',
1529 1
				'repo-slug'   => 'woocommerce-gateway-eway',
1530
			),
1531
			'payfast'         => array(
1532 1
				'name'        => __( 'WooCommerce PayFast Gateway', 'woocommerce' ),
1533 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' ),
1534 1
				'image'       => WC()->plugin_url() . '/assets/images/payfast.png',
1535 1
				'class'       => 'payfast-logo',
1536
				'enabled'     => false,
1537 1
				'repo-slug'   => 'woocommerce-payfast-gateway',
1538 1
				'file'        => 'gateway-payfast.php',
1539
			),
1540
		);
1541
	}
1542
1543
	/**
1544
	 * Simple array of "in cart" gateways to show in wizard.
1545
	 *
1546
	 * @return array
1547
	 */
1548 1
	public function get_wizard_in_cart_payment_gateways() {
1549 1
		$gateways = $this->get_wizard_available_in_cart_payment_gateways();
1550 1
		$country  = WC()->countries->get_base_country();
1551 1
		$currency = get_woocommerce_currency();
1552
1553 1
		$can_stripe  = $this->is_stripe_supported_country( $country );
1554 1
		$can_eway    = $this->is_eway_payments_supported_country( $country );
1555 1
		$can_payfast = ( 'ZA' === $country ); // South Africa.
1556 1
		$can_paypal  = $this->is_paypal_supported_currency( $currency );
1557
1558 1
		if ( ! current_user_can( 'install_plugins' ) ) {
1559 1
			return $can_paypal ? array( 'paypal' => $gateways['paypal'] ) : array();
1560
		}
1561
1562 1
		$klarna_or_square = false;
1563
1564 1
		if ( $this->is_klarna_checkout_supported_country( $country ) ) {
1565 1
			$klarna_or_square = 'klarna_checkout';
1566 1
		} elseif ( $this->is_klarna_payments_supported_country( $country ) ) {
1567 1
			$klarna_or_square = 'klarna_payments';
1568 1
		} elseif ( $this->is_square_supported_country( $country ) && get_option( 'woocommerce_sell_in_person' ) ) {
1569 1
			$klarna_or_square = 'square';
1570
		}
1571
1572 1
		$offered_gateways = array();
1573
1574 1
		if ( $can_stripe ) {
1575 1
			$gateways['stripe']['enabled']  = true;
1576 1
			$gateways['stripe']['featured'] = true;
1577 1
			$offered_gateways              += array( 'stripe' => $gateways['stripe'] );
1578 1
		} elseif ( $can_paypal ) {
1579 1
			$gateways['ppec_paypal']['enabled'] = true;
1580
		}
1581
1582 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...
1583 1
			if ( in_array( $klarna_or_square, array( 'klarna_checkout', 'klarna_payments' ), true ) ) {
1584 1
				$gateways[ $klarna_or_square ]['enabled']  = true;
1585 1
				$gateways[ $klarna_or_square ]['featured'] = false;
1586
				$offered_gateways                          += array(
1587 1
					$klarna_or_square => $gateways[ $klarna_or_square ],
1588
				);
1589
			} else {
1590
				$offered_gateways += array(
1591 1
					$klarna_or_square => $gateways[ $klarna_or_square ],
1592
				);
1593
			}
1594
		}
1595
1596 1
		if ( $can_paypal ) {
1597 1
			$offered_gateways += array( 'ppec_paypal' => $gateways['ppec_paypal'] );
1598
		}
1599
1600 1
		if ( $can_eway ) {
1601
			$offered_gateways += array( 'eway' => $gateways['eway'] );
1602
		}
1603
1604 1
		if ( $can_payfast ) {
1605
			$offered_gateways += array( 'payfast' => $gateways['payfast'] );
1606
		}
1607
1608 1
		return $offered_gateways;
1609
	}
1610
1611
	/**
1612
	 * Simple array of "manual" gateways to show in wizard.
1613
	 *
1614
	 * @return array
1615
	 */
1616
	public function get_wizard_manual_payment_gateways() {
1617
		$gateways = array(
1618
			'cheque' => array(
1619
				'name'        => _x( 'Check payments', 'Check payment method', 'woocommerce' ),
1620
				'description' => __( 'A simple offline gateway that lets you accept a check as method of payment.', 'woocommerce' ),
1621
				'image'       => '',
1622
				'class'       => '',
1623
			),
1624
			'bacs'   => array(
1625
				'name'        => __( 'Bank transfer (BACS) payments', 'woocommerce' ),
1626
				'description' => __( 'A simple offline gateway that lets you accept BACS payment.', 'woocommerce' ),
1627
				'image'       => '',
1628
				'class'       => '',
1629
			),
1630
			'cod'    => array(
1631
				'name'        => __( 'Cash on delivery', 'woocommerce' ),
1632
				'description' => __( 'A simple offline gateway that lets you accept cash on delivery.', 'woocommerce' ),
1633
				'image'       => '',
1634
				'class'       => '',
1635
			),
1636
		);
1637
1638
		return $gateways;
1639
	}
1640
1641
	/**
1642
	 * Display service item in list.
1643
	 *
1644
	 * @param int   $item_id Item ID.
1645
	 * @param array $item_info Item info array.
1646
	 */
1647
	public function display_service_item( $item_id, $item_info ) {
1648
		$item_class = 'wc-wizard-service-item';
1649
		if ( isset( $item_info['class'] ) ) {
1650
			$item_class .= ' ' . $item_info['class'];
1651
		}
1652
1653
		$previously_saved_settings = get_option( 'woocommerce_' . $item_id . '_settings' );
1654
1655
		// Show the user-saved state if it was previously saved.
1656
		// Otherwise, rely on the item info.
1657
		if ( is_array( $previously_saved_settings ) ) {
1658
			$should_enable_toggle = ( isset( $previously_saved_settings['enabled'] ) && 'yes' === $previously_saved_settings['enabled'] ) ? true : ( isset( $item_info['enabled'] ) && $item_info['enabled'] );
1659
		} else {
1660
			$should_enable_toggle = isset( $item_info['enabled'] ) && $item_info['enabled'];
1661
		}
1662
1663
		$plugins = null;
1664
		if ( isset( $item_info['repo-slug'] ) ) {
1665
			$plugin  = array(
1666
				'slug' => $item_info['repo-slug'],
1667
				'name' => $item_info['name'],
1668
			);
1669
			$plugins = array( $plugin );
1670
		}
1671
1672
		?>
1673
		<li class="<?php echo esc_attr( $item_class ); ?>">
1674
			<div class="wc-wizard-service-name">
1675 View Code Duplication
				<?php if ( ! empty( $item_info['image'] ) ) : ?>
1676
					<img src="<?php echo esc_attr( $item_info['image'] ); ?>" alt="<?php echo esc_attr( $item_info['name'] ); ?>" />
1677
				<?php else : ?>
1678
					<p><?php echo esc_html( $item_info['name'] ); ?></p>
1679
				<?php endif; ?>
1680
			</div>
1681
			<div class="wc-wizard-service-enable">
1682
				<span class="wc-wizard-service-toggle <?php echo esc_attr( $should_enable_toggle ? '' : 'disabled' ); ?>" tabindex="0">
1683
					<input
1684
						id="wc-wizard-service-<?php echo esc_attr( $item_id ); ?>"
1685
						type="checkbox"
1686
						name="wc-wizard-service-<?php echo esc_attr( $item_id ); ?>-enabled"
1687
						value="yes" <?php checked( $should_enable_toggle ); ?>
1688
						data-plugins="<?php echo wc_esc_json( wp_json_encode( $plugins ) ); ?>"
1689
					/>
1690
					<label for="wc-wizard-service-<?php echo esc_attr( $item_id ); ?>">
1691
				</span>
1692
			</div>
1693
			<div class="wc-wizard-service-description">
1694
				<?php echo wp_kses_post( wpautop( $item_info['description'] ) ); ?>
1695
				<?php if ( ! empty( $item_info['settings'] ) ) : ?>
1696
					<div class="wc-wizard-service-settings <?php echo $should_enable_toggle ? '' : 'hide'; ?>">
1697
						<?php foreach ( $item_info['settings'] as $setting_id => $setting ) : ?>
1698
							<?php
1699
							$is_checkbox = 'checkbox' === $setting['type'];
1700
1701
							if ( $is_checkbox ) {
1702
								$checked = false;
1703
								if ( isset( $previously_saved_settings[ $setting_id ] ) ) {
1704
									$checked = 'yes' === $previously_saved_settings[ $setting_id ];
1705
								} elseif ( false === $previously_saved_settings && isset( $setting['default'] ) ) {
1706
									$checked = 'yes' === $setting['default'];
1707
								}
1708
							}
1709
							if ( 'email' === $setting['type'] ) {
1710
								$value = empty( $previously_saved_settings[ $setting_id ] )
1711
									? $setting['value']
1712
									: $previously_saved_settings[ $setting_id ];
1713
							}
1714
							?>
1715
							<?php $input_id = $item_id . '_' . $setting_id; ?>
1716
							<div class="<?php echo esc_attr( 'wc-wizard-service-setting-' . $input_id ); ?>">
1717
								<label
1718
									for="<?php echo esc_attr( $input_id ); ?>"
1719
									class="<?php echo esc_attr( $input_id ); ?>"
1720
								>
1721
									<?php echo esc_html( $setting['label'] ); ?>
1722
								</label>
1723
								<input
1724
									type="<?php echo esc_attr( $setting['type'] ); ?>"
1725
									id="<?php echo esc_attr( $input_id ); ?>"
1726
									class="<?php echo esc_attr( 'payment-' . $setting['type'] . '-input' ); ?>"
1727
									name="<?php echo esc_attr( $input_id ); ?>"
1728
									value="<?php echo esc_attr( isset( $value ) ? $value : $setting['value'] ); ?>"
1729
									placeholder="<?php echo esc_attr( $setting['placeholder'] ); ?>"
1730
									<?php echo ( $setting['required'] ) ? 'required' : ''; ?>
1731
									<?php echo $is_checkbox ? checked( isset( $checked ) && $checked, true, false ) : ''; ?>
1732
									data-plugins="<?php echo wc_esc_json( wp_json_encode( isset( $setting['plugins'] ) ? $setting['plugins'] : null ) ); ?>"
1733
								/>
1734
								<?php if ( ! empty( $setting['description'] ) ) : ?>
1735
									<span class="wc-wizard-service-settings-description"><?php echo esc_html( $setting['description'] ); ?></span>
1736
								<?php endif; ?>
1737
							</div>
1738
						<?php endforeach; ?>
1739
					</div>
1740
				<?php endif; ?>
1741
			</div>
1742
		</li>
1743
		<?php
1744
	}
1745
1746
	/**
1747
	 * Is it a featured service?
1748
	 *
1749
	 * @param array $service Service info array.
1750
	 * @return boolean
1751
	 */
1752
	public function is_featured_service( $service ) {
1753
		return ! empty( $service['featured'] );
1754
	}
1755
1756
	/**
1757
	 * Is this a non featured service?
1758
	 *
1759
	 * @param array $service Service info array.
1760
	 * @return boolean
1761
	 */
1762
	public function is_not_featured_service( $service ) {
1763
		return ! $this->is_featured_service( $service );
1764
	}
1765
1766
	/**
1767
	 * Payment Step.
1768
	 */
1769
	public function wc_setup_payment() {
1770
		$featured_gateways = array_filter( $this->get_wizard_in_cart_payment_gateways(), array( $this, 'is_featured_service' ) );
1771
		$in_cart_gateways  = array_filter( $this->get_wizard_in_cart_payment_gateways(), array( $this, 'is_not_featured_service' ) );
1772
		$manual_gateways   = $this->get_wizard_manual_payment_gateways();
1773
		?>
1774
		<h1><?php esc_html_e( 'Payment', 'woocommerce' ); ?></h1>
1775
		<form method="post" class="wc-wizard-payment-gateway-form">
1776
			<p>
1777
				<?php
1778
				printf(
1779
					wp_kses(
1780
						/* translators: %s: Link */
1781
						__( 'WooCommerce can accept both online and offline payments. <a href="%s" target="_blank">Additional payment methods</a> can be installed later.', 'woocommerce' ),
1782
						array(
1783
							'a' => array(
1784
								'href'   => array(),
1785
								'target' => array(),
1786
							),
1787
						)
1788
					),
1789
					esc_url( admin_url( 'admin.php?page=wc-addons&section=payment-gateways' ) )
1790
				);
1791
				?>
1792
			</p>
1793
			<?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...
1794
			<ul class="wc-wizard-services featured">
1795
				<?php
1796
				foreach ( $featured_gateways as $gateway_id => $gateway ) {
1797
					$this->display_service_item( $gateway_id, $gateway );
1798
				}
1799
				?>
1800
			</ul>
1801
			<?php endif; ?>
1802
			<?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...
1803
			<ul class="wc-wizard-services in-cart">
1804
				<?php
1805
				foreach ( $in_cart_gateways as $gateway_id => $gateway ) {
1806
					$this->display_service_item( $gateway_id, $gateway );
1807
				}
1808
				?>
1809
			</ul>
1810
			<?php endif; ?>
1811
			<ul class="wc-wizard-services manual">
1812
				<li class="wc-wizard-services-list-toggle closed">
1813
					<div class="wc-wizard-service-name">
1814
						<?php esc_html_e( 'Offline Payments', 'woocommerce' ); ?>
1815
					</div>
1816
					<div class="wc-wizard-service-description">
1817
						<?php esc_html_e( 'Collect payments from customers offline.', 'woocommerce' ); ?>
1818
					</div>
1819
					<div class="wc-wizard-service-enable" tabindex="0">
1820
						<input class="wc-wizard-service-list-toggle" id="wc-wizard-service-list-toggle" type="checkbox">
1821
						<label for="wc-wizard-service-list-toggle"></label>
1822
					</div>
1823
				</li>
1824
				<?php
1825
				foreach ( $manual_gateways as $gateway_id => $gateway ) {
1826
					$this->display_service_item( $gateway_id, $gateway );
1827
				}
1828
				?>
1829
			</ul>
1830
			<p class="wc-setup-actions step">
1831
				<?php $this->plugin_install_info(); ?>
1832
				<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>
1833
				<?php wp_nonce_field( 'wc-setup' ); ?>
1834
			</p>
1835
		</form>
1836
		<?php
1837
	}
1838
1839
	/**
1840
	 * Payment Step save.
1841
	 */
1842
	public function wc_setup_payment_save() {
1843
		check_admin_referer( 'wc-setup' );
1844
1845
		if (
1846
			(
1847
				// Install WooCommerce Services with Stripe to enable deferred account creation.
1848
				! empty( $_POST['wc-wizard-service-stripe-enabled'] ) && // WPCS: CSRF ok, input var ok.
1849
				! empty( $_POST['stripe_create_account'] ) // WPCS: CSRF ok, input var ok.
1850
			) || (
1851
				// Install WooCommerce Services with PayPal EC to enable proxied payments.
1852
				! empty( $_POST['wc-wizard-service-ppec_paypal-enabled'] ) && // WPCS: CSRF ok, input var ok.
1853
				! empty( $_POST['ppec_paypal_reroute_requests'] ) // WPCS: CSRF ok, input var ok.
1854
			)
1855
		) {
1856
			$this->install_woocommerce_services();
1857
		}
1858
1859
		$gateways = array_merge( $this->get_wizard_in_cart_payment_gateways(), $this->get_wizard_manual_payment_gateways() );
1860
1861
		foreach ( $gateways as $gateway_id => $gateway ) {
1862
			// If repo-slug is defined, download and install plugin from .org.
1863
			if ( ! empty( $gateway['repo-slug'] ) && ! empty( $_POST[ 'wc-wizard-service-' . $gateway_id . '-enabled' ] ) ) { // WPCS: CSRF ok, input var ok.
1864
				$this->install_plugin( $gateway_id, $gateway );
1865
			}
1866
1867
			$settings = array( 'enabled' => ! empty( $_POST[ 'wc-wizard-service-' . $gateway_id . '-enabled' ] ) ? 'yes' : 'no' );  // WPCS: CSRF ok, input var ok.
1868
1869
			// @codingStandardsIgnoreStart
1870
			if ( ! empty( $gateway['settings'] ) ) {
1871
				foreach ( $gateway['settings'] as $setting_id => $setting ) {
1872
					$settings[ $setting_id ] = 'yes' === $settings['enabled'] && isset( $_POST[ $gateway_id . '_' . $setting_id ] )
1873
						? wc_clean( wp_unslash( $_POST[ $gateway_id . '_' . $setting_id ] ) )
1874
						: false;
1875
				}
1876
			}
1877
			// @codingStandardsIgnoreSEnd
1878
1879
			if ( 'ppec_paypal' === $gateway_id && empty( $settings['reroute_requests'] ) ) {
1880
				unset( $settings['enabled'] );
1881
			}
1882
1883
			$settings_key = 'woocommerce_' . $gateway_id . '_settings';
1884
			$previously_saved_settings = array_filter( (array) get_option( $settings_key, array() ) );
1885
			update_option( $settings_key, array_merge( $previously_saved_settings, $settings ) );
1886
		}
1887
1888
		wp_redirect( esc_url_raw( $this->get_next_step_link() ) );
1889
		exit;
1890
	}
1891
1892
	protected function display_recommended_item( $item_info ) {
1893
		$type        = $item_info['type'];
1894
		$title       = $item_info['title'];
1895
		$description = $item_info['description'];
1896
		$img_url     = $item_info['img_url'];
1897
		$img_alt     = $item_info['img_alt'];
1898
		?>
1899
		<li class="recommended-item checkbox">
1900
			<input
1901
				id="<?php echo esc_attr( 'wc_recommended_' . $type ); ?>"
1902
				type="checkbox"
1903
				name="<?php echo esc_attr( 'setup_' . $type ); ?>"
1904
				value="yes"
1905
				checked
1906
				data-plugins="<?php echo wc_esc_json( wp_json_encode( isset( $item_info['plugins'] ) ? $item_info['plugins'] : null ) ); ?>"
1907
			/>
1908
			<label for="<?php echo esc_attr( 'wc_recommended_' . $type ); ?>">
1909
				<img
1910
					src="<?php echo esc_url( $img_url ); ?>"
1911
					class="<?php echo esc_attr( 'recommended-item-icon-' . $type ); ?> recommended-item-icon"
1912
					alt="<?php echo esc_attr( $img_alt ); ?>" />
1913
				<div class="recommended-item-description-container">
1914
					<h3><?php echo esc_html( $title ); ?></h3>
1915
					<p><?php echo wp_kses( $description, array(
1916
						'a' => array(
1917
							'href'   => array(),
1918
							'target' => array(),
1919
							'rel'    => array(),
1920
						),
1921
						'em' => array(),
1922
					) ); ?></p>
1923
				</div>
1924
			</label>
1925
		</li>
1926
		<?php
1927
	}
1928
1929
	/**
1930
	 * Recommended step
1931
	 */
1932
	public function wc_setup_recommended() {
1933
		?>
1934
		<h1><?php esc_html_e( 'Recommended for All WooCommerce Stores', 'woocommerce' ); ?></h1>
1935
		<p>
1936
			<?php esc_html_e( 'Enhance your store with these recommended free features.', 'woocommerce' ); ?>
1937
		</p>
1938
		<form method="post">
1939
			<ul class="recommended-step">
1940
				<?php
1941
				if ( $this->should_show_theme() ) :
1942
					$theme      = wp_get_theme();
1943
					$theme_name = $theme['Name'];
1944
					$this->display_recommended_item( array(
1945
						'type'        => 'storefront_theme',
1946
						'title'       => __( 'Storefront Theme', 'woocommerce' ),
1947
						'description' => sprintf( __(
1948
								'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' ),
1949
								$theme_name
1950
						),
1951
						'img_url'     => WC()->plugin_url() . '/assets/images/obw-storefront-icon.svg',
1952
						'img_alt'     => __( 'Storefront icon', 'woocommerce' ),
1953
					) );
1954
				endif;
1955
1956
				if ( $this->should_show_automated_tax() ) :
1957
					$this->display_recommended_item( array(
1958
						'type'        => 'automated_taxes',
1959
						'title'       => __( 'Automated Taxes', 'woocommerce' ),
1960
						'description' => __( 'Save time and errors with automated tax calculation and collection at checkout. Powered by WooCommerce Services and Jetpack.', 'woocommerce' ),
1961
						'img_url'     => WC()->plugin_url() . '/assets/images/obw-taxes-icon.svg',
1962
						'img_alt'     => __( 'automated taxes icon', 'woocommerce' ),
1963
						'plugins'     => $this->get_wcs_requisite_plugins(),
1964
					) );
1965
				endif;
1966
1967 View Code Duplication
				if ( $this->should_show_wc_admin() ) :
1968
					$this->display_recommended_item( array(
1969
						'type'        => 'wc_admin',
1970
						'title'       => __( 'WooCommerce Admin', 'woocommerce' ),
1971
						'description' => __( 'Manage your store\'s reports and monitor key metrics with a new and improved interface and dashboard.', 'woocommerce' ),
1972
						'img_url'     => WC()->plugin_url() . '/assets/images/obw-woocommerce-admin-icon.svg',
1973
						'img_alt'     => __( 'WooCommerce Admin icon', 'woocommerce' ),
1974
						'plugins'     => array( array( 'name' => __( 'WooCommerce Admin', 'woocommerce' ), 'slug' => 'woocommerce-admin' ) ),
1975
					) );
1976
				endif;
1977
1978 View Code Duplication
				if ( $this->should_show_mailchimp() ) :
1979
					$this->display_recommended_item( array(
1980
						'type'        => 'mailchimp',
1981
						'title'       => __( 'Mailchimp', 'woocommerce' ),
1982
						'description' => __( 'Join the 16 million customers who use Mailchimp. Sync list and store data to send automated emails, and targeted campaigns.', 'woocommerce' ),
1983
						'img_url'     => WC()->plugin_url() . '/assets/images/obw-mailchimp-icon.svg',
1984
						'img_alt'     => __( 'Mailchimp icon', 'woocommerce' ),
1985
						'plugins'     => array( array( 'name' => __( 'Mailchimp for WooCommerce', 'woocommerce' ), 'slug' => 'mailchimp-for-woocommerce' ) ),
1986
					) );
1987
				endif;
1988
1989 View Code Duplication
				if ( $this->should_show_facebook() ) :
1990
					$this->display_recommended_item( array(
1991
						'type'        => 'facebook',
1992
						'title'       => __( 'Facebook', 'woocommerce' ),
1993
						'description' => __( 'Enjoy all Facebook products combined in one extension: pixel tracking, catalog sync, messenger chat, shop functionality and Instagram shopping (coming soon)!', 'woocommerce' ),
1994
						'img_url'     => WC()->plugin_url() . '/assets/images/obw-facebook-icon.svg',
1995
						'img_alt'     => __( 'Facebook icon', 'woocommerce' ),
1996
						'plugins'     => array( array( 'name' => __( 'Facebook for WooCommerce', 'woocommerce' ), 'slug' => 'facebook-for-woocommerce' ) ),
1997
					) );
1998
				endif;
1999
			?>
2000
		</ul>
2001
			<p class="wc-setup-actions step">
2002
				<?php $this->plugin_install_info(); ?>
2003
				<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>
2004
				<?php wp_nonce_field( 'wc-setup' ); ?>
2005
			</p>
2006
		</form>
2007
		<?php
2008
	}
2009
2010
	/**
2011
	 * Recommended step save.
2012
	 */
2013
	public function wc_setup_recommended_save() {
2014
		check_admin_referer( 'wc-setup' );
2015
2016
		$setup_storefront       = isset( $_POST['setup_storefront_theme'] ) && 'yes' === $_POST['setup_storefront_theme'];
2017
		$setup_automated_tax    = isset( $_POST['setup_automated_taxes'] ) && 'yes' === $_POST['setup_automated_taxes'];
2018
		$setup_mailchimp        = isset( $_POST['setup_mailchimp'] ) && 'yes' === $_POST['setup_mailchimp'];
2019
		$setup_facebook         = isset( $_POST['setup_facebook'] ) && 'yes' === $_POST['setup_facebook'];
2020
		$setup_wc_admin         = isset( $_POST['setup_wc_admin'] ) && 'yes' === $_POST['setup_wc_admin'];
2021
2022
		update_option( 'woocommerce_calc_taxes', $setup_automated_tax ? 'yes' : 'no' );
2023
		update_option( 'woocommerce_setup_automated_taxes', $setup_automated_tax );
2024
2025
		if ( $setup_storefront ) {
2026
			$this->install_theme( 'storefront' );
2027
		}
2028
2029
		if ( $setup_automated_tax ) {
2030
			$this->install_woocommerce_services();
2031
		}
2032
2033
		if ( $setup_mailchimp ) {
2034
			// Prevent MailChimp from redirecting to its settings page during the OBW flow.
2035
			add_option( 'mailchimp_woocommerce_plugin_do_activation_redirect', false );
2036
2037
			$this->install_plugin(
2038
				'mailchimp-for-woocommerce',
2039
				array(
2040
					'name'      => __( 'MailChimp for WooCommerce', 'woocommerce' ),
2041
					'repo-slug' => 'mailchimp-for-woocommerce',
2042
					'file'      => 'mailchimp-woocommerce.php',
2043
				)
2044
			);
2045
		}
2046
2047
		if ( $setup_facebook ) {
2048
			$this->install_plugin(
2049
				'facebook-for-woocommerce',
2050
				array(
2051
					'name'      => __( 'Facebook for WooCommerce', 'woocommerce' ),
2052
					'repo-slug' => 'facebook-for-woocommerce',
2053
				)
2054
			);
2055
		}
2056
2057
		if ( $setup_wc_admin ) {
2058
			$this->install_plugin(
2059
				'woocommerce-admin',
2060
				array(
2061
					'name'      => __( 'WooCommerce Admin', 'woocommerce' ),
2062
					'repo-slug' => 'woocommerce-admin',
2063
				)
2064
			);
2065
		}
2066
2067
		wp_redirect( esc_url_raw( $this->get_next_step_link() ) );
2068
		exit;
2069
	}
2070
2071
	/**
2072
	 * Go to the next step if Jetpack was connected.
2073
	 */
2074
	protected function wc_setup_activate_actions() {
2075
		if (
2076
			isset( $_GET['from'] ) &&
2077
			'wpcom' === $_GET['from'] &&
2078
			class_exists( 'Jetpack' ) &&
2079
			Jetpack::is_active()
2080
		) {
2081
			wp_redirect( esc_url_raw( remove_query_arg( 'from', $this->get_next_step_link() ) ) );
2082
			exit;
2083
		}
2084
	}
2085
2086
	protected function wc_setup_activate_get_feature_list() {
2087
		$features = array();
2088
2089
		$stripe_settings = get_option( 'woocommerce_stripe_settings', false );
2090
		$stripe_enabled  = is_array( $stripe_settings )
2091
			&& isset( $stripe_settings['create_account'] ) && 'yes' === $stripe_settings['create_account']
2092
			&& isset( $stripe_settings['enabled'] ) && 'yes' === $stripe_settings['enabled'];
2093
		$ppec_settings   = get_option( 'woocommerce_ppec_paypal_settings', false );
2094
		$ppec_enabled    = is_array( $ppec_settings )
2095
			&& isset( $ppec_settings['reroute_requests'] ) && 'yes' === $ppec_settings['reroute_requests']
2096
			&& isset( $ppec_settings['enabled'] ) && 'yes' === $ppec_settings['enabled'];
2097
2098
		$features['payment'] = $stripe_enabled || $ppec_enabled;
2099
		$features['taxes']   = (bool) get_option( 'woocommerce_setup_automated_taxes', false );
2100
		$features['labels']  = (bool) get_option( 'woocommerce_setup_shipping_labels', false );
2101
2102
		return $features;
2103
	}
2104
2105
	protected function wc_setup_activate_get_feature_list_str() {
2106
		$features = $this->wc_setup_activate_get_feature_list();
2107
		if ( $features['payment'] && $features['taxes'] && $features['labels'] ) {
2108
			return __( 'payment setup, automated taxes and discounted shipping labels', 'woocommerce' );
2109
		} else if ( $features['payment'] && $features['taxes'] ) {
2110
			return __( 'payment setup and automated taxes', 'woocommerce' );
2111
		} else if ( $features['payment'] && $features['labels'] ) {
2112
			return __( 'payment setup and discounted shipping labels', 'woocommerce' );
2113
		} else if ( $features['payment'] ) {
2114
			return __( 'payment setup', 'woocommerce' );
2115
		} else if ( $features['taxes'] && $features['labels'] ) {
2116
			return __( 'automated taxes and discounted shipping labels', 'woocommerce' );
2117
		} else if ( $features['taxes'] ) {
2118
			return __( 'automated taxes', 'woocommerce' );
2119
		} else if ( $features['labels'] ) {
2120
			return __( 'discounted shipping labels', 'woocommerce' );
2121
		}
2122
		return false;
2123
	}
2124
2125
	/**
2126
	 * Activate step.
2127
	 */
2128
	public function wc_setup_activate() {
2129
		$this->wc_setup_activate_actions();
2130
2131
		$jetpack_connected = class_exists( 'Jetpack' ) && Jetpack::is_active();
2132
2133
		$has_jetpack_error = false;
2134
		if ( isset( $_GET['activate_error'] ) ) {
2135
			$has_jetpack_error = true;
2136
2137
			$title = __( "Sorry, we couldn't connect your store to Jetpack", 'woocommerce' );
2138
2139
			$error_message = $this->get_activate_error_message( sanitize_text_field( wp_unslash( $_GET['activate_error'] ) ) );
2140
			$description = $error_message;
2141
		} else {
2142
			$feature_list = $this->wc_setup_activate_get_feature_list_str();
2143
2144
			$description = false;
2145
2146
			if ( $feature_list ) {
2147
				if ( ! $jetpack_connected ) {
2148
					/* translators: %s: list of features, potentially comma separated */
2149
					$description_base = __( 'Your store is almost ready! To activate services like %s, just connect with Jetpack.', 'woocommerce' );
2150
				} else {
2151
					$description_base = __( 'Thanks for using Jetpack! Your store is almost ready: to activate services like %s, just connect your store.', 'woocommerce' );
2152
				}
2153
				$description = sprintf( $description_base, $feature_list );
2154
			}
2155
2156
			if ( ! $jetpack_connected ) {
2157
				$title = $feature_list ?
2158
					__( 'Connect your store to Jetpack', 'woocommerce' ) :
2159
					__( 'Connect your store to Jetpack to enable extra features', 'woocommerce' );
2160
				$button_text = __( 'Continue with Jetpack', 'woocommerce' );
2161
			} elseif ( $feature_list ) {
2162
				$title = __( 'Connect your store to activate WooCommerce Services', 'woocommerce' );
2163
				$button_text = __( 'Continue with WooCommerce Services', 'woocommerce' );
2164
			} else {
2165
				wp_redirect( esc_url_raw( $this->get_next_step_link() ) );
2166
				exit;
2167
			}
2168
		}
2169
		?>
2170
		<h1><?php echo esc_html( $title ); ?></h1>
2171
		<p><?php echo esc_html( $description ); ?></p>
2172
2173
		<?php if ( $jetpack_connected ) : ?>
2174
			<div class="activate-splash">
2175
				<img
2176
					class="jetpack-logo"
2177
					src="<?php echo esc_url( WC()->plugin_url() . '/assets/images/jetpack_horizontal_logo.png' ); ?>"
2178
					alt="<?php esc_attr_e( 'Jetpack logo', 'woocommerce' ); ?>"
2179
				/>
2180
				<img
2181
					class="wcs-notice"
2182
					src="<?php echo esc_url( WC()->plugin_url() . '/assets/images/wcs-notice.png' ); ?>"
2183
				/>
2184
			</div>
2185
		<?php else : ?>
2186
			<img
2187
				class="jetpack-logo"
2188
				src="<?php echo esc_url( WC()->plugin_url() . '/assets/images/jetpack_vertical_logo.png' ); ?>"
2189
				alt="<?php esc_attr_e( 'Jetpack logo', 'woocommerce' ); ?>"
2190
			/>
2191
		<?php endif; ?>
2192
2193
		<?php if ( $has_jetpack_error ) : ?>
2194
			<p class="wc-setup-actions step">
2195
				<a
2196
					href="<?php echo esc_url( $this->get_next_step_link() ); ?>"
2197
					class="button-primary button button-large"
2198
				>
2199
					<?php esc_html_e( 'Finish setting up your store', 'woocommerce' ); ?>
2200
				</a>
2201
			</p>
2202
		<?php else : ?>
2203
			<p class="jetpack-terms">
2204
				<?php
2205
					printf(
2206
						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' ) ),
2207
						'https://wordpress.com/tos',
2208
						'https://jetpack.com/support/what-data-does-jetpack-sync'
2209
					);
2210
				?>
2211
			</p>
2212
			<form method="post" class="activate-jetpack">
2213
				<p class="wc-setup-actions step">
2214
					<button type="submit" class="button-primary button button-large" value="<?php echo esc_attr( $button_text ); ?>"><?php echo esc_html( $button_text ); ?></button>
2215
				</p>
2216
				<input type="hidden" name="save_step" value="activate" />
2217
				<?php wp_nonce_field( 'wc-setup' ); ?>
2218
			</form>
2219
			<?php if ( ! $jetpack_connected ) : ?>
2220
				<h3 class="jetpack-reasons">
2221
					<?php
2222
						echo esc_html( $description ?
2223
							__( "Bonus reasons you'll love Jetpack", 'woocommerce' ) :
2224
							__( "Reasons you'll love Jetpack", 'woocommerce' )
2225
						);
2226
					?>
2227
				</h3>
2228
				<ul class="wc-wizard-features">
2229
					<li class="wc-wizard-feature-item">
2230
						<p class="wc-wizard-feature-name">
2231
							<strong><?php esc_html_e( 'Better security', 'woocommerce' ); ?></strong>
2232
						</p>
2233
						<p class="wc-wizard-feature-description">
2234
							<?php esc_html_e( 'Protect your store from unauthorized access.', 'woocommerce' ); ?>
2235
						</p>
2236
					</li>
2237
					<li class="wc-wizard-feature-item">
2238
						<p class="wc-wizard-feature-name">
2239
							<strong><?php esc_html_e( 'Store stats', 'woocommerce' ); ?></strong>
2240
						</p>
2241
						<p class="wc-wizard-feature-description">
2242
							<?php esc_html_e( 'Get insights on how your store is doing, including total sales, top products, and more.', 'woocommerce' ); ?>
2243
						</p>
2244
					</li>
2245
					<li class="wc-wizard-feature-item">
2246
						<p class="wc-wizard-feature-name">
2247
							<strong><?php esc_html_e( 'Store monitoring', 'woocommerce' ); ?></strong>
2248
						</p>
2249
						<p class="wc-wizard-feature-description">
2250
							<?php esc_html_e( 'Get an alert if your store is down for even a few minutes.', 'woocommerce' ); ?>
2251
						</p>
2252
					</li>
2253
					<li class="wc-wizard-feature-item">
2254
						<p class="wc-wizard-feature-name">
2255
							<strong><?php esc_html_e( 'Product promotion', 'woocommerce' ); ?></strong>
2256
						</p>
2257
						<p class="wc-wizard-feature-description">
2258
							<?php esc_html_e( "Share new items on social media the moment they're live in your store.", 'woocommerce' ); ?>
2259
						</p>
2260
					</li>
2261
				</ul>
2262
			<?php endif; ?>
2263
		<?php endif; ?>
2264
	<?php
2265
	}
2266
2267
	protected function get_all_activate_errors() {
2268
		return array(
2269
			'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' ),
2270
			'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' ),
2271
			'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' ),
2272
			'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' ),
2273
		);
2274
	}
2275
2276
	protected function get_activate_error_message( $code = '' ) {
2277
		$errors = $this->get_all_activate_errors();
2278
		return array_key_exists( $code, $errors ) ? $errors[ $code ] : $errors['default'];
2279
	}
2280
2281
	/**
2282
	 * Activate step save.
2283
	 *
2284
	 * Install, activate, and launch connection flow for Jetpack.
2285
	 */
2286
	public function wc_setup_activate_save() {
2287
		check_admin_referer( 'wc-setup' );
2288
2289
		set_transient( 'wc_setup_activated', 'yes', MINUTE_IN_SECONDS * 10 );
2290
2291
		// Leave a note for WooCommerce Services that Jetpack has been opted into.
2292
		update_option( 'woocommerce_setup_jetpack_opted_in', true );
2293
2294
		if ( class_exists( 'Jetpack' ) && Jetpack::is_active() ) {
2295
			wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) );
2296
			exit;
2297
		}
2298
2299
		WC_Install::background_installer( 'jetpack', array(
2300
			'name'      => __( 'Jetpack', 'woocommerce' ),
2301
			'repo-slug' => 'jetpack',
2302
		) );
2303
2304
		// Did Jetpack get successfully installed?
2305
		if ( ! class_exists( 'Jetpack' ) ) {
2306
			wp_redirect( esc_url_raw( add_query_arg( 'activate_error', 'jetpack_cant_be_installed' ) ) );
2307
			exit;
2308
		}
2309
2310
		Jetpack::maybe_set_version_option();
2311
		$register_result = Jetpack::try_registration();
2312
2313
		if ( is_wp_error( $register_result ) ) {
2314
			$result_error_code = $register_result->get_error_code();
2315
			$jetpack_error_code = array_key_exists( $result_error_code, $this->get_all_activate_errors() ) ? $result_error_code : 'register';
2316
			wp_redirect( esc_url_raw( add_query_arg( 'activate_error', $jetpack_error_code ) ) );
2317
			exit;
2318
		}
2319
2320
		$redirect_url = esc_url_raw( add_query_arg( array(
2321
			'page'           => 'wc-setup',
2322
			'step'           => 'activate',
2323
			'from'           => 'wpcom',
2324
			'activate_error' => false,
2325
		), admin_url() ) );
2326
		$connection_url = Jetpack::init()->build_connect_url( true, $redirect_url, 'woocommerce-setup-wizard' );
2327
2328
		wp_redirect( esc_url_raw( $connection_url ) );
2329
		exit;
2330
	}
2331
2332
	/**
2333
	 * Final step.
2334
	 */
2335
	public function wc_setup_ready() {
2336
		// We've made it! Don't prompt the user to run the wizard again.
2337
		WC_Admin_Notices::remove_notice( 'install' );
2338
2339
		$user_email   = $this->get_current_user_email();
2340
		$videos_url   = 'https://docs.woocommerce.com/document/woocommerce-guided-tour-videos/?utm_source=setupwizard&utm_medium=product&utm_content=videos&utm_campaign=woocommerceplugin';
2341
		$docs_url     = 'https://docs.woocommerce.com/documentation/plugins/woocommerce/getting-started/?utm_source=setupwizard&utm_medium=product&utm_content=docs&utm_campaign=woocommerceplugin';
2342
		$help_text    = sprintf(
2343
			/* translators: %1$s: link to videos, %2$s: link to docs */
2344
			__( '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' ),
2345
			$videos_url,
2346
			$docs_url
2347
		);
2348
		?>
2349
		<h1><?php esc_html_e( "You're ready to start selling!", 'woocommerce' ); ?></h1>
2350
2351
		<div class="woocommerce-message woocommerce-newsletter">
2352
			<p><?php esc_html_e( "We're here for you — get tips, product updates, and inspiration straight to your mailbox.", 'woocommerce' ); ?></p>
2353
			<form action="//woocommerce.us8.list-manage.com/subscribe/post?u=2c1434dc56f9506bf3c3ecd21&amp;id=13860df971&amp;SIGNUPPAGE=plugin" method="post" target="_blank" novalidate>
2354
				<div class="newsletter-form-container">
2355
					<input
2356
						class="newsletter-form-email"
2357
						type="email"
2358
						value="<?php echo esc_attr( $user_email ); ?>"
2359
						name="EMAIL"
2360
						placeholder="<?php esc_attr_e( 'Email address', 'woocommerce' ); ?>"
2361
						required
2362
					>
2363
					<p class="wc-setup-actions step newsletter-form-button-container">
2364
						<button
2365
							type="submit"
2366
							value="<?php esc_attr_e( 'Yes please!', 'woocommerce' ); ?>"
2367
							name="subscribe"
2368
							id="mc-embedded-subscribe"
2369
							class="button-primary button newsletter-form-button"
2370
						><?php esc_html_e( 'Yes please!', 'woocommerce' ); ?></button>
2371
					</p>
2372
				</div>
2373
			</form>
2374
		</div>
2375
2376
		<ul class="wc-wizard-next-steps">
2377
			<li class="wc-wizard-next-step-item">
2378
				<div class="wc-wizard-next-step-description">
2379
					<p class="next-step-heading"><?php esc_html_e( 'Next step', 'woocommerce' ); ?></p>
2380
					<h3 class="next-step-description"><?php esc_html_e( 'Create some products', 'woocommerce' ); ?></h3>
2381
					<p class="next-step-extra-info"><?php esc_html_e( "You're ready to add products to your store.", 'woocommerce' ); ?></p>
2382
				</div>
2383
				<div class="wc-wizard-next-step-action">
2384
					<p class="wc-setup-actions step">
2385
						<a class="button button-primary button-large" href="<?php echo esc_url( admin_url( 'post-new.php?post_type=product&tutorial=true' ) ); ?>">
2386
							<?php esc_html_e( 'Create a product', 'woocommerce' ); ?>
2387
						</a>
2388
					</p>
2389
				</div>
2390
			</li>
2391
			<li class="wc-wizard-next-step-item">
2392
				<div class="wc-wizard-next-step-description">
2393
					<p class="next-step-heading"><?php esc_html_e( 'Have an existing store?', 'woocommerce' ); ?></p>
2394
					<h3 class="next-step-description"><?php esc_html_e( 'Import products', 'woocommerce' ); ?></h3>
2395
					<p class="next-step-extra-info"><?php esc_html_e( 'Transfer existing products to your new store — just import a CSV file.', 'woocommerce' ); ?></p>
2396
				</div>
2397
				<div class="wc-wizard-next-step-action">
2398
					<p class="wc-setup-actions step">
2399
						<a class="button button-large" href="<?php echo esc_url( admin_url( 'edit.php?post_type=product&page=product_importer' ) ); ?>">
2400
							<?php esc_html_e( 'Import products', 'woocommerce' ); ?>
2401
						</a>
2402
					</p>
2403
				</div>
2404
			</li>
2405
			<li class="wc-wizard-additional-steps">
2406
				<div class="wc-wizard-next-step-description">
2407
					<p class="next-step-heading"><?php esc_html_e( 'You can also:', 'woocommerce' ); ?></p>
2408
				</div>
2409
				<div class="wc-wizard-next-step-action">
2410
					<p class="wc-setup-actions step">
2411
						<a class="button button-large" href="<?php echo esc_url( admin_url() ); ?>">
2412
							<?php esc_html_e( 'Visit Dashboard', 'woocommerce' ); ?>
2413
						</a>
2414
						<a class="button button-large" href="<?php echo esc_url( admin_url( 'admin.php?page=wc-settings' ) ); ?>">
2415
							<?php esc_html_e( 'Review Settings', 'woocommerce' ); ?>
2416
						</a>
2417
						<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' ) ) ); ?>">
2418
							<?php esc_html_e( 'View &amp; Customize', 'woocommerce' ); ?>
2419
						</a>
2420
					</p>
2421
				</div>
2422
			</li>
2423
		</ul>
2424
		<p class="next-steps-help-text"><?php echo wp_kses_post( $help_text ); ?></p>
2425
		<?php
2426
	}
2427
}
2428
2429
new WC_Admin_Setup_Wizard();
2430