PluginProbe ʕ •ᴥ•ʔ
WooCommerce Square / 4.8.0
WooCommerce Square v4.8.0
5.5.0 5.4.3 5.4.2 5.4.1 5.4.0 trunk 1.0.25 1.0.26 1.0.27 1.0.28 1.0.29 1.0.30 1.0.31 1.0.32 1.0.33 1.0.34 1.0.35 1.0.36 1.0.37 1.0.38 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.4.0 2.4.1 2.5.0 2.5.1 2.5.2 2.5.3 2.6.0 2.7.0 2.8.0 2.9.0 2.9.1 3.0.0 3.0.1 3.0.2 3.0.3 3.1.0 3.2.0 3.3.0 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.7.0 3.7.1 3.8.0 3.8.1 3.8.2 3.8.3 3.9.0 4.0.0 4.1.0 4.2.0 4.2.1 4.2.2 4.2.3 4.3.0 4.3.1 4.3.2 4.4.0 4.4.1 4.4.2 4.5.0 4.5.1 4.5.2 4.6.0 4.6.1 4.6.2 4.6.3 4.6.4 4.7.0 4.7.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.1 4.8.2 4.8.3 4.8.4 4.8.5 4.8.6 4.8.7 4.8.8 4.9.0 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 4.9.6 4.9.7 4.9.8 4.9.9 5.0.0 5.0.1 5.1.0 5.1.1 5.1.2 5.2.0 5.3.0 5.3.1 5.3.2 5.3.3
woocommerce-square / includes / Settings.php
woocommerce-square / includes Last commit date
API 2 years ago Admin 1 year ago Emails 2 years ago Framework 1 year ago Gateway 2 years ago Handlers 1 year ago Sync 1 year ago Utilities 2 years ago AJAX.php 2 years ago API.php 2 years ago Admin.php 2 years ago Functions.php 3 years ago Gateway.php 2 years ago Lifecycle.php 2 years ago Plugin.php 2 years ago Settings.php 2 years ago WC_Order_Square.php 2 years ago WC_Payments_Compatibility.php 2 years ago
Settings.php
1087 lines
1 <?php
2 /**
3 * WooCommerce Square
4 *
5 * This source file is subject to the GNU General Public License v3.0
6 * that is bundled with this package in the file license.txt.
7 * It is also available through the world-wide-web at this URL:
8 * http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0 or later
9 * If you did not receive a copy of the license and are unable to
10 * obtain it through the world-wide-web, please send an email
11 * to license@woocommerce.com so we can send you a copy immediately.
12 *
13 * DISCLAIMER
14 *
15 * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16 * versions in the future. If you wish to customize WooCommerce Square for your
17 * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18 *
19 * @author WooCommerce
20 * @copyright Copyright: (c) 2019, Automattic, Inc.
21 * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0 or later
22 */
23
24 namespace WooCommerce\Square;
25
26 use Exception;
27 use WooCommerce\Square\Framework\Square_Helper;
28
29 defined( 'ABSPATH' ) || exit;
30
31 /**
32 * The settings API class.
33 *
34 * This handles registering, getting, and storing the general plugin options.
35 *
36 * Note that this is separate from the gateway settings.
37 *
38 * @since 2.0.0
39 */
40 class Settings extends \WC_Settings_API {
41
42
43 /**
44 * Square Sync setting.
45 *
46 * @var string square Sync setting indicator
47 */
48 const SYSTEM_OF_RECORD_SQUARE = 'square';
49
50 /**
51 * Woocommerce Sync setting.
52 *
53 * @var string square Sync setting indicator
54 */
55 const SYSTEM_OF_RECORD_WOOCOMMERCE = 'woocommerce';
56
57 /**
58 * Disabled Sync setting.
59 *
60 * @var string Sync setting indicator for disabled sync
61 */
62 const SYSTEM_OF_RECORD_DISABLED = 'disabled';
63
64 /** Debug mode log to file */
65 const DEBUG_MODE_LOG = 'log';
66
67 /** Debug mode display on checkout */
68 const DEBUG_MODE_CHECKOUT = 'checkout';
69
70 /** Debug mode log to file and display on checkout */
71 const DEBUG_MODE_BOTH = 'both';
72
73 /** Debug mode disabled */
74 const DEBUG_MODE_OFF = 'off';
75
76 /**
77 * Refresh token
78 *
79 * @var string un-encrypted refresh token
80 */
81 protected $refresh_token;
82
83 /**
84 * Access token
85 *
86 * @var string un-encrypted access token
87 */
88 protected $access_token;
89
90 /**
91 * Square business locations
92 *
93 * @var array business locations returned by the API
94 */
95 protected $locations;
96
97 /**
98 * Square plugin instance
99 *
100 * @var Plugin plugin instance
101 */
102 protected $plugin;
103
104
105 /**
106 * Constructs the class.
107 *
108 * @since 2.0.0
109 *
110 * @param Plugin $plugin plugin instance.
111 */
112 public function __construct( Plugin $plugin ) {
113
114 $this->plugin = $plugin;
115 $this->plugin_id = 'wc_';
116 $this->id = $plugin->get_id();
117
118 add_action( 'init', array( $this, 'init' ) );
119
120 // remove some of our custom fields that shouldn't be saved.
121 add_action(
122 'woocommerce_settings_api_sanitized_fields_' . $this->id,
123 function ( $fields ) {
124
125 unset( $fields['general'], $fields['connect'], $fields['import_products'] );
126
127 if ( $this->is_sandbox() ) {
128 $this->update_access_token( $fields['sandbox_token'] );
129 $this->access_token = false; // Remove encrypted token.
130 $this->refresh_token = false; // Remove encrypted token.
131 }
132
133 // Update the sync interval if it is changed.
134 $this->maybe_change_sync_interval( $fields );
135
136 $this->init_form_fields(); // Reload form fields after saving token.
137
138 return $fields;
139 }
140 );
141
142 add_action( 'admin_notices', array( $this, 'show_auth_keys_changed_notice' ) );
143
144 add_action( 'admin_notices', array( $this, 'show_visit_wizard_notice' ) );
145
146 add_action( 'wp_ajax_wc_square_settings_get_locations', array( $this, 'get_locations_ajax_callback' ) );
147
148 add_action( 'admin_init', array( $this, 'square_onboarding_redirect' ) );
149
150 add_action( 'admin_menu', array( $this, 'register_pages' ) );
151
152 add_action( 'woocommerce_settings_square', array( $this, 'render_square_settings_container' ) );
153
154 add_action( 'woocommerce_settings_checkout', array( $this, 'render_payments_settings_container' ) );
155
156 // Register REST API controllers.
157 new \WooCommerce\Square\Admin\Rest\WC_REST_Square_Settings_Controller();
158 new \WooCommerce\Square\Admin\Rest\WC_REST_Square_Credit_Card_Payment_Settings_Controller();
159 new \WooCommerce\Square\Admin\Rest\WC_REST_Square_Cash_App_Settings_Controller();
160 new \WooCommerce\Square\Admin\Rest\WC_REST_Square_Gift_Cards_Settings_Controller();
161 }
162
163 /**
164 * Redirect users to the templates screen on plugin activation.
165 *
166 * @since 4.7.0
167 */
168 public function square_onboarding_redirect() {
169 if ( ! $this->get_plugin()->get_dependency_handler()->meets_php_dependencies() ) {
170 return;
171 }
172
173 if ( ! get_option( 'wc_square_show_wizard_on_activation' ) ) {
174 add_option( 'wc_square_show_wizard_on_activation', true, '', 'no' );
175 wp_safe_redirect( admin_url( 'admin.php?page=woocommerce-square-onboarding' ) );
176 exit;
177 }
178 }
179
180 /**
181 * Registers square page(s).
182 *
183 * @since 4.7.0
184 */
185 public function register_pages() {
186 if ( ! $this->get_plugin()->get_dependency_handler()->meets_php_dependencies() ) {
187 return;
188 }
189
190 $current_page = isset( $_GET['page'] ) ? wp_unslash( $_GET['page'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Recommended
191 if ( ! get_option( 'wc_square_connected_page_visited' ) || 'woocommerce-square-onboarding' === $current_page ) {
192 add_submenu_page( 'woocommerce', __( 'Square Onboarding', 'woocommerce-square' ), __( 'Square Onboarding', 'woocommerce-square' ), 'manage_woocommerce', 'woocommerce-square-onboarding', array( $this, 'render_onboarding_page' ) ); // phpcs:ignore WordPress.WP.Capabilities.Unknown
193 }
194 }
195
196 /**
197 * Output the Setup Wizard page(s).
198 */
199 public function render_onboarding_page() {
200 printf(
201 '<div class="wrap" id="woocommerce-square-onboarding"></div>'
202 );
203 }
204
205 /**
206 * Show a notice to visit the wizard on plugin activation.
207 *
208 * @since 4.7.0
209 */
210 public function show_visit_wizard_notice() {
211 if ( ! wc_square()->get_dependency_handler()->meets_php_dependencies() ) {
212 return;
213 }
214
215 if ( get_option( 'wc_square_connected_page_visited' ) ) {
216 return;
217 }
218
219 wc_square()->get_admin_notice_handler()->add_admin_notice(
220 sprintf(
221 /* translators: %1$s - <a> tag, %2$s - </a> tag */
222 esc_html__(
223 'Welcome to Square for WooCommerce! Get started by visiting the %1$sOnboarding Wizard%2$s.',
224 'woocommerce-square'
225 ),
226 '<a href="' . esc_url( admin_url( 'admin.php?page=woocommerce-square-onboarding' ) ) . '">',
227 '</a>'
228 ),
229 'wc-square-welcome',
230 array(
231 'dismissible' => false,
232 'notice_class' => 'notice-info',
233 )
234 );
235 }
236
237 /**
238 * Redirect users to the onboarding wizard screen on plugin activation.
239 *
240 * @since 4.7.0
241 */
242 public function render_square_settings_container() {
243 $section = isset( $_GET['section'] ) && ! empty( $_GET['section'] ) ? wp_unslash( $_GET['section'] ) : 'general'; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Recommended
244
245 printf(
246 '<div id="woocommerce-square-settings__container-' . esc_html( $section ) . '"></div>',
247 );
248 }
249
250 /**
251 * Redirect users to the onboarding wizard screen on plugin activation.
252 *
253 * @since 4.7.0
254 */
255 public function render_payments_settings_container() {
256 $tab = isset( $_GET['tab'] ) ? wp_unslash( $_GET['tab'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Recommended
257 $section = isset( $_GET['section'] ) ? wp_unslash( $_GET['section'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.NonceVerification.Recommended
258
259 if ( 'checkout' !== $tab ) {
260 return;
261 }
262
263 if ( ! ( 'square_credit_card' === $section || 'square_cash_app_pay' === $section || 'gift_cards_pay' === $section ) ) {
264 return;
265 }
266
267 printf(
268 '<div id="woocommerce-square-payment-gateway-settings__container--' . esc_html( $section ) . '"></div>',
269 );
270 }
271
272 /**
273 * Show warning to reconnect if the `SQUARE_ENCRYPTION_KEY` and `SQUARE_ENCRYPTION_SALT` constants
274 * are newly added.
275 *
276 * @since 4.2.0
277 */
278 public function show_auth_keys_changed_notice() {
279 $is_keys_updated = get_option( 'wc_square_auth_key_updated', false );
280 $show_message = ( $this->is_custom_square_auth_keys_set() && empty( $is_keys_updated ) )
281 || ( ! $this->is_custom_square_auth_keys_set() && $is_keys_updated );
282
283 if ( $show_message ) {
284 wc_square()->get_admin_notice_handler()->add_admin_notice(
285 esc_html__( 'Square was disconnected because authentication keys were changed. Please connect again.', 'woocommerce-square' ),
286 'wc-square-disconnected-keys-changed',
287 array(
288 'dismissible' => false,
289 'notice_class' => 'notice-warning',
290 )
291 );
292
293 delete_option( 'wc_square_access_tokens' );
294 }
295
296 if ( ! $this->is_custom_square_auth_keys_set() && $is_keys_updated ) {
297 delete_option( 'wc_square_auth_key_updated' );
298 }
299 }
300
301 /**
302 * Returns true if `SQUARE_ENCRYPTION_KEY` and `SQUARE_ENCRYPTION_SALT` constants are both set.
303 *
304 * @since 4.2.0
305 *
306 * @return boolean
307 */
308 public function is_custom_square_auth_keys_set() {
309 return defined( 'SQUARE_ENCRYPTION_KEY' ) && defined( 'SQUARE_ENCRYPTION_SALT' );
310 }
311
312 /**
313 * Initializes form fields and settings.
314 *
315 * @since 3.5.1
316 */
317 public function init() {
318 $this->init_form_fields();
319 $this->init_settings();
320 }
321
322
323 /**
324 * Initializes the form fields.
325 *
326 * @since 2.0.0
327 */
328 public function init_form_fields() {
329 $this->form_fields = array();
330 }
331
332
333 /**
334 * Gets the form fields.
335 *
336 * Overridden to populate the Location settings options on display.
337 *
338 * @since 2.0.0
339 *
340 * @return array
341 */
342 public function get_form_fields() {
343
344 $fields = parent::get_form_fields();
345
346 // Confirm our local enable sandbox setting matches what is sent from the front end
347 // to account for changes from sandbox to production incorrectly fetching sandbox locations.
348 if ( $this->settings && isset( $_POST['wc_square_environment'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
349
350 $environment = 'yes' === $this->settings['enable_sandbox'] ? 'sandbox' : 'production';
351
352 if ( $environment !== $_POST['wc_square_environment'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
353 return $fields;
354 }
355 }
356
357 $location_id_field_key = '';
358 // Get the location_id field.
359 foreach ( $fields as $key => $value ) {
360 if ( strpos( $key, 'location_id' ) ) {
361 $location_id_field_key = $key;
362 break;
363 }
364 }
365
366 if ( did_action( 'wc_square_initialized' ) && $this->is_admin_settings_screen() && ! empty( $location_id_field_key ) ) {
367
368 $locations = array(
369 '' => __( 'Please choose a location', 'woocommerce-square' ),
370 );
371
372 if ( ! empty( $this->get_locations() ) ) {
373 foreach ( $this->get_locations() as $location ) {
374 if ( 'ACTIVE' === $location->getStatus() && in_array( 'CREDIT_CARD_PROCESSING', (array) $location->getCapabilities(), true ) ) {
375 $locations[ $location->getId() ] = $location->getName();
376 }
377 }
378 }
379
380 $fields[ $location_id_field_key ]['options'] = $locations;
381 }
382
383 return $fields;
384 }
385
386
387 /**
388 * Generates the HTML for import products button.
389 *
390 * @param string $id form id.
391 * @param array $field form fields.
392 */
393 public function generate_import_products_html( $id, $field ) {
394
395 $is_location_set = (bool) $this->get_location_id();
396 $is_sor_set = (bool) $this->get_system_of_record_name();
397 $display = $is_location_set && $is_sor_set ? '' : 'display: none';
398
399 ob_start();
400 ?>
401 <tr valign="top" style="<?php echo esc_attr( $display ); ?>">
402 <th scope="row" class="titledesc">
403 <label for="<?php echo esc_attr( $id ); ?>"><?php echo wp_kses_post( $field['title'] ); ?> <?php echo $this->get_tooltip_html( $field ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></label>
404 </th>
405 <td class="forminp">
406 <a id="wc_square_import_products" href='#' class='button js-import-square-products <?php echo ( ! $this->get_location_id() ? 'disabled' : '' ); ?>'>
407 <?php echo esc_html__( 'Import all products from Square', 'woocommerce-square' ); ?>
408 </a>
409 <p class="description wc_square_save_changes_message" style="display: none;"><?php esc_html_e( 'You have made changes to the settings. Please save the changes to enable the button.', 'woocommerce-square' ); ?></p>
410 </td>
411 </tr>
412 <?php
413
414 return ob_get_clean();
415 }
416
417
418 /**
419 * Generates the Connection field HTML.
420 *
421 * @since 2.0.0
422 *
423 * @param string $id field ID.
424 * @param array $field field data.
425 * @return string
426 */
427 public function generate_connect_html( $id, $field ) {
428
429 ob_start();
430 ?>
431 <tr valign="top">
432 <th scope="row" class="titledesc">
433 <label for="<?php echo esc_attr( $id ); ?>"><?php echo wp_kses_post( $field['title'] ); ?> <?php echo $this->get_tooltip_html( $field ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></label>
434 </th>
435 <td class="forminp">
436 <?php
437 if ( $this->get_access_token() ) {
438 echo $this->get_plugin()->get_connection_handler()->get_disconnect_button_html(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
439 } else {
440 echo $this->get_plugin()->get_connection_handler()->get_connect_button_html( $this->is_sandbox() ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
441 }
442 ?>
443 </td>
444 </tr>
445 <?php
446
447 return ob_get_clean();
448 }
449
450
451 /**
452 * Updates the stored refresh token.
453 *
454 * @since 2.0.0
455 *
456 * @param string $token refresh token.
457 */
458 public function update_refresh_token( $token ) {
459
460 $refresh_tokens = $this->get_refresh_tokens();
461 $environment = $this->get_environment();
462
463 if ( ! empty( $token ) ) {
464
465 $this->refresh_token = $token;
466
467 if ( Utilities\Encryption_Utility::is_encryption_supported() ) {
468
469 $encryption = new Utilities\Encryption_Utility();
470
471 try {
472
473 $token = $encryption->encrypt_data( $token );
474
475 } catch ( \Exception $exception ) {
476
477 // log the event, but don't halt the process.
478 $this->get_plugin()->log( 'Could not encrypt refresh token. ' . $exception->getMessage() );
479 }
480 }
481
482 $refresh_tokens[ $environment ] = $token;
483 }
484
485 update_option( 'wc_square_refresh_tokens', $refresh_tokens );
486 }
487
488
489 /**
490 * Updates the stored access token.
491 *
492 * @since 2.0.0
493 *
494 * @param string $token access token.
495 */
496 public function update_access_token( $token ) {
497
498 $access_tokens = $this->get_access_tokens();
499 $environment = $this->get_environment();
500
501 if ( ! empty( $token ) ) {
502
503 $this->access_token = $token;
504
505 if ( Utilities\Encryption_Utility::is_encryption_supported() ) {
506
507 $encryption = new Utilities\Encryption_Utility();
508
509 try {
510
511 $token = $encryption->encrypt_data( $token );
512
513 } catch ( \Exception $exception ) {
514
515 // log the event, but don't halt the process.
516 $this->get_plugin()->log( 'Could not encrypt access token. ' . $exception->getMessage() );
517 }
518 }
519
520 $access_tokens[ $environment ] = $token;
521 } elseif ( isset( $access_tokens[ $environment ] ) ) {
522
523 unset( $access_tokens[ $environment ] );
524 }
525
526 update_option( 'wc_square_access_tokens', $access_tokens );
527 }
528
529
530 /**
531 * Clears any stored refresh tokens.
532 *
533 * @since 2.0.0
534 */
535 public function clear_refresh_tokens() {
536 delete_option( 'wc_square_refresh_tokens' );
537 }
538
539
540 /**
541 * Clears any stored access tokens.
542 *
543 * @since 2.0.0
544 */
545 public function clear_access_tokens() {
546
547 delete_option( 'wc_square_access_tokens' );
548 }
549
550
551 /**
552 * Clears the location ID from the settings.
553 *
554 * This is helpful on disconnect / revoke so that previously set location IDs don't stick around and cause confusion.
555 *
556 * @since 2.0.0
557 */
558 public function clear_location_id() {
559
560 $settings = get_option( $this->get_option_key(), array() );
561
562 $settings[ $this->get_environment() . '_location_id' ] = '';
563
564 update_option( $this->get_option_key(), $settings );
565 }
566
567
568 /** Conditional methods *******************************************************************************************/
569
570
571 /**
572 * Determines if WooCommerce is configured to be the Sync setting.
573 *
574 * @since 2.0.0
575 *
576 * @return bool
577 */
578 public function is_system_of_record_woocommerce() {
579
580 return self::SYSTEM_OF_RECORD_WOOCOMMERCE === $this->get_system_of_record();
581 }
582
583
584 /**
585 * Determines if Square is configured to be the Sync setting.
586 *
587 * @since 2.0.0
588 *
589 * @return bool
590 */
591 public function is_system_of_record_square() {
592
593 return self::SYSTEM_OF_RECORD_SQUARE === $this->get_system_of_record();
594 }
595
596
597 /**
598 * Determines if there is no Sync setting.
599 *
600 * @since 2.0.0
601 *
602 * @return bool
603 */
604 public function is_system_of_record_disabled() {
605
606 $sor = $this->get_system_of_record();
607
608 return empty( $sor ) || self::SYSTEM_OF_RECORD_DISABLED === $sor;
609 }
610
611
612 /**
613 * Determines if inventory sync is enabled.
614 *
615 * @since 2.0.0
616 *
617 * @return bool
618 */
619 public function is_inventory_sync_enabled() {
620
621 /**
622 * Filters the inventory sync setting.
623 *
624 * @since 2.0.0
625 */
626 return (bool) apply_filters( 'wc_square_inventory_sync_enabled', 'yes' === get_option( 'woocommerce_manage_stock' ) && $this->is_product_sync_enabled() && 'yes' === $this->get_option( 'enable_inventory_sync' ) );
627 }
628
629 /**
630 * Determines if image overriding is enabled.
631 *
632 * @since 3.9.0
633 *
634 * @return bool
635 */
636 public function is_override_product_images_enabled() {
637 /**
638 * Filter to enable/disable overriding product images.
639 *
640 * @since 3.9.0
641 *
642 * @param boolean 'should_override' Boolean flag to toggle overriding image feature.
643 */
644 return (bool) apply_filters( 'wc_square_override_product_images_enabled', 'yes' === $this->get_option( 'override_product_images' ) );
645 }
646
647
648 /**
649 * Determines if product sync is enabled.
650 *
651 * @since 2.0.0
652 *
653 * @return bool
654 */
655 public function is_product_sync_enabled() {
656
657 return ! $this->is_system_of_record_disabled();
658 }
659
660
661 /**
662 * Determines whether to hide products that don't exist in square from the catalog.
663 *
664 * @since 2.0.0
665 *
666 * @return bool
667 */
668 public function hide_missing_square_products() {
669
670 return 'yes' === $this->get_option( 'hide_missing_products' );
671 }
672
673 /**
674 * Returns sync interval in seconds.
675 * Returns 1 hr = 3600 seconds as default.
676 *
677 * @since 3.5.1
678 *
679 * @return int
680 */
681 public function get_sync_interval() {
682 $sync_interval = $this->get_option( 'sync_interval', '' );
683 $sync_interval = empty( $sync_interval ) ? HOUR_IN_SECONDS : $sync_interval * HOUR_IN_SECONDS;
684
685 /**
686 * Filters the frequency with which products should be synced.
687 *
688 * @since 2.0.0
689 *
690 * @param int $interval sync interval in seconds (defaults to one hour)
691 */
692 return (int) max( MINUTE_IN_SECONDS, (int) apply_filters( 'wc_square_sync_interval', $sync_interval ) );
693 }
694
695
696 /**
697 * Determines if the plugin settings are fully configured.
698 *
699 * @since 2.0.0
700 *
701 * @return bool
702 */
703 public function is_configured() {
704
705 return $this->get_location_id() && $this->get_system_of_record();
706 }
707
708
709 /**
710 * Determines if the plugin is connected to Square.
711 *
712 * @since 2.0.0
713 *
714 * @return bool
715 */
716 public function is_connected() {
717
718 return (bool) $this->get_access_token();
719 }
720
721
722 /**
723 * Determines if configured in the sandbox environment.
724 *
725 * @since 2.0.0
726 *
727 * @return bool
728 */
729 public function is_sandbox() {
730
731 return 'sandbox' === $this->get_environment();
732 }
733
734
735 /**
736 * Determines if debug logging is enabled.
737 *
738 * @since 2.0.0
739 *
740 * @return bool
741 */
742 public function is_debug_enabled() {
743
744 return 'yes' === $this->get_option( 'debug_logging_enabled' );
745 }
746
747
748 /** Getter methods ************************************************************************************************/
749
750
751 /**
752 * Gets the configured location.
753 *
754 * @since 2.0.0
755 *
756 * @return string
757 */
758 public function get_location_id() {
759 $location_id = $this->get_option( $this->get_environment() . '_location_id' );
760
761 if ( empty( $location_id ) ) {
762 $square_db_version = get_option( $this->get_plugin()->get_plugin_version_name() );
763
764 // if the Square DB version is still pre-2.2.0, fetch the location ID using the previous option name
765 if ( ! empty( $square_db_version ) && version_compare( $square_db_version, '2.2.0', '<' ) ) {
766 $location_id = $this->get_option( 'location_id' );
767 }
768 }
769
770 return $location_id;
771 }
772
773
774 /**
775 * Gets the available locations.
776 *
777 * @since 2.0.0
778 *
779 * @param bool $force whether to force a refetch of the locations.
780 *
781 * @return \Square\Models\Location[]
782 */
783 public function get_locations( $force = false ) {
784 if ( is_array( $this->locations ) ) {
785 return $this->locations;
786 }
787
788 $locations_transient_key = 'wc_square_locations_' . $this->get_plugin()->get_version();
789
790 $section = isset( $_GET['section'] ) ? sanitize_text_field( wp_unslash( $_GET['section'] ) ) : false; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
791
792 if ( ! ( $this->is_admin_settings_screen() || ( $this->is_admin_settings_screen() && 'update' !== $section ) || $force ) ) {
793 $this->locations = get_transient( $locations_transient_key );
794 }
795
796 if ( ! is_array( $this->locations ) && did_action( 'wc_square_initialized' ) ) {
797
798 $this->locations = array();
799
800 if ( ! $this->get_plugin()->get_dependency_handler()->meets_php_dependencies() ) {
801 return $this->locations;
802 }
803
804 try {
805
806 // cache the locations returned so they can be used elsewhere.
807 $this->locations = $this->get_plugin()->get_api( $this->get_access_token(), $this->is_sandbox() )->get_locations();
808 set_transient( $locations_transient_key, $this->locations, HOUR_IN_SECONDS );
809
810 // check the returned IDs against what's currently configured.
811 $stored_location_id = $this->get_location_id();
812 $found = ! $stored_location_id;
813
814 foreach ( $this->locations as $location ) {
815
816 if ( $stored_location_id && $location->getId() === $stored_location_id ) {
817 $found = true;
818 break;
819 }
820 }
821
822 // if the currently set location ID is not present in the connected account's available locations, clear it locally.
823 if ( ! $found ) {
824 $this->clear_location_id();
825 }
826 } catch ( \Exception $exception ) {
827 $this->get_plugin()->log( 'Could not retrieve business locations.' );
828 }
829 }
830
831 return $this->locations;
832 }
833
834 /**
835 * Ajax callback for locations.
836 *
837 * @since 4.7.0
838 */
839 public function get_locations_ajax_callback() {
840 check_ajax_referer( 'wc_square_settings', 'security' );
841
842 $locations = $this->get_locations( true );
843
844 wp_send_json_success( $locations );
845 }
846
847 /**
848 * Gets the configured Sync setting.
849 *
850 * @since 2.0.0
851 *
852 * @return string
853 */
854 public function get_system_of_record() {
855
856 return $this->get_option( 'system_of_record' );
857 }
858
859
860 /**
861 * Gets the configured Sync setting name.
862 *
863 * @since 2.0.0
864 *
865 * @return string or empty string if no Sync setting is configured
866 */
867 public function get_system_of_record_name() {
868
869 switch ( $this->get_system_of_record() ) {
870
871 case 'square':
872 $sor = __( 'Square', 'woocommerce-square' );
873 break;
874 case 'woocommerce':
875 $sor = __( 'WooCommerce', 'woocommerce-square' );
876 break;
877 default:
878 $sor = '';
879 break;
880 }
881
882 return $sor;
883 }
884
885 /**
886 * Gets the refresh token.
887 *
888 * @since 2.0.0
889 *
890 * @return string|null
891 */
892 public function get_refresh_token() {
893
894 if ( empty( $this->refresh_token ) ) {
895
896 $tokens = $this->get_refresh_tokens();
897 $token = null;
898
899 if ( ! empty( $tokens[ $this->get_environment() ] ) ) {
900 $token = $tokens[ $this->get_environment() ];
901 }
902
903 if ( $token && Utilities\Encryption_Utility::is_encryption_supported() ) {
904
905 $encryption = new Utilities\Encryption_Utility();
906
907 try {
908
909 $token = $encryption->decrypt_data( $token );
910
911 } catch ( \Exception $exception ) {
912
913 // log the event, but don't halt the process.
914 $this->get_plugin()->log( 'Could not decrypt refresh token. ' . $exception->getMessage() );
915 }
916 }
917
918 $this->refresh_token = $token;
919 }
920
921 /**
922 * Filters the configured refresh token.
923 *
924 * @since 2.0.0
925 *
926 * @param string $refresh_token
927 */
928 return apply_filters( 'wc_square_refresh_token', $this->refresh_token );
929 }
930
931 /**
932 * Gets the access token.
933 *
934 * @since 2.0.0
935 *
936 * @return string|null
937 */
938 public function get_access_token() {
939
940 if ( empty( $this->access_token ) || $this->is_admin_settings_screen() ) {
941
942 $tokens = $this->get_access_tokens();
943 $token = null;
944
945 if ( ! empty( $tokens[ $this->get_environment() ] ) ) {
946 $token = $tokens[ $this->get_environment() ];
947 }
948
949 if ( $token && Utilities\Encryption_Utility::is_encryption_supported() ) {
950
951 $encryption = new Utilities\Encryption_Utility();
952
953 try {
954
955 $token = $encryption->decrypt_data( $token );
956
957 } catch ( \Exception $exception ) {
958
959 // log the event, but don't halt the process.
960 $this->get_plugin()->log( 'Could not decrypt access token. ' . $exception->getMessage() );
961 }
962 }
963
964 $this->access_token = $token;
965 }
966
967 /**
968 * Filters the configured access token.
969 *
970 * @since 2.0.0
971 *
972 * @param string $access_token access token
973 */
974 return apply_filters( 'wc_square_access_token', $this->access_token );
975 }
976
977
978 /**
979 * Gets the stored access tokens.
980 *
981 * Each environment may have its own token.
982 *
983 * @since 2.0.0
984 *
985 * @return array
986 */
987 public function get_access_tokens() {
988 return (array) get_option( 'wc_square_access_tokens', array() );
989 }
990
991
992 /**
993 * Gets the stored refresh tokens.
994 *
995 * Each environment may have its own token.
996 *
997 * @since 2.0.0
998 *
999 * @return array
1000 */
1001 public function get_refresh_tokens() {
1002 return (array) get_option( 'wc_square_refresh_tokens', array() );
1003 }
1004
1005 /**
1006 * Gets setting enabled sandbox.
1007 *
1008 * @since 2.1.2
1009 *
1010 * @return string
1011 */
1012 public function get_enable_sandbox() {
1013 return $this->get_option( 'enable_sandbox' );
1014 }
1015
1016 /**
1017 * Tells is if the setting for enabling sandbox is checked.
1018 *
1019 * @since 2.1.2
1020 *
1021 * @return boolean
1022 */
1023 public function is_sandbox_setting_enabled() {
1024 return 'yes' === $this->get_enable_sandbox();
1025 }
1026
1027
1028 /**
1029 * Gets the configured environment.
1030 *
1031 * @since 2.0.0
1032 *
1033 * @return string
1034 */
1035 public function get_environment() {
1036 $sanboxed = ( defined( 'WC_SQUARE_SANDBOX' ) && WC_SQUARE_SANDBOX ) || $this->is_sandbox_setting_enabled();
1037 return $sanboxed ? 'sandbox' : 'production';
1038 }
1039
1040
1041 /**
1042 * Gets the plugin instance.
1043 *
1044 * @since 2.0.0
1045 *
1046 * @return Plugin
1047 */
1048 public function get_plugin() {
1049
1050 return $this->plugin;
1051 }
1052
1053 /**
1054 * Determines if the current request is for the Square admin settings screen.
1055 *
1056 * @since 2.1.5
1057 * @return bool True if the current request is for the Square admin settings, otherwise false.
1058 */
1059 public function is_admin_settings_screen() {
1060 return isset( $_GET['page'], $_GET['tab'] ) && 'wc-settings' === $_GET['page'] && Plugin::PLUGIN_ID === $_GET['tab']; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1061 }
1062
1063 /**
1064 * Update the sync interval if it has changed.
1065 *
1066 * @param array $settings
1067 * @return void
1068 */
1069 public function maybe_change_sync_interval( $settings ) {
1070 // Bail if we have a filter in place to manage the sync interval.
1071 if ( has_filter( 'wc_square_sync_interval' ) ) {
1072 return;
1073 }
1074
1075 $old_settings = get_option( $this->get_option_key(), array() );
1076 // Bail if we don't have a sync interval.
1077 if ( empty( $old_settings['sync_interval'] ) || empty( $settings['sync_interval'] ) ) {
1078 return;
1079 }
1080
1081 // If the sync interval has changed, schedule a new sync.
1082 if ( $old_settings['sync_interval'] !== $settings['sync_interval'] ) {
1083 $this->plugin->get_sync_handler()->schedule_sync( true );
1084 }
1085 }
1086 }
1087