PluginProbe ʕ •ᴥ•ʔ
WooCommerce Square / 3.8.2
WooCommerce Square v3.8.2
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 3 years ago Admin 3 years ago Emails 3 years ago Framework 3 years ago Gateway 3 years ago Handlers 3 years ago Sync 3 years ago Utilities 3 years ago AJAX.php 3 years ago API.php 3 years ago Admin.php 3 years ago Functions.php 3 years ago Gateway.php 3 years ago Lifecycle.php 3 years ago Plugin.php 3 years ago Settings.php 3 years ago
Settings.php
1027 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 defined( 'ABSPATH' ) || exit;
27
28 /**
29 * The settings API class.
30 *
31 * This handles registering, getting, and storing the general plugin options.
32 *
33 * Note that this is separate from the gateway settings.
34 *
35 * @since 2.0.0
36 */
37 class Settings extends \WC_Settings_API {
38
39
40 /**
41 * Square Sync setting.
42 *
43 * @var string square Sync setting indicator
44 */
45 const SYSTEM_OF_RECORD_SQUARE = 'square';
46
47 /**
48 * Woocommerce Sync setting.
49 *
50 * @var string square Sync setting indicator
51 */
52 const SYSTEM_OF_RECORD_WOOCOMMERCE = 'woocommerce';
53
54 /**
55 * Disabled Sync setting.
56 *
57 * @var string Sync setting indicator for disabled sync
58 */
59 const SYSTEM_OF_RECORD_DISABLED = 'disabled';
60
61
62 /**
63 * Refresh token
64 *
65 * @var string un-encrypted refresh token
66 */
67 protected $refresh_token;
68
69 /**
70 * Access token
71 *
72 * @var string un-encrypted access token
73 */
74 protected $access_token;
75
76 /**
77 * Square business locations
78 *
79 * @var array business locations returned by the API
80 */
81 protected $locations;
82
83 /**
84 * Square plugin instance
85 *
86 * @var Plugin plugin instance
87 */
88 protected $plugin;
89
90
91 /**
92 * Constructs the class.
93 *
94 * @since 2.0.0
95 *
96 * @param Plugin $plugin plugin instance.
97 */
98 public function __construct( Plugin $plugin ) {
99
100 $this->plugin = $plugin;
101 $this->plugin_id = 'wc_';
102 $this->id = $plugin->get_id();
103
104 add_action( 'init', array( $this, 'init' ) );
105
106 // remove some of our custom fields that shouldn't be saved.
107 add_action(
108 'woocommerce_settings_api_sanitized_fields_' . $this->id,
109 function( $fields ) {
110
111 unset( $fields['general'], $fields['connect'], $fields['import_products'] );
112
113 if ( $this->is_sandbox() ) {
114 $this->update_access_token( $fields['sandbox_token'] );
115 $this->access_token = false; // Remove encrypted token.
116 $this->refresh_token = false; // Remove encrypted token.
117 }
118
119 $this->init_form_fields(); // Reload form fields after saving token.
120
121 return $fields;
122 }
123 );
124 }
125
126 /**
127 * Initializes form fields and settings.
128 *
129 * @since 3.5.1
130 */
131 public function init() {
132 $this->init_form_fields();
133 $this->init_settings();
134 }
135
136
137 /**
138 * Initializes the form fields.
139 *
140 * @since 2.0.0
141 */
142 public function init_form_fields() {
143
144 if ( $this->is_connected() ) {
145
146 $general_description = sprintf(
147 /* translators: Placeholders: %1$s - <a> tag, %2$s - </a> tag */
148 __( 'Sync your products and inventory and also accept credit and debit card payments at checkout. %1$sClick here%2$s to configure payments.', 'woocommerce-square' ),
149 '<a href="' . esc_url( $this->get_plugin()->get_payment_gateway_configuration_url( $this->get_plugin()->get_gateway()->get_id() ) ) . '">',
150 '</a>'
151 );
152
153 } else {
154
155 $general_description = __( 'Connect with Square to start syncing your products and inventory and also accept credit and debit card payments at checkout.', 'woocommerce-square' );
156 }
157
158 $fields = array(
159 'general' => array(
160 'type' => 'title',
161 'description' => $general_description,
162 ),
163 );
164
165 $fields['enable_sandbox'] = array(
166 'title' => __( 'Enable Sandbox Mode', 'woocommerce-square' ),
167 'label' => '<span>' . __( 'Enable to set the plugin in sandbox mode.', 'woocommerce-square' ) . '</span>',
168 'type' => 'checkbox',
169 'description' => __( 'After enabling you’ll see a new Sandbox settings section with two fields; Sandbox Application ID & Sandbox Access Token.', 'woocommerce-square' ),
170 );
171
172 $fields['sandbox_settings'] = array(
173 'type' => 'title',
174 'title' => __( 'Sandbox settings', 'woocommerce-square' ),
175 'id' => 'wc_square_sandbox_settings',
176 'description' => sprintf(
177 // translators: Placeholders: %1$s - URL.
178 __( 'Sandbox details can be created at: %s', 'woocommerce-square' ),
179 sprintf( '<a href="%1$s">%1$s</a>', 'https://developer.squareup.com/apps' )
180 ),
181 );
182
183 $fields['sandbox_application_id'] = array(
184 'type' => 'input',
185 'title' => __( 'Sandbox Application ID', 'woocommerce-square' ),
186 'class' => 'wc_square_sandbox_settings',
187 'description' => __( 'Application ID for the Sandbox Application, see the details in the My Applications section.', 'woocommerce-square' ),
188 );
189
190 $fields['sandbox_token'] = array(
191 'type' => 'input',
192 'title' => __( 'Sandbox Access Token', 'woocommerce-square' ),
193 'class' => 'wc_square_sandbox_settings',
194 'description' => __( 'Access Token for the Sandbox Test Account, see the details in the Sandbox Test Account section. Make sure you use the correct Sandbox Access Token for your application. For a given Sandbox Test Account, each Authorized Application is assigned a different Access Token.', 'woocommerce-square' ),
195 );
196
197 // display these fields only if connected.
198 if ( $this->is_connected() ) {
199
200 $fields[ $this->get_environment() . '_location_id' ] = array(
201 'title' => __( 'Business location', 'woocommerce-square' ),
202 'type' => 'select',
203 'class' => 'wc-enhanced-select',
204 'description' => sprintf(
205 /* translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s - <a> tag, %4$s - </a> tag */
206 __( 'Select a location to link to this site. Only %1$sactive%2$s %3$slocations%4$s that support credit card processing in Square can be linked.', 'woocommerce-square' ),
207 '<strong>',
208 '</strong>',
209 '<a href="https://docs.woocommerce.com/document/woocommerce-square/#section-4" target="_blank">',
210 '</a>'
211 ),
212 'options' => array(), // this is populated on display.
213 );
214
215 $fields['system_of_record'] = array(
216 'title' => __( 'Sync settings', 'woocommerce-square' ),
217 'type' => 'select',
218 'class' => 'wc-enhanced-select',
219 'description' => sprintf(
220 /* translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s - <a> tag, %4$s - </a> tag */
221 __( 'Choose where data will be updated for synced products. Inventory in Square is %1$salways%2$s checked for adjustments when sync is enabled.%3$s%4$sLearn more%5$s about choosing a system of record or %6$screate a ticket%7$s if you\'re experiencing technical issues.', 'woocommerce-square' ),
222 '<strong>',
223 '</strong>',
224 '<br>',
225 '<a href="' . esc_url( wc_square()->get_documentation_url() ) . '#section-8">',
226 '</a>',
227 '<a href="https://wordpress.org/support/plugin/woocommerce-square/">',
228 '</a>'
229 ),
230 'options' => array(
231 self::SYSTEM_OF_RECORD_DISABLED => __( 'Do not sync product data', 'woocommerce-square' ),
232 self::SYSTEM_OF_RECORD_SQUARE => __( 'Square', 'woocommerce-square' ),
233 self::SYSTEM_OF_RECORD_WOOCOMMERCE => __( 'WooCommerce', 'woocommerce-square' ),
234 ),
235 'default' => 'disabled',
236 );
237
238 $fields['enable_inventory_sync'] = array(
239 'title' => __( 'Sync inventory', 'woocommerce-square' ),
240 'label' => '<span>' . __( 'Enable to sync product inventory with Square', 'woocommerce-square' ) . '</span>',
241 'type' => 'checkbox',
242 'description' => __( 'Inventory is fetched from Square periodically and updated in WooCommerce', 'woocommerce-square' ),
243 );
244
245 $fields['hide_missing_products'] = array(
246 'title' => __( 'Handle missing products', 'woocommerce-square' ),
247 'label' => __( 'Hide synced products when not found in Square', 'woocommerce-square' ),
248 'type' => 'checkbox',
249 'description' => __( 'Products not found in Square will be hidden in the WooCommerce product catalog.', 'woocommerce-square' ),
250 );
251
252 $fields['sync_interval'] = array(
253 'title' => __( 'Sync interval', 'woocommerce-square' ),
254 'type' => 'select',
255 'default' => '1',
256 'options' => array(
257 '0.25' => esc_html__( '15 minutes', 'woocommerce-square' ),
258 '0.5' => esc_html__( '30 minutes', 'woocommerce-square' ),
259 '0.75' => esc_html__( '45 minutes', 'woocommerce-square' ),
260 '1' => esc_html__( '1 hour', 'woocommerce-square' ),
261 '2' => esc_html__( '2 hours', 'woocommerce-square' ),
262 '3' => esc_html__( '3 hours', 'woocommerce-square' ),
263 '6' => esc_html__( '6 hours', 'woocommerce-square' ),
264 '8' => esc_html__( '8 hours', 'woocommerce-square' ),
265 '12' => esc_html__( '12 hours', 'woocommerce-square' ),
266 '24' => esc_html__( '24 hours', 'woocommerce-square' ),
267 ),
268 'description' => sprintf(
269 esc_html__( 'Frequency for how regularly WooCommerce will sync products with Square.', 'woocommerce-square' )
270 ),
271 );
272
273 $sync_interval = $this->get_sync_interval();
274
275 if ( has_filter( 'wc_square_sync_interval' ) ) {
276 $fields['sync_interval']['custom_attributes']['disabled'] = true;
277 $fields['sync_interval']['description'] = sprintf(
278 // translators: %4$s: interval duration in minutes.
279 esc_html__( 'Frequency for how regularly WooCommerce will sync products with Square.%1$sSync interval settings are disabled as they are being overridden by the %2$swc_square_sync_interval%3$s filter. This filter is setting the sync interval to %4$s minutes.', 'woocommerce-square' ),
280 '<br /><br />',
281 '<code>',
282 '</code>',
283 $sync_interval / HOUR_IN_SECONDS * 60
284 );
285 }
286
287 $fields['import_products'] = array(
288 'title' => __( 'Import Products', 'woocommerce-square' ),
289 'type' => 'import_products',
290 'desc_tip' => __( 'Run an import to create new products in this WooCommerce store for each new product created in Square that has a unique SKU not existing in here. Needs to be run each time new items are created in Square.', 'woocommerce-square' ),
291 );
292 }
293
294 // In sandbox mode we don't want to intially display the connect button, only disconnect.
295 if ( ! ( $this->is_sandbox() && ! $this->is_connected() ) ) {
296 $fields = array_merge(
297 $fields,
298 array(
299 'connect' => array(
300 'title' => __( 'Connection', 'woocommerce-square' ),
301 'type' => 'connect',
302 'desc_tip' => '',
303 ),
304 )
305 );
306 }
307
308 // Always display these fields.
309 $fields = array_merge(
310 $fields,
311 array(
312 'debug_logging_enabled' => array(
313 'title' => __( 'Enable Logging', 'woocommerce-square' ),
314 'type' => 'checkbox',
315 'label' => sprintf(
316 /* translators: Placeholders: %1$s - <a> tag, %2$s - </a> tag */
317 __( 'Log debug messages to the %1$sWooCommerce status log%2$s', 'woocommerce-square' ),
318 '<a href="' . esc_url( admin_url( 'admin.php?page=wc-status&tab=logs' ) ) . '">',
319 '</a>'
320 ),
321 ),
322 )
323 );
324
325 $this->form_fields = $fields;
326 }
327
328
329 /**
330 * Gets the form fields.
331 *
332 * Overridden to populate the Location settings options on display.
333 *
334 * @since 2.0.0
335 *
336 * @return array
337 */
338 public function get_form_fields() {
339
340 $fields = parent::get_form_fields();
341
342 // Confirm our local enable sandbox setting matches what is sent from the front end
343 // to account for changes from sandbox to production incorrectly fetching sandbox locations.
344 if ( $this->settings && isset( $_POST['wc_square_environment'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
345
346 $environment = 'yes' === $this->settings['enable_sandbox'] ? 'sandbox' : 'production';
347
348 if ( $environment !== $_POST['wc_square_environment'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
349 return $fields;
350 }
351 }
352
353 $location_id_field_key = '';
354 // Get the location_id field.
355 foreach ( $fields as $key => $value ) {
356 if ( strpos( $key, 'location_id' ) ) {
357 $location_id_field_key = $key;
358 break;
359 }
360 }
361
362 if ( did_action( 'wc_square_initialized' ) && $this->is_admin_settings_screen() && ! empty( $location_id_field_key ) ) {
363
364 $locations = array(
365 '' => __( 'Please choose a location', 'woocommerce-square' ),
366 );
367
368 if ( ! empty( $this->get_locations() ) ) {
369 foreach ( $this->get_locations() as $location ) {
370 if ( 'ACTIVE' === $location->getStatus() && in_array( 'CREDIT_CARD_PROCESSING', (array) $location->getCapabilities(), true ) ) {
371 $locations[ $location->getId() ] = $location->getName();
372 }
373 }
374 }
375
376 $fields[ $location_id_field_key ]['options'] = $locations;
377 }
378
379 return $fields;
380 }
381
382
383 /**
384 * Generates the HTML for import products button.
385 *
386 * @param string $id form id.
387 * @param array $field form fields.
388 */
389 public function generate_import_products_html( $id, $field ) {
390
391 $is_location_set = (bool) $this->get_location_id();
392 $is_sor_set = (bool) $this->get_system_of_record_name();
393 $display = $is_location_set && $is_sor_set ? '' : 'display: none';
394
395 ob_start();
396 ?>
397 <tr valign="top" style="<?php echo esc_attr( $display ); ?>">
398 <th scope="row" class="titledesc">
399 <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>
400 </th>
401 <td class="forminp">
402 <a id="wc_square_import_products" href='#' class='button js-import-square-products <?php echo ( ! $this->get_location_id() ? 'disabled' : '' ); ?>'>
403 <?php echo esc_html__( 'Import all products from Square', 'woocommerce-square' ); ?>
404 </a>
405 <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>
406 </td>
407 </tr>
408 <?php
409
410 return ob_get_clean();
411 }
412
413
414 /**
415 * Generates the Connection field HTML.
416 *
417 * @since 2.0.0
418 *
419 * @param string $id field ID.
420 * @param array $field field data.
421 * @return string
422 */
423 public function generate_connect_html( $id, $field ) {
424
425 ob_start();
426 ?>
427 <tr valign="top">
428 <th scope="row" class="titledesc">
429 <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>
430 </th>
431 <td class="forminp">
432 <?php
433 if ( $this->get_access_token() ) {
434 echo $this->get_plugin()->get_connection_handler()->get_disconnect_button_html(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
435 } else {
436 echo $this->get_plugin()->get_connection_handler()->get_connect_button_html( $this->is_sandbox() ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
437 }
438 ?>
439 </td>
440 </tr>
441 <?php
442
443 return ob_get_clean();
444 }
445
446
447 /**
448 * Updates the stored refresh token.
449 *
450 * @since 2.0.0
451 *
452 * @param string $token refresh token.
453 */
454 public function update_refresh_token( $token ) {
455
456 $refresh_tokens = $this->get_refresh_tokens();
457 $environment = $this->get_environment();
458
459 if ( ! empty( $token ) ) {
460
461 $this->refresh_token = $token;
462
463 if ( Utilities\Encryption_Utility::is_encryption_supported() ) {
464
465 $encryption = new Utilities\Encryption_Utility();
466
467 try {
468
469 $token = $encryption->encrypt_data( $token );
470
471 } catch ( \Exception $exception ) {
472
473 // log the event, but don't halt the process.
474 $this->get_plugin()->log( 'Could not encrypt refresh token. ' . $exception->getMessage() );
475 }
476 }
477
478 $refresh_tokens[ $environment ] = $token;
479 }
480
481 update_option( 'wc_square_refresh_tokens', $refresh_tokens );
482 }
483
484
485 /**
486 * Updates the stored access token.
487 *
488 * @since 2.0.0
489 *
490 * @param string $token access token.
491 */
492 public function update_access_token( $token ) {
493
494 $access_tokens = $this->get_access_tokens();
495 $environment = $this->get_environment();
496
497 if ( ! empty( $token ) ) {
498
499 $this->access_token = $token;
500
501 if ( Utilities\Encryption_Utility::is_encryption_supported() ) {
502
503 $encryption = new Utilities\Encryption_Utility();
504
505 try {
506
507 $token = $encryption->encrypt_data( $token );
508
509 } catch ( \Exception $exception ) {
510
511 // log the event, but don't halt the process.
512 $this->get_plugin()->log( 'Could not encrypt access token. ' . $exception->getMessage() );
513 }
514 }
515
516 $access_tokens[ $environment ] = $token;
517 } elseif ( isset( $access_tokens[ $environment ] ) ) {
518
519 unset( $access_tokens[ $environment ] );
520 }
521
522 update_option( 'wc_square_access_tokens', $access_tokens );
523 }
524
525
526 /**
527 * Clears any stored refresh tokens.
528 *
529 * @since 2.0.0
530 */
531 public function clear_refresh_tokens() {
532 delete_option( 'wc_square_refresh_tokens' );
533 }
534
535
536 /**
537 * Clears any stored access tokens.
538 *
539 * @since 2.0.0
540 */
541 public function clear_access_tokens() {
542
543 delete_option( 'wc_square_access_tokens' );
544 }
545
546
547 /**
548 * Clears the location ID from the settings.
549 *
550 * This is helpful on disconnect / revoke so that previously set location IDs don't stick around and cause confusion.
551 *
552 * @since 2.0.0
553 */
554 public function clear_location_id() {
555
556 $settings = get_option( $this->get_option_key(), array() );
557
558 $settings[ $this->get_environment() . '_location_id' ] = '';
559
560 update_option( $this->get_option_key(), $settings );
561 }
562
563
564 /** Conditional methods *******************************************************************************************/
565
566
567 /**
568 * Determines if WooCommerce is configured to be the Sync setting.
569 *
570 * @since 2.0.0
571 *
572 * @return bool
573 */
574 public function is_system_of_record_woocommerce() {
575
576 return self::SYSTEM_OF_RECORD_WOOCOMMERCE === $this->get_system_of_record();
577 }
578
579
580 /**
581 * Determines if Square is configured to be the Sync setting.
582 *
583 * @since 2.0.0
584 *
585 * @return bool
586 */
587 public function is_system_of_record_square() {
588
589 return self::SYSTEM_OF_RECORD_SQUARE === $this->get_system_of_record();
590 }
591
592
593 /**
594 * Determines if there is no Sync setting.
595 *
596 * @since 2.0.0
597 *
598 * @return bool
599 */
600 public function is_system_of_record_disabled() {
601
602 $sor = $this->get_system_of_record();
603
604 return empty( $sor ) || self::SYSTEM_OF_RECORD_DISABLED === $sor;
605 }
606
607
608 /**
609 * Determines if inventory sync is enabled.
610 *
611 * @since 2.0.0
612 *
613 * @return bool
614 */
615 public function is_inventory_sync_enabled() {
616
617 /**
618 * Filters the inventory sync setting.
619 *
620 * @since 2.0.0
621 */
622 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' ) );
623 }
624
625
626 /**
627 * Determines if product sync is enabled.
628 *
629 * @since 2.0.0
630 *
631 * @return bool
632 */
633 public function is_product_sync_enabled() {
634
635 return ! $this->is_system_of_record_disabled();
636 }
637
638
639 /**
640 * Determines whether to hide products that don't exist in square from the catalog.
641 *
642 * @since 2.0.0
643 *
644 * @return bool
645 */
646 public function hide_missing_square_products() {
647
648 return 'yes' === $this->get_option( 'hide_missing_products' );
649 }
650
651 /**
652 * Returns sync interval in seconds.
653 * Returns 1 hr = 3600 seconds as default.
654 *
655 * @since 3.5.1
656 *
657 * @return int
658 */
659 public function get_sync_interval() {
660 $sync_interval = $this->get_option( 'sync_interval', '' );
661 $sync_interval = empty( $sync_interval ) ? HOUR_IN_SECONDS : $sync_interval * HOUR_IN_SECONDS;
662
663 /**
664 * Filters the frequency with which products should be synced.
665 *
666 * @since 2.0.0
667 *
668 * @param int $interval sync interval in seconds (defaults to one hour)
669 */
670 return (int) max( MINUTE_IN_SECONDS, (int) apply_filters( 'wc_square_sync_interval', $sync_interval ) );
671 }
672
673
674 /**
675 * Determines if the plugin settings are fully configured.
676 *
677 * @since 2.0.0
678 *
679 * @return bool
680 */
681 public function is_configured() {
682
683 return $this->get_location_id() && $this->get_system_of_record();
684 }
685
686
687 /**
688 * Determines if the plugin is connected to Square.
689 *
690 * @since 2.0.0
691 *
692 * @return bool
693 */
694 public function is_connected() {
695
696 return (bool) $this->get_access_token();
697 }
698
699
700 /**
701 * Determines if configured in the sandbox environment.
702 *
703 * @since 2.0.0
704 *
705 * @return bool
706 */
707 public function is_sandbox() {
708
709 return 'sandbox' === $this->get_environment();
710 }
711
712
713 /**
714 * Determines if debug logging is enabled.
715 *
716 * @since 2.0.0
717 *
718 * @return bool
719 */
720 public function is_debug_enabled() {
721
722 return 'yes' === $this->get_option( 'debug_logging_enabled' );
723 }
724
725
726 /** Getter methods ************************************************************************************************/
727
728
729 /**
730 * Gets the configured location.
731 *
732 * @since 2.0.0
733 *
734 * @return string
735 */
736 public function get_location_id() {
737 $location_id = $this->get_option( $this->get_environment() . '_location_id' );
738
739 if ( empty( $location_id ) ) {
740 $square_db_version = get_option( $this->get_plugin()->get_plugin_version_name() );
741
742 // if the Square DB version is still pre-2.2.0, fetch the location ID using the previous option name
743 if ( ! empty( $square_db_version ) && version_compare( $square_db_version, '2.2.0', '<' ) ) {
744 $location_id = $this->get_option( 'location_id' );
745 }
746 }
747
748 return $location_id;
749 }
750
751
752 /**
753 * Gets the available locations.
754 *
755 * @since 2.0.0
756 *
757 * @return \Square\Models\Location[]
758 */
759 public function get_locations() {
760
761 if ( is_array( $this->locations ) ) {
762
763 return $this->locations;
764 }
765
766 $locations_transient_key = 'wc_square_locations_' . $this->get_plugin()->get_version();
767
768 $section = isset( $_GET['section'] ) ? sanitize_text_field( wp_unslash( $_GET['section'] ) ) : false; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
769
770 // don't always need to refetch when not on Settings screen.
771 if ( ! $this->is_admin_settings_screen() || ( $this->is_admin_settings_screen() && 'update' === $section ) ) {
772 $this->locations = get_transient( $locations_transient_key );
773 }
774
775 if ( ! is_array( $this->locations ) && did_action( 'wc_square_initialized' ) ) {
776
777 $this->locations = array();
778
779 try {
780
781 // cache the locations returned so they can be used elsewhere.
782 $this->locations = $this->get_plugin()->get_api( $this->get_access_token(), $this->is_sandbox() )->get_locations();
783 set_transient( $locations_transient_key, $this->locations, HOUR_IN_SECONDS );
784
785 // check the returned IDs against what's currently configured.
786 $stored_location_id = $this->get_location_id();
787 $found = ! $stored_location_id;
788
789 foreach ( $this->locations as $location ) {
790
791 if ( $stored_location_id && $location->getId() === $stored_location_id ) {
792 $found = true;
793 break;
794 }
795 }
796
797 // if the currently set location ID is not present in the connected account's available locations, clear it locally.
798 if ( ! $found ) {
799 $this->clear_location_id();
800 }
801 } catch ( \Exception $exception ) {
802
803 $this->get_plugin()->log( 'Could not retrieve business locations.' );
804 }
805 }
806
807 return $this->locations;
808 }
809
810
811 /**
812 * Gets the configured Sync setting.
813 *
814 * @since 2.0.0
815 *
816 * @return string
817 */
818 public function get_system_of_record() {
819
820 return $this->get_option( 'system_of_record' );
821 }
822
823
824 /**
825 * Gets the configured Sync setting name.
826 *
827 * @since 2.0.0
828 *
829 * @return string or empty string if no Sync setting is configured
830 */
831 public function get_system_of_record_name() {
832
833 switch ( $this->get_system_of_record() ) {
834
835 case 'square':
836 $sor = __( 'Square', 'woocommerce-square' );
837 break;
838 case 'woocommerce':
839 $sor = __( 'WooCommerce', 'woocommerce-square' );
840 break;
841 default:
842 $sor = '';
843 break;
844 }
845
846 return $sor;
847 }
848
849 /**
850 * Gets the refresh token.
851 *
852 * @since 2.0.0
853 *
854 * @return string|null
855 */
856 public function get_refresh_token() {
857
858 if ( empty( $this->refresh_token ) ) {
859
860 $tokens = $this->get_refresh_tokens();
861 $token = null;
862
863 if ( ! empty( $tokens[ $this->get_environment() ] ) ) {
864 $token = $tokens[ $this->get_environment() ];
865 }
866
867 if ( $token && Utilities\Encryption_Utility::is_encryption_supported() ) {
868
869 $encryption = new Utilities\Encryption_Utility();
870
871 try {
872
873 $token = $encryption->decrypt_data( $token );
874
875 } catch ( \Exception $exception ) {
876
877 // log the event, but don't halt the process.
878 $this->get_plugin()->log( 'Could not decrypt refresh token. ' . $exception->getMessage() );
879 }
880 }
881
882 $this->refresh_token = $token;
883 }
884
885 /**
886 * Filters the configured refresh token.
887 *
888 * @since 2.0.0
889 *
890 * @param string $refresh_token
891 */
892 return apply_filters( 'wc_square_refresh_token', $this->refresh_token );
893 }
894
895 /**
896 * Gets the access token.
897 *
898 * @since 2.0.0
899 *
900 * @return string|null
901 */
902 public function get_access_token() {
903
904 if ( empty( $this->access_token ) || $this->is_admin_settings_screen() ) {
905
906 $tokens = $this->get_access_tokens();
907 $token = null;
908
909 if ( ! empty( $tokens[ $this->get_environment() ] ) ) {
910 $token = $tokens[ $this->get_environment() ];
911 }
912
913 if ( $token && Utilities\Encryption_Utility::is_encryption_supported() ) {
914
915 $encryption = new Utilities\Encryption_Utility();
916
917 try {
918
919 $token = $encryption->decrypt_data( $token );
920
921 } catch ( \Exception $exception ) {
922
923 // log the event, but don't halt the process.
924 $this->get_plugin()->log( 'Could not decrypt access token. ' . $exception->getMessage() );
925 }
926 }
927
928 $this->access_token = $token;
929 }
930
931 /**
932 * Filters the configured access token.
933 *
934 * @since 2.0.0
935 *
936 * @param string $access_token access token
937 */
938 return apply_filters( 'wc_square_access_token', $this->access_token );
939 }
940
941
942 /**
943 * Gets the stored access tokens.
944 *
945 * Each environment may have its own token.
946 *
947 * @since 2.0.0
948 *
949 * @return array
950 */
951 public function get_access_tokens() {
952 return (array) get_option( 'wc_square_access_tokens', array() );
953 }
954
955
956 /**
957 * Gets the stored refresh tokens.
958 *
959 * Each environment may have its own token.
960 *
961 * @since 2.0.0
962 *
963 * @return array
964 */
965 public function get_refresh_tokens() {
966 return (array) get_option( 'wc_square_refresh_tokens', array() );
967 }
968
969 /**
970 * Gets setting enabled sandbox.
971 *
972 * @since 2.1.2
973 *
974 * @return string
975 */
976 public function get_enable_sandbox() {
977 return $this->get_option( 'enable_sandbox' );
978 }
979
980 /**
981 * Tells is if the setting for enabling sandbox is checked.
982 *
983 * @since 2.1.2
984 *
985 * @return boolean
986 */
987 public function is_sandbox_setting_enabled() {
988 return 'yes' === $this->get_enable_sandbox();
989 }
990
991
992 /**
993 * Gets the configured environment.
994 *
995 * @since 2.0.0
996 *
997 * @return string
998 */
999 public function get_environment() {
1000 $sanboxed = ( defined( 'WC_SQUARE_SANDBOX' ) && WC_SQUARE_SANDBOX ) || $this->is_sandbox_setting_enabled();
1001 return $sanboxed ? 'sandbox' : 'production';
1002 }
1003
1004
1005 /**
1006 * Gets the plugin instance.
1007 *
1008 * @since 2.0.0
1009 *
1010 * @return Plugin
1011 */
1012 public function get_plugin() {
1013
1014 return $this->plugin;
1015 }
1016
1017 /**
1018 * Determines if the current request is for the Square admin settings screen.
1019 *
1020 * @since 2.1.5
1021 * @return bool True if the current request is for the Square admin settings, otherwise false.
1022 */
1023 public function is_admin_settings_screen() {
1024 return isset( $_GET['page'], $_GET['tab'] ) && 'wc-settings' === $_GET['page'] && Plugin::PLUGIN_ID === $_GET['tab']; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
1025 }
1026 }
1027