PluginProbe
WooCommerce Square / 4.5.1
WooCommerce Square v4.5.1
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 All 132 releases
woocommerce-square / includes / Plugin.php

Plugin.php in WooCommerce Square 4.5.1, at includes/Plugin.php

1,008 lines 27.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 use WooCommerce\Square\Framework\PaymentGateway\Payment_Gateway_Plugin;
29 use WooCommerce\Square\Framework\PaymentGateway\PaymentTokens\Square_Credit_Card_Payment_Token;
30 use WooCommerce\Square\Framework\Square_Helper;
31 use WooCommerce\Square\Gateway\Cash_App_Pay_Gateway;
32 use WooCommerce\Square\Handlers\Background_Job;
33 use WooCommerce\Square\Handlers\Async_Request;
34 use WooCommerce\Square\Handlers\Email;
35 use WooCommerce\Square\Handlers\Order;
36 use WooCommerce\Square\Handlers\Product;
37 use WooCommerce\Square\Handlers\Sync;
38 use WooCommerce\Square\Handlers\Products;
39
40 /**
41 * The main plugin class.
42 *
43 * @since 2.0.0
44 */
45 class Plugin extends Payment_Gateway_Plugin {
46
47
48 /** plugin version number */
49 const VERSION = WC_SQUARE_PLUGIN_VERSION;
50
51 /** plugin ID */
52 const PLUGIN_ID = 'square';
53
54 /** string gateway ID */
55 const GATEWAY_ID = 'square_credit_card';
56
57 /** string Cash App Pay gateway ID */
58 const CASH_APP_PAY_GATEWAY_ID = 'square_cash_app_pay';
59
60 /** @var Plugin plugin instance */
61 protected static $instance;
62
63 /** @var Settings settings handler instance */
64 private $settings_handler;
65
66 /** @var Handlers\Connection connection handler instance */
67 private $connection_handler;
68
69 /** @var Admin admin handler instance */
70 private $admin_handler;
71
72 /** @var Sync sync handler instance */
73 private $sync_handler;
74
75 /** @var Background_Job background handler instance */
76 private $background_job_handler;
77
78 /** @var AJAX handler instance */
79 private $ajax_handler;
80
81 /** @var Email emails handler */
82 private $email_handler;
83
84 /** @var Order orders handler */
85 private $order_handler;
86
87 /** @var Products products handler */
88 private $products_handler;
89
90 /** @var Async_Request Asynchronous request handler */
91 private $async_request_handler;
92
93 /**
94 * Constructs the plugin.
95 *
96 * @since 2.0.0
97 */
98 public function __construct() {
99
100 parent::__construct(
101 self::PLUGIN_ID,
102 self::VERSION,
103 array(
104 'text_domain' => 'woocommerce-square',
105 'gateways' => array(
106 self::GATEWAY_ID => Gateway::class,
107 self::CASH_APP_PAY_GATEWAY_ID => Cash_App_Pay_Gateway::class,
108 ),
109 'require_ssl' => true,
110 'supports' => array(
111 self::FEATURE_CAPTURE_CHARGE,
112 self::FEATURE_CUSTOMER_ID,
113 self::FEATURE_MY_PAYMENT_METHODS,
114 ),
115 'dependencies' => array(
116 'php_extensions' => array( 'curl', 'json', 'mbstring' ),
117 ),
118 )
119 );
120
121 $this->includes();
122
123 /**
124 * Fires upon plugin loaded (legacy hook).
125 *
126 * @since 1.0.0
127 */
128 do_action( 'wc_square_loaded' );
129
130 add_action( 'woocommerce_register_taxonomy', array( $this, 'init_taxonomies' ) );
131 add_action( 'admin_notices', array( $this, 'add_admin_notices' ) );
132 add_filter( 'woocommerce_locate_template', array( $this, 'locate_template' ), 20, 3 );
133 add_filter( 'woocommerce_locate_core_template', array( $this, 'locate_template' ), 20, 3 );
134
135 add_action( 'action_scheduler_init', array( $this, 'schedule_token_migration_job' ) );
136 add_action( 'wc_square_init_payment_token_migration_v2', array( $this, 'register_payment_tokens_migration_scheduler' ) );
137 add_action( 'wc_square_init_payment_token_migration', '__return_false' );
138 }
139
140
141 /**
142 * Includes required classes.
143 *
144 * @since 2.0.0
145 */
146 private function includes() {
147
148 $this->connection_handler = new Handlers\Connection( $this );
149
150 $this->sync_handler = new Sync( $this );
151
152 // background export must be loaded all the time, because otherwise background jobs simply won't work
153 require_once $this->get_framework_path() . '/Utilities/WP_Background_Job_Handler.php';
154
155 $this->background_job_handler = new Background_Job();
156
157 $this->ajax_handler = new AJAX();
158
159 $this->email_handler = new Email();
160
161 $this->order_handler = new Order();
162
163 if ( class_exists( '\WooCommerce\Square\Handlers\Async_Request' ) ) {
164 $this->async_request_handler = new Async_Request();
165 }
166 }
167
168
169 /**
170 * Adds API request logging.
171 *
172 * @internal
173 *
174 * @since 2.0.0
175 */
176 public function add_api_request_logging() {
177
178 if ( ! has_action( 'wc_square_api_request_performed' ) ) {
179 add_action( 'wc_square_api_request_performed', array( $this, 'log_api_request' ), 10, 2 );
180 }
181 }
182
183
184 /**
185 * Logs an API request & response.
186 *
187 * @since 2.0.0
188 *
189 * @param array $request request data
190 * @param array $response response data
191 * @param string|null $log_id log ID
192 */
193 public function log_api_request( $request, $response, $log_id = null ) {
194
195 if ( $this->get_settings_handler() && $this->get_settings_handler()->is_debug_enabled() ) {
196 parent::log_api_request( $request, $response, $log_id );
197 }
198 }
199
200
201 /**
202 * If debug logging is enabled, saves errors or messages to Square Log
203 *
204 * @since 2.2.4
205 * @param string $message error or message to save to log
206 * @param string $log_id optional log id to segment the files by, defaults to plugin id
207 */
208 public function log( $message, $log_id = null ) {
209
210 if ( $this->get_settings_handler() && $this->get_settings_handler()->is_debug_enabled() ) {
211 parent::log( $message, $log_id );
212 }
213 }
214
215
216 /**
217 * Initializes the lifecycle handler.
218 *
219 * @since 2.0.0
220 */
221 public function init_lifecycle_handler() {
222
223 $this->lifecycle_handler = new Lifecycle( $this );
224 }
225
226
227 /**
228 * Registers custom taxonomies.
229 *
230 * @internal
231 *
232 * @since 2.0.0
233 */
234 public function init_taxonomies() {
235
236 Product::init_taxonomies();
237 }
238
239
240 /**
241 * Initializes the general plugin functionality.
242 *
243 * @since 2.0.0
244 */
245 public function init_plugin() {
246
247 $this->settings_handler = new Settings( $this );
248 $this->products_handler = new Products( $this );
249
250 if ( ! $this->admin_handler && is_admin() ) {
251 $this->admin_handler = new Admin( $this );
252 }
253
254 /**
255 * @see wc_square_initialized
256 * @since 2.0.0
257 */
258 do_action( 'wc_square_initialized' );
259 }
260
261
262 /**
263 * Locates the WooCommerce template files from our templates directory.
264 *
265 * @internal
266 *
267 * @since 2.0.0
268 *
269 * @param string $template already found template
270 * @param string $template_name searchable template name
271 * @param string $template_path template path
272 * @return string search result for the template
273 */
274 public function locate_template( $template, $template_name, $template_path ) {
275
276 // only keep looking if no custom theme template was found
277 // or if a default WooCommerce template was found
278 if ( ! $template || Square_Helper::str_starts_with( $template, WC()->plugin_path() ) ) {
279
280 // set the path to our templates directory
281 $plugin_path = $this->get_plugin_path() . '/templates/';
282
283 // if a template is found, make it so
284 if ( is_readable( $plugin_path . $template_name ) ) {
285 $template = $plugin_path . $template_name;
286 }
287 }
288
289 return $template;
290 }
291
292
293 /** Admin methods *************************************************************************************************/
294
295
296 /**
297 * Adds admin notices.
298 *
299 * @since 2.0.0
300 */
301 public function add_admin_notices() {
302
303 // show any one-off messages
304 $this->get_message_handler()->show_messages();
305
306 // display a notice if the auto-refresh failed
307 if ( get_option( 'wc_square_refresh_failed', false ) ) {
308
309 $message = sprintf(
310 /* translators: Placeholders: %1$s - <a> tag, %2$s - </a> tag */
311 __( 'Heads up! There may be a problem with your connection to Square. In order to continue accepting payments, please %1$sdisconnect and re-connect your site%2$s.', 'woocommerce-square' ),
312 '<a href="' . esc_url( $this->get_settings_url() ) . '">',
313 '</a>'
314 );
315
316 $this->get_admin_notice_handler()->add_admin_notice(
317 $message,
318 'refresh-failed',
319 array(
320 'dismissible' => false,
321 'notice_class' => 'notice-warning',
322 )
323 );
324 }
325
326 if ( $this->get_settings_handler()->is_connected() ) {
327
328 $message = '<strong>' . __( 'You are connected to Square!', 'woocommerce-square' ) . '</strong>';
329
330 // prompt to set a location if not set
331 if ( ! $this->get_settings_handler()->get_location_id() ) {
332
333 if ( $this->is_plugin_settings() ) {
334
335 $instruction = __( 'To get started, set your business location.', 'woocommerce-square' );
336
337 } else {
338
339 $instruction = sprintf(
340 /* translators: Placeholders: %1$s - <a> tag, %2$s - </a> tag */
341 __( 'Visit the %1$splugin settings%2$s to set your business location.', 'woocommerce-square' ),
342 '<a href="' . esc_url( $this->get_settings_url() ) . '">',
343 '</a>'
344 );
345 }
346
347 $this->get_admin_notice_handler()->add_admin_notice( $message . ' ' . $instruction, 'set-location' );
348
349 } elseif ( ! $this->get_sync_handler()->get_last_synced_at() && $this->get_settings_handler()->is_product_sync_enabled() ) {
350
351 $message = __( 'You are ready to sync products!', 'woocommerce-square' );
352
353 if ( ! empty( Product::get_products_synced_with_square() ) ) {
354
355 $instruction = sprintf(
356 /* translators: Placeholders: %1$s - <strong> tag, %2$s - product count, %3$s - </strong> tag, %4$s - <a> tag, %5$s - </a> tag */
357 __( '%1$s%2$d products%3$s are marked "sync with Square". %4$sStart a new sync now &raquo;%5$s', 'woocommerce-square' ),
358 '<strong>',
359 count( Product::get_products_synced_with_square() ),
360 '</strong>',
361 '<a href="' . esc_url( add_query_arg( 'section', 'update', $this->get_settings_url() ) ) . '">',
362 '</a>'
363 );
364
365 } else {
366
367 $instruction = sprintf(
368 /* translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s - <a> tag, %4$s - </a> tag */
369 __( '%1$sNo products%2$s are marked "sync with Square". %3$sUpdate your products to sync data &raquo;%4$s', 'woocommerce-square' ),
370 '<strong>',
371 '</strong>',
372 '<a href="' . esc_url( admin_url( 'edit.php?post_type=product' ) ) . '">',
373 '</a>'
374 );
375 }
376
377 $this->get_admin_notice_handler()->add_admin_notice( $message . ' ' . $instruction, 'set-location' );
378 }
379
380 // a notice for when WC stock handling is globally disabled
381 if ( 'yes' !== get_option( 'woocommerce_manage_stock' ) && $this->get_settings_handler()->is_inventory_sync_enabled() ) {
382
383 $message = sprintf(
384 /* translators: Placeholders: %1$s - <a> tag, %2$s - </a> tag */
385 __( 'Heads up! Square is configured to sync product inventory, but WooCommerce stock management is disabled. Please %1$senable stock management%2$s to ensure product inventory counts are kept in sync.', 'woocommerce-square' ),
386 '<a href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=products&section=inventory' ) ) . '">',
387 '</a>'
388 );
389
390 $this->get_admin_notice_handler()->add_admin_notice(
391 $message,
392 'enable-wc-sync',
393 array(
394 'notice_class' => 'notice-warning',
395 )
396 );
397 }
398 } else {
399
400 if ( $this->is_plugin_settings() ) {
401
402 $instruction = __( 'To get started, connect with Square.', 'woocommerce-square' );
403
404 } else {
405
406 $instruction = sprintf(
407 /* translators: Placeholders: %1$s - <a> tag, %2$s - </a> tag */
408 __( 'To get started, %1$sconnect with Square &raquo;%2$s', 'woocommerce-square' ),
409 '<a href="' . esc_url( $this->get_settings_url() ) . '">',
410 '</a>'
411 );
412 }
413
414 $message = sprintf(
415 /* translators: Placeholders: %1$s - plugin name */
416 __( 'Thanks for installing %1$s!', 'woocommerce-square' ),
417 esc_html( $this->get_plugin_name() )
418 );
419
420 $this->get_admin_notice_handler()->add_admin_notice( $message . ' ' . $instruction, 'connect' );
421 }
422
423 // add a notice for out-of-bounds base locations
424 $this->add_base_location_admin_notice();
425
426 // add a notice when no refresh token is available
427 $this->add_missing_refresh_token_notice();
428
429 // add a tax-inclusive warning to product pages
430 $this->add_tax_inclusive_pricing_notice();
431
432 if ( get_option( 'wc_square_updated_to_2_0_0' ) ) {
433
434 $this->get_admin_notice_handler()->add_admin_notice(
435 sprintf(
436 /* translators: Placeholders: %1$s - plugin name, %2$ - plugin version number, %3$s - opening <a> HTML link tag, %4$s - closing </a> HTML link tag, %5$s - opening <a> HTML link tag, %6$s - closing </a> HTML link tag*/
437 esc_html__( '%1$s has been updated to version %2$s. In order to continue syncing product inventory, please make sure to disconnect and reconnect with Square from the %3$splugin settings%4$s and re-sync your products. Read more in the %5$supdated documentation%6$s.', 'woocommerce-square' ),
438 '<strong>' . esc_html( $this->get_plugin_name() ) . '</strong>',
439 $this->get_version(),
440 '<a href="' . esc_url( $this->get_settings_url() ) . '">',
441 '</a>',
442 '<a href="' . esc_url( $this->get_documentation_url() ) . '">',
443 '</a>'
444 ),
445 'updated-to-v2',
446 array( 'notice_class' => 'notice-warning' )
447 );
448 }
449 }
450
451
452 /**
453 * Adds a notice for out-of-bounds base locations.
454 *
455 * @since 2.0.0
456 */
457 protected function add_base_location_admin_notice() {
458
459 $accepted_countries = array(
460 'US',
461 'CA',
462 'GB',
463 'AU',
464 'JP',
465 'IE',
466 'FR',
467 'ES',
468 );
469
470 $base_location = wc_get_base_location();
471
472 if ( isset( $base_location['country'] ) && ! in_array( $base_location['country'], $accepted_countries, true ) ) {
473
474 $this->get_admin_notice_handler()->add_admin_notice(
475 sprintf(
476 /* translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s - 2-character country code, %4$s - comma separated list of 2-character country codes */
477 __( '%1$sWooCommerce Square:%2$s Your base country is %3$s, but Square can’t accept transactions from merchants outside of %4$s.', 'woocommerce-square' ),
478 '<strong>',
479 '</strong>',
480 esc_html( $base_location['country'] ),
481 esc_html( Square_Helper::list_array_items( $accepted_countries ) )
482 ),
483 'wc-square-base-location',
484 array(
485 'notice_class' => 'notice-error',
486 )
487 );
488 }
489 }
490
491 /**
492 * Adds a notice if no refresh token has been cached.
493 *
494 * @since 2.0.5
495 */
496 protected function add_missing_refresh_token_notice() {
497 if ( $this->get_settings_handler()->is_sandbox() ) {
498 return;
499 }
500
501 $refresh_token = '';
502 $settings_handler = $this->get_settings_handler();
503
504 if ( method_exists( $settings_handler, 'get_access_token' ) ) {
505 $access_token = $settings_handler->get_access_token();
506 if ( empty( $access_token ) ) {
507 // We are already in a disconnected state, don't show the warning.
508 return;
509 }
510 }
511
512 if ( method_exists( $settings_handler, 'get_refresh_token' ) ) {
513 $refresh_token = $settings_handler->get_refresh_token();
514 }
515
516 if ( empty( $refresh_token ) ) {
517 $this->get_admin_notice_handler()->add_admin_notice(
518 sprintf(
519 /* translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s - <a> tag, %4$s - </a> tag */
520 __( '%1$sWooCommerce Square:%2$s Automatic refreshing of the connection to Square is inactive. Please disconnect and reconnect to resolve.', 'woocommerce-square' ),
521 '<strong>',
522 '</strong>'
523 ),
524 'wc-square-missing-refresh-token',
525 array(
526 'dismissible' => false,
527 'notice_class' => 'notice-error',
528 )
529 );
530 }
531 }
532
533
534 /**
535 * Adds a tax-inclusive admin warning to product pages.
536 *
537 * @since 2.0.0
538 */
539 protected function add_tax_inclusive_pricing_notice() {
540 global $typenow;
541
542 // only show on product edit pages when configured that prices include tax
543 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce not required, not writing any changes.
544 if ( 'product' === $typenow && isset( $_GET['action'], $_GET['post'] ) && 'edit' === $_GET['action'] && wc_prices_include_tax() && $this->get_settings_handler()->is_product_sync_enabled() ) {
545
546 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce not required, not writing any changes.
547 $product = wc_get_product( (int) $_GET['post'] );
548
549 // only show for products configured as taxable and sync with Square
550 if ( $product instanceof \WC_Product && $product->is_taxable() && Product::is_synced_with_square( $product ) ) {
551
552 $this->get_admin_notice_handler()->add_admin_notice(
553 sprintf(
554 /* translators: Placeholders: %1$s = <strong> tag, %2$s = </strong> tag */
555 __( '%1$sWooCommerce Square:%2$s Product prices are entered inclusive of tax, but Square does not support syncing tax-inclusive prices. Please make sure your Square tax rates match your WooCommerce tax rates.', 'woocommerce-square' ),
556 '<strong>',
557 '</strong>'
558 ),
559 'wc-square-tax-inclusive',
560 array(
561 'notice_class' => 'notice-warning',
562 )
563 );
564 }
565 }
566 }
567
568
569 /**
570 * Adds admin notices for currency issues.
571 *
572 * @since 2.0.0
573 */
574 protected function add_currency_admin_notices() {
575
576 parent::add_currency_admin_notices();
577
578 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce not required, only showing a notice.
579 if ( isset( $_GET['page'] ) && 'wc-settings' === $_GET['page'] && $this->get_settings_handler()->is_connected() ) {
580
581 foreach ( $this->get_settings_handler()->get_locations() as $location ) {
582
583 if ( $this->get_settings_handler()->get_location_id() === $location->getId() && get_woocommerce_currency() !== $location->getCurrency() ) {
584
585 $this->get_admin_notice_handler()->add_admin_notice(
586 sprintf(
587 /* translators: Placeholders: %1$s = store currency, %2$s = configured Square business location currency, %3$s = <a> tag, %4$s = </a> tag, %5$s = <a> tag, %6$s = </a> tag */
588 __( 'Heads up! Your store currency is %1$s but your configured Square business location currency is %2$s, so payments cannot be processed. Please %3$schoose a different business location%4$s or change your %5$sshop currency%6$s.', 'woocommerce-square' ),
589 '<strong>' . esc_html( get_woocommerce_currency() ) . '</strong>',
590 '<strong>' . esc_html( $location->getCurrency() ) . '</strong>',
591 '<a href="' . esc_url( $this->get_settings_url() ) . '">',
592 '</a>',
593 '<a href="' . esc_url( admin_url( 'admin.php?page=wc-settings' ) ) . '">',
594 '</a>'
595 ),
596 'wc-square-currency-mismatch',
597 array(
598 'notice_class' => 'notice-error',
599 )
600 );
601 }
602 }
603 }
604 }
605
606
607 /** Helper methods ************************************************************************************************/
608
609
610 /**
611 * Returns an idempotency key to be used in Square API requests.
612 *
613 * @since 2.0.0
614 *
615 * @param string $key_input
616 * @param bool $append_key_input
617 * @return string
618 */
619 public function get_idempotency_key( $key_input = '', $append_key_input = true ) {
620
621 if ( '' === $key_input ) {
622 $key_input = uniqid( '', false );
623 }
624
625 /**
626 * Filters an idempotency key.
627 *
628 * @since 2.0.0
629 *
630 * @param string $key_input
631 */
632 return apply_filters( 'wc_square_idempotency_key', sha1( get_option( 'siteurl' ) . $key_input ) . ( $append_key_input ? ':' . $key_input : '' ) );
633 }
634
635
636 /** Conditional methods *******************************************************************************************/
637
638
639 /**
640 * Determines if viewing the plugin settings.
641 *
642 * @since 2.0.0
643 *
644 * @return bool
645 */
646 public function is_plugin_settings() {
647 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce note required, read-only check.
648 return parent::is_plugin_settings() || ( isset( $_GET['page'], $_GET['tab'] ) && 'wc-settings' === $_GET['page'] && self::PLUGIN_ID === $_GET['tab'] );
649 }
650
651 /**
652 * Determines if viewing the gateway settings.
653 *
654 * @since 2.3.0
655 *
656 * @return bool
657 */
658 public function is_gateway_settings() {
659 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce note required, read-only check.
660 return isset( $_GET['page'], $_GET['tab'], $_GET['section'] ) && 'wc-settings' === $_GET['page'] && 'checkout' === $_GET['tab'] && self::GATEWAY_ID === $_GET['section'];
661 }
662
663
664 /** Getter methods ************************************************************************************************/
665
666
667 /**
668 * Gets the main Square API handler.
669 *
670 * @since 2.0.0
671 *
672 * @param string|null $access_token API access token
673 * @return API
674 */
675 public function get_api( $access_token = null, $is_sandbox = null ) {
676
677 if ( ! $access_token ) {
678 $access_token = $this->get_settings_handler()->get_access_token();
679 }
680
681 if ( is_null( $is_sandbox ) ) {
682 $is_sandbox = $this->get_settings_handler()->is_sandbox();
683 }
684
685 return new API( $access_token, $is_sandbox );
686 }
687
688
689 /**
690 * Gets the connection handler.
691 *
692 * @since 2.0.0
693 *
694 * @return Handlers\Connection
695 */
696 public function get_connection_handler() {
697
698 return $this->connection_handler;
699 }
700
701
702 /**
703 * Gets the sync handler instance.
704 *
705 * @since 2.0.0
706 *
707 * @return Sync
708 */
709 public function get_sync_handler() {
710
711 return $this->sync_handler;
712 }
713
714
715 /**
716 * Gets the background sync handler instance.
717 *
718 * @since 2.0.0
719 *
720 * @return Background_Job
721 */
722 public function get_background_job_handler() {
723
724 return $this->background_job_handler;
725 }
726
727
728 /**
729 * Gets the settings handler instance.
730 *
731 * @since 2.0.0
732 *
733 * @return Settings
734 */
735 public function get_settings_handler() {
736
737 return $this->settings_handler;
738 }
739
740
741
742 /**
743 * Gets the admin handler instance.
744 *
745 * @since 2.0.0
746 *
747 * @return Admin|null
748 */
749 public function get_admin_handler() {
750
751 // throw a notice if calling before admin_init
752 Square_Helper::maybe_doing_it_early( 'admin_init', __METHOD__, '2.0.0' );
753
754 return $this->admin_handler;
755 }
756
757
758 /**
759 * Gets the email handler instance.
760 *
761 * @since 2.0.0
762 *
763 * @return Email
764 */
765 public function get_email_handler() {
766
767 return $this->email_handler;
768 }
769
770
771 /**
772 * Gets the order handler instance.
773 *
774 * @since 2.0.0
775 *
776 * @return Order
777 */
778 public function get_order_handler() {
779
780 return $this->order_handler;
781 }
782
783 /**
784 * Get the products handler instance/
785 *
786 * @since 2.0.8
787 *
788 * @return Products
789 */
790 public function get_products_handler() {
791 return $this->products_handler;
792 }
793
794 /**
795 * Gets the Asynchronous request handler instance.
796 *
797 * @since 4.1.0
798 *
799 * @return Async_Request
800 */
801 public function get_async_request_handler() {
802 return $this->async_request_handler;
803 }
804
805 /**
806 * Gets the plugin name.
807 *
808 * @since 2.0.0
809 *
810 * @return string
811 */
812 public function get_plugin_name() {
813
814 return __( 'WooCommerce Square', 'woocommerce-square' );
815 }
816
817
818 /**
819 * Gets the settings URL.
820 *
821 * @since 2.0.0
822 *
823 * @param null|string $gateway_id gateway ID
824 * @return string
825 */
826 public function get_settings_url( $gateway_id = null ) {
827
828 $params = array(
829 'page' => 'wc-settings',
830 'tab' => self::PLUGIN_ID,
831 );
832
833 // All usage of this return value has been escaped late.
834 // nosemgrep audit.php.wp.security.xss.query-arg
835 return add_query_arg( $params, admin_url( 'admin.php' ) );
836 }
837
838
839 /**
840 * Gets the sale page URL.
841 *
842 * @since 2.0.0
843 *
844 * @return string
845 */
846 public function get_sales_page_url() {
847
848 return 'https://woocommerce.com/products/square/';
849 }
850
851
852 /**
853 * Gets the documentation URL.
854 *
855 * @since 2.0.0
856 *
857 * @return string
858 */
859 public function get_documentation_url() {
860
861 return 'https://docs.woocommerce.com/document/woocommerce-square/';
862 }
863
864
865 /**
866 * Gets the plugin reviews page URL.
867 *
868 * Used for the 'Reviews' plugin action and review prompts.
869 *
870 * @since 2.1.7
871 *
872 * @return string
873 */
874 public function get_reviews_url() {
875
876 return $this->get_sales_page_url() ? $this->get_sales_page_url() . '#comments' : '';
877 }
878
879
880 /**
881 * Gets the support URL.
882 *
883 * @since 2.0.0
884 *
885 * @return string
886 */
887 public function get_support_url() {
888
889 return 'https://woocommerce.com/my-account/create-a-ticket/?select=1770503';
890 }
891
892
893 /**
894 * Gets __DIR__.
895 *
896 * @since 2.0.0
897 *
898 * @return string
899 */
900 protected function get_file() {
901
902 return __DIR__;
903 }
904
905
906 /**
907 * Gets the singleton instance of the plugin.
908 *
909 * @since 2.0.0
910 *
911 * @return Plugin
912 */
913 public static function instance() {
914
915 if ( null === self::$instance ) {
916 self::$instance = new self();
917 }
918
919 return self::$instance;
920 }
921
922 /**
923 * Schedules the migration of payment tokens.
924 *
925 * @since 3.8.0
926 */
927 public function schedule_token_migration_job() {
928 if ( false !== get_option( 'wc_square_payment_token_migration_complete' ) ) {
929 return;
930 }
931
932 // Remove all OLD scheduled actions to cleanup DB.
933 // TODO: Remove this in next release.
934 global $wpdb;
935 $wpdb->query( "DELETE FROM {$wpdb->prefix}actionscheduler_actions WHERE hook = 'wc_square_init_payment_token_migration'" );
936
937 if ( false === as_has_scheduled_action( 'wc_square_init_payment_token_migration_v2' ) ) {
938 as_enqueue_async_action( 'wc_square_init_payment_token_migration_v2', array( 'page' => 1 ) );
939 }
940 }
941
942 /**
943 * Migrates payment token from user_meta to WC_Payment_Token_CC.
944 *
945 * @param integer $page Pagination number.
946 * @since 3.8.0
947 */
948 public function register_payment_tokens_migration_scheduler( $page ) {
949 $payment_tokens_handler = wc_square()->get_gateway()->get_payment_tokens_handler();
950 $meta_key = $payment_tokens_handler->get_user_meta_name();
951
952 // Get 5 users in a batch.
953 $users = get_users(
954 array(
955 'fields' => array( 'ID' ),
956 'number' => 5,
957 'paged' => $page,
958 'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
959 array(
960 'key' => $meta_key,
961 'compare' => 'EXISTS',
962 ),
963 ),
964 )
965 );
966
967 // If users array is empty, then set status in options to indicate migration is complete.
968 if ( empty( $users ) ) {
969 $payment_tokens_handler->clear_all_transients();
970 update_option( 'wc_square_payment_token_migration_complete', true );
971 return;
972 }
973
974 // Re-run scheduler for the next page of users.
975 as_enqueue_async_action( 'wc_square_init_payment_token_migration_v2', array( 'page' => $page + 1 ) );
976
977 foreach ( $users as $user ) {
978 $user_payment_tokens = get_user_meta( $user->id, $meta_key, true );
979
980 if ( ! is_array( $user_payment_tokens ) || empty( $user_payment_tokens ) ) {
981 continue;
982 }
983
984 foreach ( $user_payment_tokens as $token => $user_payment_token_data ) {
985 // Check if token already exists in WC_Payment_Token_CC.
986 if ( $payment_tokens_handler->user_has_token( $user->id, $token ) ) {
987 continue;
988 }
989
990 $payment_token = new Square_Credit_Card_Payment_Token();
991 $payment_token->set_token( $token );
992 $payment_token->set_card_type( $user_payment_token_data['card_type'] );
993 $payment_token->set_last4( $user_payment_token_data['last_four'] );
994 $payment_token->set_expiry_month( $user_payment_token_data['exp_month'] );
995 $payment_token->set_expiry_year( $user_payment_token_data['exp_year'] );
996 $payment_token->set_user_id( $user->id );
997 $payment_token->set_gateway_id( wc_square()->get_gateway()->get_id() );
998
999 if ( isset( $user_payment_token_data['nickname'] ) ) {
1000 $payment_token->set_nickname( $user_payment_token_data['nickname'] );
1001 }
1002
1003 $payment_token->save();
1004 }
1005 }
1006 }
1007 }
1008