Version Description
- 2020-09-02 =
- Add - Initial support for WooCommerce Subscriptions: Signing up for subscriptions, scheduled payments, and customer-initiated payment method changes.
- Add - Added a link to transaction details from order screens.
- Add - Allow merchant to edit statement descriptor.
- Fix - Do not redirect to the onboarding page after completing the WC4.5-beta wizard.
- Fix - Save order metadata before the payment is completed to avoid missing payments.
- Update - Bumped the minimum Jetpack requirement to version 8.2.
Download this release
Release Info
| Developer | automattic |
| Plugin | |
| Version | 1.4.0 |
| Comparing to | |
| See all releases | |
Code changes from version 1.3.0 to 1.4.0
- changelog.txt +8 -0
- includes/class-wc-payment-gateway-wcpay.php +399 -196
- includes/class-wc-payments-account.php +57 -1
- includes/class-wc-payments-token-service.php +6 -4
- includes/class-wc-payments.php +9 -2
- includes/compat/subscriptions/class-wc-payment-gateway-wcpay-subscriptions-compat.php +139 -0
- includes/data-types/class-payment-information.php +176 -0
- includes/wc-payment-api/class-wc-payments-api-client.php +25 -2
- includes/wc-payment-api/class-wc-payments-http.php +7 -4
- readme.txt +10 -2
- vendor/autoload.php +1 -1
- vendor/autoload_packages.php +2 -2
- vendor/automattic/jetpack-config/src/class-config.php +17 -7
- vendor/automattic/jetpack-connection/.gitignore +1 -0
- vendor/automattic/jetpack-connection/composer.json +8 -5
- vendor/automattic/jetpack-connection/docs/register-site.md +92 -5
- vendor/automattic/jetpack-connection/legacy/class-jetpack-ixr-client.php +3 -2
- vendor/automattic/jetpack-connection/legacy/class-jetpack-ixr-clientmulticall.php +6 -3
- vendor/automattic/jetpack-connection/legacy/class-jetpack-xmlrpc-server.php +25 -19
- vendor/automattic/jetpack-connection/src/class-error-handler.php +621 -0
- vendor/automattic/jetpack-connection/src/class-manager.php +237 -49
- vendor/automattic/jetpack-connection/src/class-plugin-storage.php +55 -18
- vendor/automattic/jetpack-connection/src/class-plugin.php +28 -1
- vendor/automattic/jetpack-connection/src/class-rest-connector.php +234 -6
- vendor/automattic/jetpack-connection/src/error-handlers/class-invalid-blog-token.php +94 -0
- vendor/automattic/jetpack-constants/phpunit.xml +7 -0
- vendor/automattic/jetpack-options/composer.json +1 -1
- vendor/automattic/jetpack-options/legacy/class-jetpack-options.php +26 -3
- vendor/automattic/jetpack-roles/phpunit.xml +7 -0
- vendor/automattic/jetpack-status/README.md +34 -0
- vendor/automattic/jetpack-status/composer.json +31 -0
- vendor/automattic/jetpack-status/src/class-status.php +235 -0
- vendor/composer/ClassLoader.php +1 -1
- vendor/composer/autoload_classmap.php +3 -0
- vendor/composer/autoload_classmap_package.php +28 -16
- vendor/composer/autoload_files_package.php +1 -1
- vendor/composer/autoload_real.php +7 -10
- vendor/composer/autoload_static.php +7 -4
- vendor/composer/installed.json +70 -34
- woocommerce-payments.php +35 -2
changelog.txt
CHANGED
|
@@ -1,5 +1,13 @@
|
|
| 1 |
*** WooCommerce Payments Changelog ***
|
| 2 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3 |
= 1.3.0 - 2020-08-17 =
|
| 4 |
* Add - Support for saved cards.
|
| 5 |
* Add - Search bar for transactions.
|
| 1 |
*** WooCommerce Payments Changelog ***
|
| 2 |
|
| 3 |
+
= 1.4.0 - 2020-09-02 =
|
| 4 |
+
* Add - Initial support for WooCommerce Subscriptions: Signing up for subscriptions, scheduled payments, and customer-initiated payment method changes.
|
| 5 |
+
* Add - Added a link to transaction details from order screens.
|
| 6 |
+
* Add - Allow merchant to edit statement descriptor.
|
| 7 |
+
* Fix - Do not redirect to the onboarding page after completing the WC4.5-beta wizard.
|
| 8 |
+
* Fix - Save order metadata before the payment is completed to avoid missing payments.
|
| 9 |
+
* Update - Bumped the minimum Jetpack requirement to version 8.2.
|
| 10 |
+
|
| 11 |
= 1.3.0 - 2020-08-17 =
|
| 12 |
* Add - Support for saved cards.
|
| 13 |
* Add - Search bar for transactions.
|
includes/class-wc-payment-gateway-wcpay.php
CHANGED
|
@@ -10,6 +10,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|
| 10 |
}
|
| 11 |
|
| 12 |
use WCPay\Logger;
|
|
|
|
| 13 |
use WCPay\Exceptions\WC_Payments_Intent_Authentication_Exception;
|
| 14 |
use WCPay\Tracker;
|
| 15 |
|
|
@@ -99,27 +100,32 @@ class WC_Payment_Gateway_WCPay extends WC_Payment_Gateway_CC {
|
|
| 99 |
|
| 100 |
// Define setting fields.
|
| 101 |
$this->form_fields = [
|
| 102 |
-
'enabled'
|
| 103 |
'title' => __( 'Enable/disable', 'woocommerce-payments' ),
|
| 104 |
'label' => __( 'Enable WooCommerce Payments', 'woocommerce-payments' ),
|
| 105 |
'type' => 'checkbox',
|
| 106 |
'description' => '',
|
| 107 |
'default' => 'no',
|
| 108 |
],
|
| 109 |
-
'account_details'
|
| 110 |
'type' => 'account_actions',
|
| 111 |
],
|
| 112 |
-
'account_status'
|
| 113 |
'type' => 'account_status',
|
| 114 |
],
|
| 115 |
-
'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 116 |
'title' => __( 'Manual capture', 'woocommerce-payments' ),
|
| 117 |
'label' => __( 'Issue an authorization on checkout, and capture later.', 'woocommerce-payments' ),
|
| 118 |
'type' => 'checkbox',
|
| 119 |
'description' => __( 'Charge must be captured within 7 days of authorization, otherwise the authorization and order will be canceled.', 'woocommerce-payments' ),
|
| 120 |
'default' => 'no',
|
| 121 |
],
|
| 122 |
-
'test_mode'
|
| 123 |
'title' => __( 'Test mode', 'woocommerce-payments' ),
|
| 124 |
'label' => __( 'Enable test mode', 'woocommerce-payments' ),
|
| 125 |
'type' => 'checkbox',
|
|
@@ -127,7 +133,7 @@ class WC_Payment_Gateway_WCPay extends WC_Payment_Gateway_CC {
|
|
| 127 |
'default' => 'no',
|
| 128 |
'desc_tip' => true,
|
| 129 |
],
|
| 130 |
-
'enable_logging'
|
| 131 |
'title' => __( 'Debug log', 'woocommerce-payments' ),
|
| 132 |
'label' => __( 'When enabled debug notes will be added to the log.', 'woocommerce-payments' ),
|
| 133 |
'type' => 'checkbox',
|
|
@@ -146,7 +152,9 @@ class WC_Payment_Gateway_WCPay extends WC_Payment_Gateway_CC {
|
|
| 146 |
// Load the settings.
|
| 147 |
$this->init_settings();
|
| 148 |
|
|
|
|
| 149 |
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, [ $this, 'process_admin_options' ] );
|
|
|
|
| 150 |
add_action( 'woocommerce_order_actions', [ $this, 'add_order_actions' ] );
|
| 151 |
add_action( 'woocommerce_order_action_capture_charge', [ $this, 'capture_charge' ] );
|
| 152 |
add_action( 'woocommerce_order_action_cancel_authorization', [ $this, 'cancel_authorization' ] );
|
|
@@ -388,223 +396,263 @@ class WC_Payment_Gateway_WCPay extends WC_Payment_Gateway_CC {
|
|
| 388 |
/**
|
| 389 |
* Process the payment for a given order.
|
| 390 |
*
|
| 391 |
-
* @param int
|
|
|
|
| 392 |
*
|
| 393 |
* @return array|null An array with result of payment and redirect URL, or nothing.
|
| 394 |
*/
|
| 395 |
-
public function process_payment( $order_id ) {
|
| 396 |
$order = wc_get_order( $order_id );
|
| 397 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 398 |
}
|
| 399 |
|
| 400 |
/**
|
| 401 |
* Process the payment for a given order.
|
| 402 |
*
|
| 403 |
-
* @param WC_Order
|
| 404 |
-
* @param WC_Cart
|
|
|
|
|
|
|
|
|
|
| 405 |
*
|
| 406 |
* @return array|null An array with result of payment and redirect URL, or nothing.
|
|
|
|
| 407 |
*/
|
| 408 |
-
public function process_payment_for_order( $order, $cart ) {
|
| 409 |
-
|
| 410 |
-
|
| 411 |
-
|
| 412 |
-
|
| 413 |
-
|
| 414 |
-
|
| 415 |
-
|
| 416 |
-
|
| 417 |
-
|
| 418 |
-
|
| 419 |
-
|
| 420 |
-
|
| 421 |
-
|
| 422 |
-
|
| 423 |
-
$user = wp_get_current_user();
|
| 424 |
-
$customer_id = $this->customer_service->get_customer_id_by_user_id( $user->ID );
|
| 425 |
-
|
| 426 |
-
if ( null === $customer_id ) {
|
| 427 |
-
// Create a new customer.
|
| 428 |
-
$customer_id = $this->customer_service->create_customer_for_user( $user, $name, $email );
|
| 429 |
-
} else {
|
| 430 |
-
// Update the existing customer with the current details. In the event the old customer can't be
|
| 431 |
-
// found a new one is created, so we update the customer ID here as well.
|
| 432 |
-
$customer_id = $this->customer_service->update_customer_for_user( $customer_id, $user, $name, $email );
|
| 433 |
-
}
|
| 434 |
|
| 435 |
-
|
| 436 |
-
|
| 437 |
-
|
| 438 |
-
|
| 439 |
-
|
| 440 |
-
// If updating the payment method fails, log the error message but catch the error to avoid crashing the checkout flow.
|
| 441 |
-
Logger::log( 'Error when updating saved payment method: ' . $e->getMessage() );
|
| 442 |
-
}
|
| 443 |
-
}
|
| 444 |
|
| 445 |
-
|
| 446 |
-
|
| 447 |
-
|
| 448 |
-
|
| 449 |
-
|
| 450 |
-
|
| 451 |
-
|
| 452 |
-
|
| 453 |
-
|
| 454 |
-
|
| 455 |
-
|
| 456 |
-
$payment_method,
|
| 457 |
-
$customer_id,
|
| 458 |
-
$manual_capture,
|
| 459 |
-
$save_payment_method,
|
| 460 |
-
$metadata,
|
| 461 |
-
$this->get_level3_data_from_order( $order )
|
| 462 |
-
);
|
| 463 |
|
| 464 |
-
|
| 465 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 466 |
|
| 467 |
-
|
| 468 |
-
try {
|
| 469 |
-
$this->token_service->add_payment_method_to_user( $payment_method, wp_get_current_user() );
|
| 470 |
-
} catch ( Exception $e ) {
|
| 471 |
-
// If saving the token fails, log the error message but catch the error to avoid crashing the checkout flow.
|
| 472 |
-
Logger::log( 'Error when saving payment method: ' . $e->getMessage() );
|
| 473 |
-
}
|
| 474 |
-
}
|
| 475 |
|
| 476 |
-
|
| 477 |
-
|
| 478 |
-
|
| 479 |
-
|
| 480 |
-
/* translators: %1: the successfully charged amount, %2: transaction ID of the payment */
|
| 481 |
-
__( 'A payment of %1$s was <strong>successfully charged</strong> using WooCommerce Payments (<code>%2$s</code>).', 'woocommerce-payments' ),
|
| 482 |
-
[
|
| 483 |
-
'strong' => '<strong>',
|
| 484 |
-
'code' => '<code>',
|
| 485 |
-
]
|
| 486 |
-
),
|
| 487 |
-
wc_price( $amount ),
|
| 488 |
-
$intent_id
|
| 489 |
-
);
|
| 490 |
|
| 491 |
-
|
| 492 |
-
|
| 493 |
-
|
| 494 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 495 |
|
| 496 |
-
|
| 497 |
-
|
| 498 |
-
|
| 499 |
-
|
| 500 |
-
|
| 501 |
-
|
| 502 |
-
|
| 503 |
-
|
| 504 |
-
|
| 505 |
-
|
| 506 |
-
'code' => '<code>',
|
| 507 |
-
]
|
| 508 |
-
),
|
| 509 |
-
wc_price( $amount ),
|
| 510 |
-
$intent_id
|
| 511 |
-
);
|
| 512 |
|
| 513 |
-
|
| 514 |
-
|
| 515 |
-
|
| 516 |
-
|
| 517 |
-
|
| 518 |
-
|
| 519 |
-
|
| 520 |
-
|
| 521 |
-
|
| 522 |
-
|
| 523 |
-
// Add a note in case the customer does not complete the payment (exits the page),
|
| 524 |
-
// so the store owner has some information about what happened to create an order.
|
| 525 |
-
$note = sprintf(
|
| 526 |
-
WC_Payments_Utils::esc_interpolated_html(
|
| 527 |
-
/* translators: %1: the authorized amount, %2: transaction ID of the payment */
|
| 528 |
-
__( 'A payment of %1$s was <strong>started</strong> using WooCommerce Payments (<code>%2$s</code>).', 'woocommerce-payments' ),
|
| 529 |
-
[
|
| 530 |
-
'strong' => '<strong>',
|
| 531 |
-
'code' => '<code>',
|
| 532 |
-
]
|
| 533 |
-
),
|
| 534 |
-
wc_price( $amount ),
|
| 535 |
-
$intent_id
|
| 536 |
-
);
|
| 537 |
-
$order->add_order_note( $note );
|
| 538 |
|
| 539 |
-
|
| 540 |
-
|
| 541 |
-
|
| 542 |
-
|
| 543 |
-
|
| 544 |
-
|
| 545 |
-
|
| 546 |
-
|
| 547 |
-
|
| 548 |
-
|
| 549 |
-
|
| 550 |
-
|
| 551 |
-
wp_create_nonce( 'wcpay_update_order_status_nonce' )
|
| 552 |
-
),
|
| 553 |
-
];
|
| 554 |
}
|
| 555 |
-
} else {
|
| 556 |
-
$order->payment_complete();
|
| 557 |
}
|
| 558 |
|
| 559 |
-
|
| 560 |
-
|
|
|
|
|
|
|
| 561 |
|
| 562 |
-
|
| 563 |
-
|
| 564 |
-
|
| 565 |
-
|
| 566 |
-
|
| 567 |
-
|
| 568 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 569 |
|
| 570 |
-
|
|
|
|
|
|
|
|
|
|
| 571 |
|
| 572 |
-
|
| 573 |
-
|
| 574 |
-
|
| 575 |
-
|
| 576 |
-
|
| 577 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 578 |
|
| 579 |
-
|
| 580 |
-
|
| 581 |
-
*
|
| 582 |
-
* @return string
|
| 583 |
-
* @throws Exception - If no payment method is found.
|
| 584 |
-
*/
|
| 585 |
-
private function get_payment_method_from_request() {
|
| 586 |
-
// phpcs:disable WordPress.Security.NonceVerification.Missing
|
| 587 |
-
if ( empty( $_POST['wcpay-payment-method'] ) && empty( $_POST[ 'wc-' . self::GATEWAY_ID . '-payment-token' ] ) ) {
|
| 588 |
-
// If no payment method is set then stop here with an error.
|
| 589 |
-
throw new Exception( __( 'Payment method not found.', 'woocommerce-payments' ) );
|
| 590 |
-
}
|
| 591 |
|
| 592 |
-
|
|
|
|
|
|
|
|
|
|
| 593 |
|
| 594 |
-
|
| 595 |
-
|
| 596 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 597 |
|
| 598 |
-
|
| 599 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 600 |
}
|
|
|
|
| 601 |
|
| 602 |
-
|
|
|
|
|
|
|
| 603 |
}
|
| 604 |
|
| 605 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 606 |
|
| 607 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 608 |
}
|
| 609 |
|
| 610 |
/**
|
|
@@ -717,6 +765,127 @@ class WC_Payment_Gateway_WCPay extends WC_Payment_Gateway_CC {
|
|
| 717 |
return ob_get_clean();
|
| 718 |
}
|
| 719 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 720 |
/**
|
| 721 |
* Generate markup for account actions
|
| 722 |
*/
|
|
@@ -995,6 +1164,12 @@ class WC_Payment_Gateway_WCPay extends WC_Payment_Gateway_CC {
|
|
| 995 |
$intent_id
|
| 996 |
);
|
| 997 |
$order->add_order_note( $note );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 998 |
$order->payment_complete( $intent_id );
|
| 999 |
break;
|
| 1000 |
case 'requires_capture':
|
|
@@ -1013,6 +1188,12 @@ class WC_Payment_Gateway_WCPay extends WC_Payment_Gateway_CC {
|
|
| 1013 |
// Save the note separately because if there is no change in status
|
| 1014 |
// then the note is not saved using WC_Order::update_status.
|
| 1015 |
$order->add_order_note( $note );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1016 |
$order->update_status( 'on-hold' );
|
| 1017 |
$order->set_transaction_id( $intent_id );
|
| 1018 |
break;
|
|
@@ -1037,16 +1218,12 @@ class WC_Payment_Gateway_WCPay extends WC_Payment_Gateway_CC {
|
|
| 1037 |
}
|
| 1038 |
|
| 1039 |
if ( 'succeeded' === $status || 'requires_capture' === $status ) {
|
| 1040 |
-
// The order is successful, so update it to reflect that.
|
| 1041 |
-
$order->update_meta_data( '_charge_id', $intent->get_charge_id() );
|
| 1042 |
-
$order->update_meta_data( '_intention_status', $status );
|
| 1043 |
-
$order->save();
|
| 1044 |
-
|
| 1045 |
wc_reduce_stock_levels( $order_id );
|
| 1046 |
WC()->cart->empty_cart();
|
| 1047 |
|
| 1048 |
if ( ! empty( $payment_method_id ) ) {
|
| 1049 |
try {
|
|
|
|
| 1050 |
$this->token_service->add_payment_method_to_user( $payment_method_id, wp_get_current_user() );
|
| 1051 |
} catch ( Exception $e ) {
|
| 1052 |
// If saving the token fails, log the error message but catch the error to avoid crashing the checkout flow.
|
|
@@ -1112,13 +1289,13 @@ class WC_Payment_Gateway_WCPay extends WC_Payment_Gateway_CC {
|
|
| 1112 |
public function add_payment_method() {
|
| 1113 |
try {
|
| 1114 |
|
| 1115 |
-
// phpcs:
|
| 1116 |
if ( ! isset( $_POST['wcpay-setup-intent'] ) ) {
|
| 1117 |
throw new Exception( __( 'A WooCommerce Payments payment method was not provided', 'woocommerce-payments' ) );
|
| 1118 |
}
|
| 1119 |
|
|
|
|
| 1120 |
$setup_intent_id = ! empty( $_POST['wcpay-setup-intent'] ) ? wc_clean( $_POST['wcpay-setup-intent'] ) : false;
|
| 1121 |
-
// phpcs:enable WordPress.Security.NonceVerification.Missing,WordPress.Security.ValidatedSanitizedInput.MissingUnslash
|
| 1122 |
|
| 1123 |
$customer_id = $this->customer_service->get_customer_id_by_user_id( get_current_user_id() );
|
| 1124 |
|
|
@@ -1154,7 +1331,8 @@ class WC_Payment_Gateway_WCPay extends WC_Payment_Gateway_CC {
|
|
| 1154 |
* @throws Exception - When an error occurs in setup intent creation.
|
| 1155 |
*/
|
| 1156 |
public function create_setup_intent() {
|
| 1157 |
-
|
|
|
|
| 1158 |
|
| 1159 |
// Determine the customer adding the payment method, create one if we don't have one already.
|
| 1160 |
$user = wp_get_current_user();
|
|
@@ -1164,7 +1342,7 @@ class WC_Payment_Gateway_WCPay extends WC_Payment_Gateway_CC {
|
|
| 1164 |
}
|
| 1165 |
|
| 1166 |
return $this->payments_api_client->create_setup_intent(
|
| 1167 |
-
$
|
| 1168 |
$customer_id
|
| 1169 |
);
|
| 1170 |
}
|
|
@@ -1195,4 +1373,29 @@ class WC_Payment_Gateway_WCPay extends WC_Payment_Gateway_CC {
|
|
| 1195 |
);
|
| 1196 |
}
|
| 1197 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1198 |
}
|
| 10 |
}
|
| 11 |
|
| 12 |
use WCPay\Logger;
|
| 13 |
+
use WCPay\DataTypes\Payment_Information;
|
| 14 |
use WCPay\Exceptions\WC_Payments_Intent_Authentication_Exception;
|
| 15 |
use WCPay\Tracker;
|
| 16 |
|
| 100 |
|
| 101 |
// Define setting fields.
|
| 102 |
$this->form_fields = [
|
| 103 |
+
'enabled' => [
|
| 104 |
'title' => __( 'Enable/disable', 'woocommerce-payments' ),
|
| 105 |
'label' => __( 'Enable WooCommerce Payments', 'woocommerce-payments' ),
|
| 106 |
'type' => 'checkbox',
|
| 107 |
'description' => '',
|
| 108 |
'default' => 'no',
|
| 109 |
],
|
| 110 |
+
'account_details' => [
|
| 111 |
'type' => 'account_actions',
|
| 112 |
],
|
| 113 |
+
'account_status' => [
|
| 114 |
'type' => 'account_status',
|
| 115 |
],
|
| 116 |
+
'account_statement_descriptor' => [
|
| 117 |
+
'type' => 'account_statement_descriptor',
|
| 118 |
+
'title' => __( 'Customer bank statement', 'woocommerce-payments' ),
|
| 119 |
+
'description' => __( 'Edit the way your store name appears on your customers’ bank statements.', 'woocommerce-payments' ),
|
| 120 |
+
],
|
| 121 |
+
'manual_capture' => [
|
| 122 |
'title' => __( 'Manual capture', 'woocommerce-payments' ),
|
| 123 |
'label' => __( 'Issue an authorization on checkout, and capture later.', 'woocommerce-payments' ),
|
| 124 |
'type' => 'checkbox',
|
| 125 |
'description' => __( 'Charge must be captured within 7 days of authorization, otherwise the authorization and order will be canceled.', 'woocommerce-payments' ),
|
| 126 |
'default' => 'no',
|
| 127 |
],
|
| 128 |
+
'test_mode' => [
|
| 129 |
'title' => __( 'Test mode', 'woocommerce-payments' ),
|
| 130 |
'label' => __( 'Enable test mode', 'woocommerce-payments' ),
|
| 131 |
'type' => 'checkbox',
|
| 133 |
'default' => 'no',
|
| 134 |
'desc_tip' => true,
|
| 135 |
],
|
| 136 |
+
'enable_logging' => [
|
| 137 |
'title' => __( 'Debug log', 'woocommerce-payments' ),
|
| 138 |
'label' => __( 'When enabled debug notes will be added to the log.', 'woocommerce-payments' ),
|
| 139 |
'type' => 'checkbox',
|
| 152 |
// Load the settings.
|
| 153 |
$this->init_settings();
|
| 154 |
|
| 155 |
+
add_filter( 'woocommerce_settings_api_sanitized_fields_' . $this->id, [ $this, 'sanitize_plugin_settings' ] );
|
| 156 |
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, [ $this, 'process_admin_options' ] );
|
| 157 |
+
add_action( 'admin_notices', [ $this, 'display_errors' ], 9999 );
|
| 158 |
add_action( 'woocommerce_order_actions', [ $this, 'add_order_actions' ] );
|
| 159 |
add_action( 'woocommerce_order_action_capture_charge', [ $this, 'capture_charge' ] );
|
| 160 |
add_action( 'woocommerce_order_action_cancel_authorization', [ $this, 'cancel_authorization' ] );
|
| 396 |
/**
|
| 397 |
* Process the payment for a given order.
|
| 398 |
*
|
| 399 |
+
* @param int $order_id Order ID to process the payment for.
|
| 400 |
+
* @param bool $force_save_payment_method Whether this is a one-off payment (false) or it's the first installment of a recurring payment (true).
|
| 401 |
*
|
| 402 |
* @return array|null An array with result of payment and redirect URL, or nothing.
|
| 403 |
*/
|
| 404 |
+
public function process_payment( $order_id, $force_save_payment_method = false ) {
|
| 405 |
$order = wc_get_order( $order_id );
|
| 406 |
+
|
| 407 |
+
try {
|
| 408 |
+
// phpcs:ignore WordPress.Security.NonceVerification.Missing
|
| 409 |
+
$payment_information = Payment_Information::from_payment_request( $_POST );
|
| 410 |
+
$manual_capture = 'yes' === $this->get_option( 'manual_capture' );
|
| 411 |
+
|
| 412 |
+
return $this->process_payment_for_order( $order, WC()->cart, $payment_information, $manual_capture, $force_save_payment_method );
|
| 413 |
+
} catch ( Exception $e ) {
|
| 414 |
+
// TODO: Create plugin specific exceptions so that we can be smarter about what we create notices for.
|
| 415 |
+
wc_add_notice( $e->getMessage(), 'error' );
|
| 416 |
+
|
| 417 |
+
$order->update_status( 'failed' );
|
| 418 |
+
|
| 419 |
+
return [
|
| 420 |
+
'result' => 'fail',
|
| 421 |
+
'redirect' => '',
|
| 422 |
+
];
|
| 423 |
+
}
|
| 424 |
}
|
| 425 |
|
| 426 |
/**
|
| 427 |
* Process the payment for a given order.
|
| 428 |
*
|
| 429 |
+
* @param WC_Order $order Order.
|
| 430 |
+
* @param WC_Cart $cart Cart.
|
| 431 |
+
* @param WC_Payment_Information $payment_information Payment info.
|
| 432 |
+
* @param bool $manual_capture Indicates whether this payment is merchant-initiated (true) or customer-initated (false).
|
| 433 |
+
* @param bool $force_save_payment_method Whether this is a one-off payment (false) or it's the first installment of a recurring payment (true).
|
| 434 |
*
|
| 435 |
* @return array|null An array with result of payment and redirect URL, or nothing.
|
| 436 |
+
* @throws WC_Payments_API_Exception Error processing the payment.
|
| 437 |
*/
|
| 438 |
+
public function process_payment_for_order( $order, $cart, $payment_information, $manual_capture, $force_save_payment_method = false ) {
|
| 439 |
+
// phpcs:ignore WordPress.Security.NonceVerification.Missing
|
| 440 |
+
$save_payment_method = ! $payment_information->is_using_saved_payment_method() && ( ! empty( $_POST[ 'wc-' . self::GATEWAY_ID . '-new-payment-method' ] ) || $force_save_payment_method );
|
| 441 |
+
|
| 442 |
+
$order_id = $order->get_id();
|
| 443 |
+
$amount = $order->get_total();
|
| 444 |
+
$user = $order->get_user() ?? wp_get_current_user();
|
| 445 |
+
$name = sanitize_text_field( $order->get_billing_first_name() ) . ' ' . sanitize_text_field( $order->get_billing_last_name() );
|
| 446 |
+
$email = sanitize_email( $order->get_billing_email() );
|
| 447 |
+
$metadata = [
|
| 448 |
+
'customer_name' => $name,
|
| 449 |
+
'customer_email' => $email,
|
| 450 |
+
'site_url' => esc_url( get_site_url() ),
|
| 451 |
+
'order_id' => $order_id,
|
| 452 |
+
];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 453 |
|
| 454 |
+
// We only force save the card during subscriptions.
|
| 455 |
+
// TODO: This is a bit flawed; make these 2 functionalities distinct.
|
| 456 |
+
if ( $force_save_payment_method ) {
|
| 457 |
+
$metadata['payment_type'] = 'recurring';
|
| 458 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
| 459 |
|
| 460 |
+
// Determine the customer making the payment, create one if we don't have one already.
|
| 461 |
+
$customer_id = $this->customer_service->get_customer_id_by_user_id( $user->ID );
|
| 462 |
+
|
| 463 |
+
if ( null === $customer_id ) {
|
| 464 |
+
// Create a new customer.
|
| 465 |
+
$customer_id = $this->customer_service->create_customer_for_user( $user, $name, $email );
|
| 466 |
+
} else {
|
| 467 |
+
// Update the existing customer with the current details. In the event the old customer can't be
|
| 468 |
+
// found a new one is created, so we update the customer ID here as well.
|
| 469 |
+
$customer_id = $this->customer_service->update_customer_for_user( $customer_id, $user, $name, $email );
|
| 470 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 471 |
|
| 472 |
+
// Update saved payment method information with checkout values, as some saved methods might not have billing details.
|
| 473 |
+
if ( $payment_information->is_using_saved_payment_method() ) {
|
| 474 |
+
try {
|
| 475 |
+
$this->customer_service->update_payment_method_with_billing_details_from_order( $payment_information->get_payment_method(), $order );
|
| 476 |
+
} catch ( Exception $e ) {
|
| 477 |
+
// If updating the payment method fails, log the error message but catch the error to avoid crashing the checkout flow.
|
| 478 |
+
Logger::log( 'Error when updating saved payment method: ' . $e->getMessage() );
|
| 479 |
+
}
|
| 480 |
+
}
|
| 481 |
|
| 482 |
+
$intent_failed = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 483 |
|
| 484 |
+
// In case amount is 0 and we're not saving the payment method, we won't be using intents and can confirm the order payment.
|
| 485 |
+
if ( 0 === $amount && ! $save_payment_method ) {
|
| 486 |
+
$order->payment_complete();
|
| 487 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 488 |
|
| 489 |
+
if ( $amount > 0 ) {
|
| 490 |
+
// Create intention, try to confirm it & capture the charge (if 3DS is not required).
|
| 491 |
+
$intent = $this->payments_api_client->create_and_confirm_intention(
|
| 492 |
+
WC_Payments_Utils::prepare_amount( $amount, 'USD' ),
|
| 493 |
+
'usd',
|
| 494 |
+
$payment_information->get_payment_method(),
|
| 495 |
+
$customer_id,
|
| 496 |
+
$manual_capture,
|
| 497 |
+
$save_payment_method,
|
| 498 |
+
$metadata,
|
| 499 |
+
$this->get_level3_data_from_order( $order ),
|
| 500 |
+
$payment_information->is_merchant_initiated()
|
| 501 |
+
);
|
| 502 |
|
| 503 |
+
$intent_id = $intent->get_id();
|
| 504 |
+
$status = $intent->get_status();
|
| 505 |
+
$charge_id = $intent->get_charge_id();
|
| 506 |
+
} else {
|
| 507 |
+
// For $0 orders, we need to save the payment method using a setup intent.
|
| 508 |
+
$intent = $this->payments_api_client->create_setup_intent(
|
| 509 |
+
$payment_information->get_payment_method(),
|
| 510 |
+
$customer_id,
|
| 511 |
+
'true'
|
| 512 |
+
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 513 |
|
| 514 |
+
$intent_id = $intent['id'];
|
| 515 |
+
$status = $intent['status'];
|
| 516 |
+
$charge_id = '';
|
| 517 |
+
|
| 518 |
+
// In SCA cases the setup intent status might be requires_action and we should display the authentication modal.
|
| 519 |
+
// For now, since we're not supporting SCA cards, we can ignore that status.
|
| 520 |
+
if ( 'succeeded' !== $status ) {
|
| 521 |
+
throw new Exception( __( 'Failed to add the provided payment method. Please try again later', 'woocommerce-payments' ) );
|
| 522 |
+
}
|
| 523 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 524 |
|
| 525 |
+
if ( ! empty( $intent ) ) {
|
| 526 |
+
if ( 'succeeded' !== $status && 'requires_capture' !== $status ) {
|
| 527 |
+
$intent_failed = true;
|
| 528 |
+
}
|
| 529 |
+
|
| 530 |
+
if ( $save_payment_method && ! $intent_failed ) {
|
| 531 |
+
try {
|
| 532 |
+
$token = $this->token_service->add_payment_method_to_user( $payment_information->get_payment_method(), $user );
|
| 533 |
+
$payment_information->set_token( $token );
|
| 534 |
+
} catch ( Exception $e ) {
|
| 535 |
+
// If saving the token fails, log the error message but catch the error to avoid crashing the checkout flow.
|
| 536 |
+
Logger::log( 'Error when saving payment method: ' . $e->getMessage() );
|
|
|
|
|
|
|
|
|
|
| 537 |
}
|
|
|
|
|
|
|
| 538 |
}
|
| 539 |
|
| 540 |
+
if ( $payment_information->is_using_saved_payment_method() ) {
|
| 541 |
+
$token = $payment_information->get_payment_token();
|
| 542 |
+
$this->add_token_to_order( $order, $token );
|
| 543 |
+
}
|
| 544 |
|
| 545 |
+
switch ( $status ) {
|
| 546 |
+
case 'succeeded':
|
| 547 |
+
$note = sprintf(
|
| 548 |
+
WC_Payments_Utils::esc_interpolated_html(
|
| 549 |
+
/* translators: %1: the successfully charged amount, %2: transaction ID of the payment */
|
| 550 |
+
__( 'A payment of %1$s was <strong>successfully charged</strong> using WooCommerce Payments (<code>%2$s</code>).', 'woocommerce-payments' ),
|
| 551 |
+
[
|
| 552 |
+
'strong' => '<strong>',
|
| 553 |
+
'code' => '<code>',
|
| 554 |
+
]
|
| 555 |
+
),
|
| 556 |
+
wc_price( $amount ),
|
| 557 |
+
$intent_id
|
| 558 |
+
);
|
| 559 |
|
| 560 |
+
$order->update_meta_data( '_intent_id', $intent_id );
|
| 561 |
+
$order->update_meta_data( '_charge_id', $charge_id );
|
| 562 |
+
$order->update_meta_data( '_intention_status', $status );
|
| 563 |
+
$order->save();
|
| 564 |
|
| 565 |
+
if ( $amount > 0 ) {
|
| 566 |
+
$order->add_order_note( $note );
|
| 567 |
+
}
|
| 568 |
+
$order->payment_complete( $intent_id );
|
| 569 |
+
break;
|
| 570 |
+
case 'requires_capture':
|
| 571 |
+
$note = sprintf(
|
| 572 |
+
WC_Payments_Utils::esc_interpolated_html(
|
| 573 |
+
/* translators: %1: the authorized amount, %2: transaction ID of the payment */
|
| 574 |
+
__( 'A payment of %1$s was <strong>authorized</strong> using WooCommerce Payments (<code>%2$s</code>).', 'woocommerce-payments' ),
|
| 575 |
+
[
|
| 576 |
+
'strong' => '<strong>',
|
| 577 |
+
'code' => '<code>',
|
| 578 |
+
]
|
| 579 |
+
),
|
| 580 |
+
wc_price( $amount ),
|
| 581 |
+
$intent_id
|
| 582 |
+
);
|
| 583 |
|
| 584 |
+
$order->update_status( 'on-hold', $note );
|
| 585 |
+
$order->set_transaction_id( $intent_id );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 586 |
|
| 587 |
+
$order->update_meta_data( '_intent_id', $intent_id );
|
| 588 |
+
$order->update_meta_data( '_charge_id', $charge_id );
|
| 589 |
+
$order->update_meta_data( '_intention_status', $status );
|
| 590 |
+
$order->save();
|
| 591 |
|
| 592 |
+
break;
|
| 593 |
+
case 'requires_action':
|
| 594 |
+
// Add a note in case the customer does not complete the payment (exits the page),
|
| 595 |
+
// so the store owner has some information about what happened to create an order.
|
| 596 |
+
$note = sprintf(
|
| 597 |
+
WC_Payments_Utils::esc_interpolated_html(
|
| 598 |
+
/* translators: %1: the authorized amount, %2: transaction ID of the payment */
|
| 599 |
+
__( 'A payment of %1$s was <strong>started</strong> using WooCommerce Payments (<code>%2$s</code>).', 'woocommerce-payments' ),
|
| 600 |
+
[
|
| 601 |
+
'strong' => '<strong>',
|
| 602 |
+
'code' => '<code>',
|
| 603 |
+
]
|
| 604 |
+
),
|
| 605 |
+
wc_price( $amount ),
|
| 606 |
+
$intent_id
|
| 607 |
+
);
|
| 608 |
+
$order->add_order_note( $note );
|
| 609 |
|
| 610 |
+
$order->update_meta_data( '_intent_id', $intent_id );
|
| 611 |
+
$order->update_meta_data( '_intention_status', $status );
|
| 612 |
+
$order->save();
|
| 613 |
+
|
| 614 |
+
return [
|
| 615 |
+
'result' => 'success',
|
| 616 |
+
// Include a new nonce for update_order_status to ensure the update order
|
| 617 |
+
// status call works when a guest user creates an account during checkout.
|
| 618 |
+
'redirect' => sprintf(
|
| 619 |
+
'#wcpay-confirm-pi:%s:%s:%s',
|
| 620 |
+
$order_id,
|
| 621 |
+
$intent->get_client_secret(),
|
| 622 |
+
wp_create_nonce( 'wcpay_update_order_status_nonce' )
|
| 623 |
+
),
|
| 624 |
+
];
|
| 625 |
}
|
| 626 |
+
}
|
| 627 |
|
| 628 |
+
wc_reduce_stock_levels( $order_id );
|
| 629 |
+
if ( isset( $cart ) ) {
|
| 630 |
+
$cart->empty_cart();
|
| 631 |
}
|
| 632 |
|
| 633 |
+
return [
|
| 634 |
+
'result' => 'success',
|
| 635 |
+
'redirect' => $this->get_return_url( $order ),
|
| 636 |
+
];
|
| 637 |
+
}
|
| 638 |
|
| 639 |
+
/**
|
| 640 |
+
* Saves the payment token to the order.
|
| 641 |
+
*
|
| 642 |
+
* @param WC_Order $order The order.
|
| 643 |
+
* @param WC_Payment_Token $token The token to save.
|
| 644 |
+
*/
|
| 645 |
+
protected function add_token_to_order( $order, $token ) {
|
| 646 |
+
$order_tokens = $order->get_payment_tokens();
|
| 647 |
+
|
| 648 |
+
// This could lead to tokens being saved twice in an order's payment tokens, but it is needed so that shoppers
|
| 649 |
+
// may re-use a previous card for the same subscription, as we consider the last token to be the active one.
|
| 650 |
+
// We can't remove the previous entry for the token because WC_Order does not support removal of tokens [1] and
|
| 651 |
+
// we can't delete the token as it might be used somewhere else.
|
| 652 |
+
// [1] https://github.com/woocommerce/woocommerce/issues/11857.
|
| 653 |
+
if ( $token->get_id() !== end( $order_tokens ) ) {
|
| 654 |
+
$order->add_payment_token( $token );
|
| 655 |
+
}
|
| 656 |
}
|
| 657 |
|
| 658 |
/**
|
| 765 |
return ob_get_clean();
|
| 766 |
}
|
| 767 |
|
| 768 |
+
/**
|
| 769 |
+
* Generates markup for account statement descriptor field.
|
| 770 |
+
*
|
| 771 |
+
* @param string $key Field key.
|
| 772 |
+
* @param array $data Field data.
|
| 773 |
+
*
|
| 774 |
+
* @return string
|
| 775 |
+
*/
|
| 776 |
+
public function generate_account_statement_descriptor_html( $key, $data ) {
|
| 777 |
+
if ( ! $this->is_connected() ) {
|
| 778 |
+
return '';
|
| 779 |
+
}
|
| 780 |
+
|
| 781 |
+
return parent::generate_text_html( $key, $data );
|
| 782 |
+
}
|
| 783 |
+
|
| 784 |
+
/**
|
| 785 |
+
* Get option from DB or connected account.
|
| 786 |
+
*
|
| 787 |
+
* Overrides parent method to retrieve some options from connected account.
|
| 788 |
+
*
|
| 789 |
+
* @param string $key Option key.
|
| 790 |
+
* @param mixed $empty_value Value when empty.
|
| 791 |
+
* @return string The value specified for the option or a default value for the option.
|
| 792 |
+
*/
|
| 793 |
+
public function get_option( $key, $empty_value = null ) {
|
| 794 |
+
switch ( $key ) {
|
| 795 |
+
case 'account_statement_descriptor':
|
| 796 |
+
return $this->get_account_statement_descriptor();
|
| 797 |
+
default:
|
| 798 |
+
return parent::get_option( $key, $empty_value );
|
| 799 |
+
}
|
| 800 |
+
}
|
| 801 |
+
|
| 802 |
+
/**
|
| 803 |
+
* Sanitizes plugin settings before saving them in site's DB.
|
| 804 |
+
*
|
| 805 |
+
* Filters out some values stored in connected account.
|
| 806 |
+
*
|
| 807 |
+
* @param array $settings Plugin settings.
|
| 808 |
+
* @return array Sanitized settings.
|
| 809 |
+
*/
|
| 810 |
+
public function sanitize_plugin_settings( $settings ) {
|
| 811 |
+
if ( isset( $settings['account_statement_descriptor'] ) ) {
|
| 812 |
+
$this->update_statement_descriptor( $settings['account_statement_descriptor'] );
|
| 813 |
+
unset( $settings['account_statement_descriptor'] );
|
| 814 |
+
}
|
| 815 |
+
|
| 816 |
+
return $settings;
|
| 817 |
+
}
|
| 818 |
+
|
| 819 |
+
/**
|
| 820 |
+
* Gets connected account statement descriptor.
|
| 821 |
+
*
|
| 822 |
+
* @param mixed $empty_value Empty value to return when not connected or fails to fetch account descriptor.
|
| 823 |
+
*
|
| 824 |
+
* @return string Statement descriptor of default value.
|
| 825 |
+
*/
|
| 826 |
+
private function get_account_statement_descriptor( $empty_value = null ) {
|
| 827 |
+
try {
|
| 828 |
+
if ( ! $this->is_connected() ) {
|
| 829 |
+
return $empty_value;
|
| 830 |
+
}
|
| 831 |
+
|
| 832 |
+
return $this->account->get_statement_descriptor();
|
| 833 |
+
} catch ( Exception $e ) {
|
| 834 |
+
Logger::error( 'Failed to get account statement descriptor.' . $e );
|
| 835 |
+
return $empty_value;
|
| 836 |
+
}
|
| 837 |
+
}
|
| 838 |
+
|
| 839 |
+
/**
|
| 840 |
+
* Handles statement descriptor update when plugin settings saved.
|
| 841 |
+
*
|
| 842 |
+
* Adds error message to display in admin notices in case of failure.
|
| 843 |
+
*
|
| 844 |
+
* @param string $statement_descriptor Statement descriptor value.
|
| 845 |
+
*/
|
| 846 |
+
private function update_statement_descriptor( $statement_descriptor ) {
|
| 847 |
+
if ( empty( $statement_descriptor ) ) {
|
| 848 |
+
return;
|
| 849 |
+
}
|
| 850 |
+
|
| 851 |
+
$account_settings = [
|
| 852 |
+
'statement_descriptor' => $statement_descriptor,
|
| 853 |
+
];
|
| 854 |
+
$error_message = $this->account->update_stripe_account( $account_settings );
|
| 855 |
+
|
| 856 |
+
if ( is_string( $error_message ) ) {
|
| 857 |
+
$msg = __( 'Failed to update Statement descriptor. ', 'woocommerce-payments' ) . $error_message;
|
| 858 |
+
$this->add_error( $msg );
|
| 859 |
+
}
|
| 860 |
+
}
|
| 861 |
+
|
| 862 |
+
/**
|
| 863 |
+
* Validates statement descriptor value
|
| 864 |
+
*
|
| 865 |
+
* @param string $key Field key.
|
| 866 |
+
* @param string $value Posted Value.
|
| 867 |
+
*
|
| 868 |
+
* @return string Sanitized statement descriptor.
|
| 869 |
+
* @throws Exception When statement descriptor is invalid.
|
| 870 |
+
*/
|
| 871 |
+
public function validate_account_statement_descriptor_field( $key, $value ) {
|
| 872 |
+
// Validation can be done with a single regex but splitting into multiple for better readability.
|
| 873 |
+
$valid_length = '/^.{5,22}$/';
|
| 874 |
+
$has_one_letter = '/^.*[a-zA-Z]+/';
|
| 875 |
+
$no_specials = '/^[^*"\'<>]*$/';
|
| 876 |
+
|
| 877 |
+
if (
|
| 878 |
+
! preg_match( $valid_length, $value ) ||
|
| 879 |
+
! preg_match( $has_one_letter, $value ) ||
|
| 880 |
+
! preg_match( $no_specials, $value )
|
| 881 |
+
) {
|
| 882 |
+
throw new Exception( __( 'Customer bank statement is invalid. Statement should be between 5 and 22 characters long, contain at least single Latin character and does not contain special characters: \' " * < >', 'woocommerce-payments' ) );
|
| 883 |
+
}
|
| 884 |
+
|
| 885 |
+
// Perform text validation after own checks to prevent special characters like < > escaped before own validation.
|
| 886 |
+
return $this->validate_text_field( $key, $value );
|
| 887 |
+
}
|
| 888 |
+
|
| 889 |
/**
|
| 890 |
* Generate markup for account actions
|
| 891 |
*/
|
| 1164 |
$intent_id
|
| 1165 |
);
|
| 1166 |
$order->add_order_note( $note );
|
| 1167 |
+
|
| 1168 |
+
// The order is successful, so update it to reflect that.
|
| 1169 |
+
$order->update_meta_data( '_charge_id', $intent->get_charge_id() );
|
| 1170 |
+
$order->update_meta_data( '_intention_status', $status );
|
| 1171 |
+
$order->save();
|
| 1172 |
+
|
| 1173 |
$order->payment_complete( $intent_id );
|
| 1174 |
break;
|
| 1175 |
case 'requires_capture':
|
| 1188 |
// Save the note separately because if there is no change in status
|
| 1189 |
// then the note is not saved using WC_Order::update_status.
|
| 1190 |
$order->add_order_note( $note );
|
| 1191 |
+
|
| 1192 |
+
// The order is successful, so update it to reflect that.
|
| 1193 |
+
$order->update_meta_data( '_charge_id', $intent->get_charge_id() );
|
| 1194 |
+
$order->update_meta_data( '_intention_status', $status );
|
| 1195 |
+
$order->save();
|
| 1196 |
+
|
| 1197 |
$order->update_status( 'on-hold' );
|
| 1198 |
$order->set_transaction_id( $intent_id );
|
| 1199 |
break;
|
| 1218 |
}
|
| 1219 |
|
| 1220 |
if ( 'succeeded' === $status || 'requires_capture' === $status ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1221 |
wc_reduce_stock_levels( $order_id );
|
| 1222 |
WC()->cart->empty_cart();
|
| 1223 |
|
| 1224 |
if ( ! empty( $payment_method_id ) ) {
|
| 1225 |
try {
|
| 1226 |
+
// TODO: Add token to subscriptions related to this order.
|
| 1227 |
$this->token_service->add_payment_method_to_user( $payment_method_id, wp_get_current_user() );
|
| 1228 |
} catch ( Exception $e ) {
|
| 1229 |
// If saving the token fails, log the error message but catch the error to avoid crashing the checkout flow.
|
| 1289 |
public function add_payment_method() {
|
| 1290 |
try {
|
| 1291 |
|
| 1292 |
+
// phpcs:ignore WordPress.Security.NonceVerification.Missing
|
| 1293 |
if ( ! isset( $_POST['wcpay-setup-intent'] ) ) {
|
| 1294 |
throw new Exception( __( 'A WooCommerce Payments payment method was not provided', 'woocommerce-payments' ) );
|
| 1295 |
}
|
| 1296 |
|
| 1297 |
+
// phpcs:ignore WordPress.Security.NonceVerification.Missing,WordPress.Security.ValidatedSanitizedInput.MissingUnslash
|
| 1298 |
$setup_intent_id = ! empty( $_POST['wcpay-setup-intent'] ) ? wc_clean( $_POST['wcpay-setup-intent'] ) : false;
|
|
|
|
| 1299 |
|
| 1300 |
$customer_id = $this->customer_service->get_customer_id_by_user_id( get_current_user_id() );
|
| 1301 |
|
| 1331 |
* @throws Exception - When an error occurs in setup intent creation.
|
| 1332 |
*/
|
| 1333 |
public function create_setup_intent() {
|
| 1334 |
+
// phpcs:ignore WordPress.Security.NonceVerification.Missing
|
| 1335 |
+
$payment_information = Payment_Information::from_payment_request( $_POST );
|
| 1336 |
|
| 1337 |
// Determine the customer adding the payment method, create one if we don't have one already.
|
| 1338 |
$user = wp_get_current_user();
|
| 1342 |
}
|
| 1343 |
|
| 1344 |
return $this->payments_api_client->create_setup_intent(
|
| 1345 |
+
$payment_information->get_payment_method(),
|
| 1346 |
$customer_id
|
| 1347 |
);
|
| 1348 |
}
|
| 1373 |
);
|
| 1374 |
}
|
| 1375 |
}
|
| 1376 |
+
|
| 1377 |
+
/**
|
| 1378 |
+
* Add a url to the admin order page that links directly to the transactions detail view.
|
| 1379 |
+
*
|
| 1380 |
+
* @since 1.4.0
|
| 1381 |
+
*
|
| 1382 |
+
* @param WC_Order $order The context passed into this function when the user view the order details page in WordPress admin.
|
| 1383 |
+
* @return string
|
| 1384 |
+
*/
|
| 1385 |
+
public function get_transaction_url( $order ) {
|
| 1386 |
+
$charge_id = $order->get_meta( '_charge_id' );
|
| 1387 |
+
|
| 1388 |
+
if ( empty( $charge_id ) ) {
|
| 1389 |
+
return '';
|
| 1390 |
+
}
|
| 1391 |
+
|
| 1392 |
+
return add_query_arg(
|
| 1393 |
+
[
|
| 1394 |
+
'page' => 'wc-admin',
|
| 1395 |
+
'path' => '/payments/transactions/details&',
|
| 1396 |
+
'id' => $charge_id,
|
| 1397 |
+
],
|
| 1398 |
+
admin_url( 'admin.php' )
|
| 1399 |
+
);
|
| 1400 |
+
}
|
| 1401 |
}
|
includes/class-wc-payments-account.php
CHANGED
|
@@ -162,6 +162,17 @@ class WC_Payments_Account {
|
|
| 162 |
];
|
| 163 |
}
|
| 164 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 165 |
/**
|
| 166 |
* Utility function to immediately redirect to the main "Welcome to WooCommerce Payments" onboarding page.
|
| 167 |
* Note that this function immediately ends the execution.
|
|
@@ -226,6 +237,11 @@ class WC_Payments_Account {
|
|
| 226 |
return false;
|
| 227 |
}
|
| 228 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 229 |
return true;
|
| 230 |
}
|
| 231 |
|
|
@@ -567,7 +583,7 @@ class WC_Payments_Account {
|
|
| 567 |
delete_transient( self::ACCOUNT_TRANSIENT );
|
| 568 |
$this->get_cached_account_data();
|
| 569 |
} catch ( Exception $e ) {
|
| 570 |
-
|
| 571 |
}
|
| 572 |
}
|
| 573 |
|
|
@@ -617,4 +633,44 @@ class WC_Payments_Account {
|
|
| 617 |
}
|
| 618 |
);
|
| 619 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 620 |
}
|
| 162 |
];
|
| 163 |
}
|
| 164 |
|
| 165 |
+
/**
|
| 166 |
+
* Gets the account statement descriptor for rendering on the settings page.
|
| 167 |
+
*
|
| 168 |
+
* @return string Account statement descriptor.
|
| 169 |
+
* @throws WC_Payments_API_Exception Bubbles up from get_cached_account_data.
|
| 170 |
+
*/
|
| 171 |
+
public function get_statement_descriptor() {
|
| 172 |
+
$account = $this->get_cached_account_data();
|
| 173 |
+
return isset( $account['statement_descriptor'] ) ? $account['statement_descriptor'] : '';
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
/**
|
| 177 |
* Utility function to immediately redirect to the main "Welcome to WooCommerce Payments" onboarding page.
|
| 178 |
* Note that this function immediately ends the execution.
|
| 237 |
return false;
|
| 238 |
}
|
| 239 |
|
| 240 |
+
// Don't redirect if the user is on Jetpack pages.
|
| 241 |
+
if ( 'jetpack' === $current_page ) {
|
| 242 |
+
return false;
|
| 243 |
+
}
|
| 244 |
+
|
| 245 |
return true;
|
| 246 |
}
|
| 247 |
|
| 583 |
delete_transient( self::ACCOUNT_TRANSIENT );
|
| 584 |
$this->get_cached_account_data();
|
| 585 |
} catch ( Exception $e ) {
|
| 586 |
+
Logger::error( "Failed to refresh account data. Error: $e" );
|
| 587 |
}
|
| 588 |
}
|
| 589 |
|
| 633 |
}
|
| 634 |
);
|
| 635 |
}
|
| 636 |
+
|
| 637 |
+
/**
|
| 638 |
+
* Updates Stripe account settings.
|
| 639 |
+
*
|
| 640 |
+
* @param array $stripe_account_settings Settings to update.
|
| 641 |
+
*
|
| 642 |
+
* @return null|string Error message if update failed.
|
| 643 |
+
*/
|
| 644 |
+
public function update_stripe_account( $stripe_account_settings ) {
|
| 645 |
+
try {
|
| 646 |
+
if ( ! $this->settings_changed( $stripe_account_settings ) ) {
|
| 647 |
+
Logger::info( 'Skip updating account settings. Nothing is changed.' );
|
| 648 |
+
return;
|
| 649 |
+
}
|
| 650 |
+
$updated_account = $this->payments_api_client->update_account( $stripe_account_settings );
|
| 651 |
+
$this->cache_account( $updated_account );
|
| 652 |
+
} catch ( Exception $e ) {
|
| 653 |
+
Logger::error( 'Failed to update Stripe account ' . $e );
|
| 654 |
+
return $e->getMessage();
|
| 655 |
+
}
|
| 656 |
+
}
|
| 657 |
+
|
| 658 |
+
/**
|
| 659 |
+
* Checks if account settings changed.
|
| 660 |
+
*
|
| 661 |
+
* @param array $changes Account settings changes.
|
| 662 |
+
*
|
| 663 |
+
* @return bool True if at least one parameter value is changed.
|
| 664 |
+
*/
|
| 665 |
+
private function settings_changed( $changes = [] ) {
|
| 666 |
+
$account = get_transient( self::ACCOUNT_TRANSIENT );
|
| 667 |
+
|
| 668 |
+
// Consider changes as valid if we don't have cached account data.
|
| 669 |
+
if ( ! $this->is_valid_cached_account( $account ) ) {
|
| 670 |
+
return true;
|
| 671 |
+
}
|
| 672 |
+
|
| 673 |
+
$diff = array_diff_assoc( $changes, $account );
|
| 674 |
+
return ! empty( $diff );
|
| 675 |
+
}
|
| 676 |
}
|
includes/class-wc-payments-token-service.php
CHANGED
|
@@ -51,6 +51,7 @@ class WC_Payments_Token_Service {
|
|
| 51 |
*
|
| 52 |
* @param array $payment_method Payment method to be added.
|
| 53 |
* @param WP_User $user User to attach payment method to.
|
|
|
|
| 54 |
*/
|
| 55 |
public function add_token_to_user( $payment_method, $user ) {
|
| 56 |
// Clear cached payment methods.
|
|
@@ -74,10 +75,11 @@ class WC_Payments_Token_Service {
|
|
| 74 |
*
|
| 75 |
* @param string $payment_method_id Payment method to be added.
|
| 76 |
* @param WP_User $user User to attach payment method to.
|
|
|
|
| 77 |
*/
|
| 78 |
public function add_payment_method_to_user( $payment_method_id, $user ) {
|
| 79 |
$payment_method_object = $this->payments_api_client->get_payment_method( $payment_method_id );
|
| 80 |
-
return $this->add_token_to_user( $payment_method_object,
|
| 81 |
}
|
| 82 |
|
| 83 |
/**
|
|
@@ -93,7 +95,7 @@ class WC_Payments_Token_Service {
|
|
| 93 |
return $tokens;
|
| 94 |
}
|
| 95 |
|
| 96 |
-
$customer_id = $this->customer_service->get_customer_id_by_user_id(
|
| 97 |
|
| 98 |
if ( null === $customer_id ) {
|
| 99 |
return $tokens;
|
|
@@ -110,7 +112,7 @@ class WC_Payments_Token_Service {
|
|
| 110 |
foreach ( $payment_methods as $payment_method ) {
|
| 111 |
if ( isset( $payment_method['type'] ) && 'card' === $payment_method['type'] ) {
|
| 112 |
if ( ! in_array( $payment_method['id'], $stored_tokens, true ) ) {
|
| 113 |
-
$token = $this->add_token_to_user( $payment_method,
|
| 114 |
$tokens[ $token->get_id() ] = $token;
|
| 115 |
}
|
| 116 |
}
|
|
@@ -145,7 +147,7 @@ class WC_Payments_Token_Service {
|
|
| 145 |
*/
|
| 146 |
public function woocommerce_payment_token_set_default( $token_id, $token ) {
|
| 147 |
if ( WC_Payment_Gateway_WCPay::GATEWAY_ID === $token->get_gateway_id() ) {
|
| 148 |
-
$customer_id = $this->customer_service->get_customer_id_by_user_id(
|
| 149 |
if ( $customer_id ) {
|
| 150 |
$this->customer_service->set_default_payment_method_for_customer( $customer_id, $token->get_token() );
|
| 151 |
// Clear cached payment methods.
|
| 51 |
*
|
| 52 |
* @param array $payment_method Payment method to be added.
|
| 53 |
* @param WP_User $user User to attach payment method to.
|
| 54 |
+
* @return WC_Payment_Token_CC The WC object for the payment token.
|
| 55 |
*/
|
| 56 |
public function add_token_to_user( $payment_method, $user ) {
|
| 57 |
// Clear cached payment methods.
|
| 75 |
*
|
| 76 |
* @param string $payment_method_id Payment method to be added.
|
| 77 |
* @param WP_User $user User to attach payment method to.
|
| 78 |
+
* @return WC_Payment_Token_CC The newly created token.
|
| 79 |
*/
|
| 80 |
public function add_payment_method_to_user( $payment_method_id, $user ) {
|
| 81 |
$payment_method_object = $this->payments_api_client->get_payment_method( $payment_method_id );
|
| 82 |
+
return $this->add_token_to_user( $payment_method_object, $user );
|
| 83 |
}
|
| 84 |
|
| 85 |
/**
|
| 95 |
return $tokens;
|
| 96 |
}
|
| 97 |
|
| 98 |
+
$customer_id = $this->customer_service->get_customer_id_by_user_id( $user_id );
|
| 99 |
|
| 100 |
if ( null === $customer_id ) {
|
| 101 |
return $tokens;
|
| 112 |
foreach ( $payment_methods as $payment_method ) {
|
| 113 |
if ( isset( $payment_method['type'] ) && 'card' === $payment_method['type'] ) {
|
| 114 |
if ( ! in_array( $payment_method['id'], $stored_tokens, true ) ) {
|
| 115 |
+
$token = $this->add_token_to_user( $payment_method, get_user_by( 'id', $user_id ) );
|
| 116 |
$tokens[ $token->get_id() ] = $token;
|
| 117 |
}
|
| 118 |
}
|
| 147 |
*/
|
| 148 |
public function woocommerce_payment_token_set_default( $token_id, $token ) {
|
| 149 |
if ( WC_Payment_Gateway_WCPay::GATEWAY_ID === $token->get_gateway_id() ) {
|
| 150 |
+
$customer_id = $this->customer_service->get_customer_id_by_user_id( $token->get_user_id() );
|
| 151 |
if ( $customer_id ) {
|
| 152 |
$this->customer_service->set_default_payment_method_for_customer( $customer_id, $token->get_token() );
|
| 153 |
// Clear cached payment methods.
|
includes/class-wc-payments.php
CHANGED
|
@@ -94,13 +94,20 @@ class WC_Payments {
|
|
| 94 |
include_once dirname( __FILE__ ) . '/class-logger.php';
|
| 95 |
include_once dirname( __FILE__ ) . '/class-wc-payment-gateway-wcpay.php';
|
| 96 |
include_once dirname( __FILE__ ) . '/class-wc-payments-token-service.php';
|
| 97 |
-
include_once
|
|
|
|
| 98 |
|
| 99 |
self::$account = new WC_Payments_Account( self::$api_client );
|
| 100 |
self::$customer_service = new WC_Payments_Customer_Service( self::$api_client );
|
| 101 |
self::$token_service = new WC_Payments_Token_Service( self::$api_client, self::$customer_service );
|
| 102 |
|
| 103 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 104 |
|
| 105 |
add_filter( 'woocommerce_payment_gateways', [ __CLASS__, 'register_gateway' ] );
|
| 106 |
add_filter( 'option_woocommerce_gateway_order', [ __CLASS__, 'set_gateway_top_of_list' ], 2 );
|
| 94 |
include_once dirname( __FILE__ ) . '/class-logger.php';
|
| 95 |
include_once dirname( __FILE__ ) . '/class-wc-payment-gateway-wcpay.php';
|
| 96 |
include_once dirname( __FILE__ ) . '/class-wc-payments-token-service.php';
|
| 97 |
+
include_once dirname( __FILE__ ) . '/exceptions/class-wc-payments-intent-authentication-exception.php';
|
| 98 |
+
include_once dirname( __FILE__ ) . '/data-types/class-payment-information.php';
|
| 99 |
|
| 100 |
self::$account = new WC_Payments_Account( self::$api_client );
|
| 101 |
self::$customer_service = new WC_Payments_Customer_Service( self::$api_client );
|
| 102 |
self::$token_service = new WC_Payments_Token_Service( self::$api_client, self::$customer_service );
|
| 103 |
|
| 104 |
+
$gateway_class = 'WC_Payment_Gateway_WCPay';
|
| 105 |
+
if ( class_exists( 'WC_Subscriptions' ) && version_compare( WC_Subscriptions::$version, '3.0.0', '>=' ) ) {
|
| 106 |
+
include_once dirname( __FILE__ ) . '/compat/subscriptions/class-wc-payment-gateway-wcpay-subscriptions-compat.php';
|
| 107 |
+
$gateway_class = 'WC_Payment_Gateway_WCPay_Subscriptions_Compat';
|
| 108 |
+
}
|
| 109 |
+
|
| 110 |
+
self::$gateway = new $gateway_class( self::$api_client, self::$account, self::$customer_service, self::$token_service );
|
| 111 |
|
| 112 |
add_filter( 'woocommerce_payment_gateways', [ __CLASS__, 'register_gateway' ] );
|
| 113 |
add_filter( 'option_woocommerce_gateway_order', [ __CLASS__, 'set_gateway_top_of_list' ], 2 );
|
includes/compat/subscriptions/class-wc-payment-gateway-wcpay-subscriptions-compat.php
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
/**
|
| 3 |
+
* Class WC_Payment_Gateway_WCPay_Subscriptions_Compat
|
| 4 |
+
*
|
| 5 |
+
* @package WooCommerce\Payments
|
| 6 |
+
*/
|
| 7 |
+
|
| 8 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
| 9 |
+
exit; // Exit if accessed directly.
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
use WCPay\Logger;
|
| 13 |
+
use WCPay\DataTypes\Payment_Information;
|
| 14 |
+
|
| 15 |
+
/**
|
| 16 |
+
* Gateway class for WooCommerce Payments, with added compatibility with WooCommerce Subscriptions.
|
| 17 |
+
*/
|
| 18 |
+
class WC_Payment_Gateway_WCPay_Subscriptions_Compat extends WC_Payment_Gateway_WCPay {
|
| 19 |
+
|
| 20 |
+
/**
|
| 21 |
+
* WC_Payment_Gateway_WCPay_Subscriptions_Compat constructor.
|
| 22 |
+
*
|
| 23 |
+
* @param array ...$args Arguments passed to the main gateway's constructor.
|
| 24 |
+
*/
|
| 25 |
+
public function __construct( ...$args ) {
|
| 26 |
+
parent::__construct( ...$args );
|
| 27 |
+
|
| 28 |
+
$this->supports = array_merge(
|
| 29 |
+
$this->supports,
|
| 30 |
+
[
|
| 31 |
+
'subscriptions',
|
| 32 |
+
'subscription_cancellation',
|
| 33 |
+
'subscription_suspension',
|
| 34 |
+
'subscription_reactivation',
|
| 35 |
+
'subscription_amount_changes',
|
| 36 |
+
'subscription_date_changes',
|
| 37 |
+
'subscription_payment_method_change',
|
| 38 |
+
'subscription_payment_method_change_customer',
|
| 39 |
+
'multiple_subscriptions',
|
| 40 |
+
]
|
| 41 |
+
);
|
| 42 |
+
|
| 43 |
+
add_action( 'woocommerce_scheduled_subscription_payment_' . $this->id, [ $this, 'scheduled_subscription_payment' ], 10, 2 );
|
| 44 |
+
add_action( 'woocommerce_subscription_failing_payment_method_updated_' . $this->id, [ $this, 'update_failing_payment_method' ], 10, 2 );
|
| 45 |
+
add_filter( 'wc_payments_display_save_payment_method_checkbox', [ $this, 'display_save_payment_method_checkbox' ], 10 );
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
/**
|
| 49 |
+
* Process the payment for a given order.
|
| 50 |
+
*
|
| 51 |
+
* @param int $order_id Order ID to process the payment for.
|
| 52 |
+
* @param bool $is_recurring_payment Whether this is a one-off payment (false) or it's the first installment of a recurring payment (true).
|
| 53 |
+
*
|
| 54 |
+
* @return array|null An array with result of payment and redirect URL, or nothing.
|
| 55 |
+
*/
|
| 56 |
+
public function process_payment( $order_id, $is_recurring_payment = false ) {
|
| 57 |
+
return parent::process_payment( $order_id, wcs_order_contains_subscription( $order_id ) );
|
| 58 |
+
}
|
| 59 |
+
|
| 60 |
+
/**
|
| 61 |
+
* Returns a boolean value indicating whether the save payment checkbox should be
|
| 62 |
+
* displayed during checkout.
|
| 63 |
+
*
|
| 64 |
+
* Returns `false` if the cart currently has a subscriptions. Returns the value in
|
| 65 |
+
* `$display` otherwise.
|
| 66 |
+
*
|
| 67 |
+
* @param bool $display Bool indicating whether to show the save payment checkbox in the absence of subscriptions.
|
| 68 |
+
*
|
| 69 |
+
* @return bool Indicates whether the save payment method checkbox should be displayed or not.
|
| 70 |
+
*/
|
| 71 |
+
public function display_save_payment_method_checkbox( $display ) {
|
| 72 |
+
if ( WC_Subscriptions_Cart::cart_contains_subscription() ) {
|
| 73 |
+
return false;
|
| 74 |
+
}
|
| 75 |
+
// Only render the "Save payment method" checkbox if there are no subscription products in the cart.
|
| 76 |
+
return $display;
|
| 77 |
+
}
|
| 78 |
+
|
| 79 |
+
/**
|
| 80 |
+
* Process a scheduled subscription payment.
|
| 81 |
+
*
|
| 82 |
+
* @param float $amount The amount to charge.
|
| 83 |
+
* @param WC_Order $renewal_order A WC_Order object created to record the renewal payment.
|
| 84 |
+
*/
|
| 85 |
+
public function scheduled_subscription_payment( $amount, $renewal_order ) {
|
| 86 |
+
$order_tokens = $renewal_order->get_payment_tokens();
|
| 87 |
+
$token_id = end( $order_tokens );
|
| 88 |
+
$token = ! $token_id ? null : WC_Payment_Tokens::get( $token_id );
|
| 89 |
+
if ( is_null( $token ) ) {
|
| 90 |
+
Logger::error( 'There is no saved payment token for order #' . $renewal_order->get_id() );
|
| 91 |
+
$renewal_order->update_status( 'failed' );
|
| 92 |
+
return;
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
$payment_information = new Payment_Information( '', $token, true );
|
| 96 |
+
|
| 97 |
+
try {
|
| 98 |
+
// TODO: make `force_saved_card` and adding the 'recurring' metadata 2 distinct features.
|
| 99 |
+
$this->process_payment_for_order( $renewal_order, null, $payment_information, false, true );
|
| 100 |
+
} catch ( WC_Payments_API_Exception $e ) {
|
| 101 |
+
Logger::error( 'Error processing subscription renewal: ' . $e->getMessage() );
|
| 102 |
+
|
| 103 |
+
$renewal_order->update_status( 'failed' );
|
| 104 |
+
}
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
/**
|
| 108 |
+
* Adds the payment token from a failed renewal order to the provided subscription.
|
| 109 |
+
*
|
| 110 |
+
* @param WC_Subscription $subscription The subscription to be updated.
|
| 111 |
+
* @param WC_Order $renewal_order The failed renewal order.
|
| 112 |
+
*/
|
| 113 |
+
public function update_failing_payment_method( $subscription, $renewal_order ) {
|
| 114 |
+
$renewal_order_tokens = $renewal_order->get_payment_tokens();
|
| 115 |
+
$renewal_token_id = end( $renewal_order_tokens );
|
| 116 |
+
$renewal_token = ! $renewal_token_id ? null : WC_Payment_Tokens::get( $renewal_token_id );
|
| 117 |
+
if ( is_null( $renewal_token ) ) {
|
| 118 |
+
Logger::error( 'Failing subscription could not be updated: there is no saved payment token for order #' . $renewal_order->get_id() );
|
| 119 |
+
return;
|
| 120 |
+
}
|
| 121 |
+
$subscription->add_payment_token( $renewal_token );
|
| 122 |
+
}
|
| 123 |
+
|
| 124 |
+
/**
|
| 125 |
+
* Saves the payment token to the order.
|
| 126 |
+
*
|
| 127 |
+
* @param WC_Order $order The order.
|
| 128 |
+
* @param WC_Payment_Token $token The token to save.
|
| 129 |
+
*/
|
| 130 |
+
protected function add_token_to_order( $order, $token ) {
|
| 131 |
+
parent::add_token_to_order( $order, $token );
|
| 132 |
+
|
| 133 |
+
// Set payment token for subscriptions, so it can be used for renewals.
|
| 134 |
+
$subscriptions = wcs_get_subscriptions_for_order( $order->get_id() );
|
| 135 |
+
foreach ( $subscriptions as $subscription ) {
|
| 136 |
+
parent::add_token_to_order( $subscription, $token );
|
| 137 |
+
}
|
| 138 |
+
}
|
| 139 |
+
}
|
includes/data-types/class-payment-information.php
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
/**
|
| 3 |
+
* Class Payment_Information
|
| 4 |
+
*
|
| 5 |
+
* @package WooCommerce\Payments
|
| 6 |
+
*/
|
| 7 |
+
|
| 8 |
+
namespace WCPay\DataTypes;
|
| 9 |
+
|
| 10 |
+
if ( ! defined( 'ABSPATH' ) ) {
|
| 11 |
+
exit; // Exit if accessed directly.
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
/**
|
| 15 |
+
* Mostly a wrapper containing information on a single payment.
|
| 16 |
+
*/
|
| 17 |
+
class Payment_Information {
|
| 18 |
+
/**
|
| 19 |
+
* The ID of the payment method used for this payment.
|
| 20 |
+
*
|
| 21 |
+
* @var string
|
| 22 |
+
*/
|
| 23 |
+
private $payment_method;
|
| 24 |
+
|
| 25 |
+
/**
|
| 26 |
+
* The payment token used for this payment.
|
| 27 |
+
*
|
| 28 |
+
* @var \WC_Payment_Token/NULL
|
| 29 |
+
*/
|
| 30 |
+
private $token;
|
| 31 |
+
|
| 32 |
+
/**
|
| 33 |
+
* Indicates whether the payment is merchant-initiated (true) or customer-initiated (false).
|
| 34 |
+
*
|
| 35 |
+
* @var bool
|
| 36 |
+
*/
|
| 37 |
+
private $off_session;
|
| 38 |
+
|
| 39 |
+
/**
|
| 40 |
+
* Payment information constructor.
|
| 41 |
+
*
|
| 42 |
+
* @param string $payment_method The ID of the payment method used for this payment.
|
| 43 |
+
* @param \WC_Payment_Token $token The payment token used for this payment.
|
| 44 |
+
* @param bool $off_session Indicates whether the payment is merchant-initiated (true) or customer-initiated (false).
|
| 45 |
+
*
|
| 46 |
+
* @throws \Exception - If no payment method is found in the provided request.
|
| 47 |
+
*/
|
| 48 |
+
public function __construct(
|
| 49 |
+
string $payment_method,
|
| 50 |
+
\WC_Payment_Token $token = null,
|
| 51 |
+
bool $off_session = false
|
| 52 |
+
) {
|
| 53 |
+
if ( empty( $payment_method ) && empty( $token ) ) {
|
| 54 |
+
throw new \Exception( __( 'Invalid payment method. Please input a new card number.', 'woocommerce-payments' ) );
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
$this->payment_method = $payment_method;
|
| 58 |
+
$this->token = $token;
|
| 59 |
+
$this->off_session = $off_session;
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
/**
|
| 63 |
+
* Returns true if payment was initiated by the merchant, false otherwise.
|
| 64 |
+
*
|
| 65 |
+
* @return bool True if payment was initiated by the merchant, false otherwise.
|
| 66 |
+
*/
|
| 67 |
+
public function is_merchant_initiated(): bool {
|
| 68 |
+
return $this->off_session;
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
/**
|
| 72 |
+
* Returns the payment method ID.
|
| 73 |
+
*
|
| 74 |
+
* @return string The payment method ID.
|
| 75 |
+
*/
|
| 76 |
+
public function get_payment_method(): string {
|
| 77 |
+
// Use the token if we have it.
|
| 78 |
+
if ( $this->is_using_saved_payment_method() ) {
|
| 79 |
+
return $this->token->get_token();
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
return $this->payment_method;
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
/**
|
| 86 |
+
* Returns the payment token.
|
| 87 |
+
*
|
| 88 |
+
* TODO: Once php requirement is bumped to >= 7.1.0 change return type to ?\WC_Payment_Token
|
| 89 |
+
* since the return type is nullable, as per
|
| 90 |
+
* https://www.php.net/manual/en/functions.returning-values.php#functions.returning-values.type-declaration
|
| 91 |
+
*
|
| 92 |
+
* @return \WC_Payment_Token/NULL The payment token.
|
| 93 |
+
*/
|
| 94 |
+
public function get_payment_token(): \WC_Payment_Token {
|
| 95 |
+
return $this->token;
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
/**
|
| 99 |
+
* Update the payment token associated with this payment.
|
| 100 |
+
*
|
| 101 |
+
* @param \WC_Payment_Token $token The new payment token.
|
| 102 |
+
*/
|
| 103 |
+
public function set_token( \WC_Payment_Token $token ) {
|
| 104 |
+
$this->token = $token;
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
/**
|
| 108 |
+
* Returns true if the payment token is not empty, false otherwise.
|
| 109 |
+
*
|
| 110 |
+
* @return bool True if payment token is not empty, false otherwise.
|
| 111 |
+
*/
|
| 112 |
+
public function is_using_saved_payment_method(): bool {
|
| 113 |
+
return ! empty( $this->token );
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
/**
|
| 117 |
+
* Payment information constructor.
|
| 118 |
+
*
|
| 119 |
+
* @param array $request Associative array containing payment request information.
|
| 120 |
+
* @param bool $off_session Indicates whether the payment is merchant-initiated (true) or customer-initiated (false).
|
| 121 |
+
*
|
| 122 |
+
* @throws Exception - If no payment method is found in the provided request.
|
| 123 |
+
*/
|
| 124 |
+
public static function from_payment_request(
|
| 125 |
+
array $request,
|
| 126 |
+
bool $off_session = false
|
| 127 |
+
): Payment_Information {
|
| 128 |
+
$payment_method = self::get_payment_method_from_request( $request );
|
| 129 |
+
$token = self::get_token_from_request( $request );
|
| 130 |
+
$off_session = $off_session;
|
| 131 |
+
|
| 132 |
+
return new Payment_Information( $payment_method, $token, $off_session );
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
/**
|
| 136 |
+
* Extracts the payment method from the provided request.
|
| 137 |
+
*
|
| 138 |
+
* @param array $request Associative array containing payment request information.
|
| 139 |
+
*
|
| 140 |
+
* @return string
|
| 141 |
+
*/
|
| 142 |
+
public static function get_payment_method_from_request( array $request ): string {
|
| 143 |
+
//phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
|
| 144 |
+
return ! empty( $request['wcpay-payment-method'] ) ? wc_clean( $request['wcpay-payment-method'] ) : '';
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
/**
|
| 148 |
+
* Extract the payment token from the provided request.
|
| 149 |
+
*
|
| 150 |
+
* TODO: Once php requirement is bumped to >= 7.1.0 set return type to ?\WC_Payment_Token
|
| 151 |
+
* since the return type is nullable, as per
|
| 152 |
+
* https://www.php.net/manual/en/functions.returning-values.php#functions.returning-values.type-declaration
|
| 153 |
+
*
|
| 154 |
+
* @param array $request Associative array containing payment request information.
|
| 155 |
+
*
|
| 156 |
+
* @return \WC_Payment_Token|NULL
|
| 157 |
+
*/
|
| 158 |
+
public static function get_token_from_request( array $request ) {
|
| 159 |
+
if (
|
| 160 |
+
! isset( $request[ 'wc-' . \WC_Payment_Gateway_WCPay::GATEWAY_ID . '-payment-token' ] ) ||
|
| 161 |
+
'new' === $request[ 'wc-' . \WC_Payment_Gateway_WCPay::GATEWAY_ID . '-payment-token' ]
|
| 162 |
+
) {
|
| 163 |
+
return null;
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
//phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash
|
| 167 |
+
$token = \WC_Payment_Tokens::get( wc_clean( $request[ 'wc-' . \WC_Payment_Gateway_WCPay::GATEWAY_ID . '-payment-token' ] ) );
|
| 168 |
+
|
| 169 |
+
// If the token doesn't belong to this gateway or the current user it's invalid.
|
| 170 |
+
if ( ! $token || \WC_Payment_Gateway_WCPay::GATEWAY_ID !== $token->get_gateway_id() || $token->get_user_id() !== get_current_user_id() ) {
|
| 171 |
+
return null;
|
| 172 |
+
}
|
| 173 |
+
|
| 174 |
+
return $token;
|
| 175 |
+
}
|
| 176 |
+
}
|
includes/wc-payment-api/class-wc-payments-api-client.php
CHANGED
|
@@ -121,6 +121,7 @@ class WC_Payments_API_Client {
|
|
| 121 |
* @param bool $save_payment_method - Whether to save payment method for future purchases.
|
| 122 |
* @param array $metadata - Meta data values to be sent along with payment intent creation.
|
| 123 |
* @param array $level3 - Level 3 data.
|
|
|
|
| 124 |
*
|
| 125 |
* @return WC_Payments_API_Intention
|
| 126 |
* @throws WC_Payments_API_Exception - Exception thrown on intention creation failure.
|
|
@@ -133,7 +134,8 @@ class WC_Payments_API_Client {
|
|
| 133 |
$manual_capture = false,
|
| 134 |
$save_payment_method = false,
|
| 135 |
$metadata = [],
|
| 136 |
-
$level3 = []
|
|
|
|
| 137 |
) {
|
| 138 |
// TODO: There's scope to have amount and currency bundled up into an object.
|
| 139 |
$request = [];
|
|
@@ -146,6 +148,10 @@ class WC_Payments_API_Client {
|
|
| 146 |
$request['metadata'] = $metadata;
|
| 147 |
$request['level3'] = $level3;
|
| 148 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 149 |
if ( $save_payment_method ) {
|
| 150 |
$request['setup_future_usage'] = 'off_session';
|
| 151 |
}
|
|
@@ -254,14 +260,16 @@ class WC_Payments_API_Client {
|
|
| 254 |
*
|
| 255 |
* @param string $payment_method_id - ID of payment method to be saved.
|
| 256 |
* @param string $customer_id - ID of the customer.
|
|
|
|
| 257 |
*
|
| 258 |
* @return array
|
| 259 |
* @throws WC_Payments_API_Exception - Exception thrown on setup intent creation failure.
|
| 260 |
*/
|
| 261 |
-
public function create_setup_intent( $payment_method_id, $customer_id ) {
|
| 262 |
$request = [
|
| 263 |
'payment_method' => $payment_method_id,
|
| 264 |
'customer' => $customer_id,
|
|
|
|
| 265 |
];
|
| 266 |
|
| 267 |
return $this->request( $request, self::SETUP_INTENTS_API, self::POST );
|
|
@@ -612,6 +620,21 @@ class WC_Payments_API_Client {
|
|
| 612 |
);
|
| 613 |
}
|
| 614 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 615 |
/**
|
| 616 |
* Get data needed to initialize the OAuth flow
|
| 617 |
*
|
| 121 |
* @param bool $save_payment_method - Whether to save payment method for future purchases.
|
| 122 |
* @param array $metadata - Meta data values to be sent along with payment intent creation.
|
| 123 |
* @param array $level3 - Level 3 data.
|
| 124 |
+
* @param bool $off_session - Whether the payment is off-session (merchant-initiated), or on-session (customer-initiated).
|
| 125 |
*
|
| 126 |
* @return WC_Payments_API_Intention
|
| 127 |
* @throws WC_Payments_API_Exception - Exception thrown on intention creation failure.
|
| 134 |
$manual_capture = false,
|
| 135 |
$save_payment_method = false,
|
| 136 |
$metadata = [],
|
| 137 |
+
$level3 = [],
|
| 138 |
+
$off_session = false
|
| 139 |
) {
|
| 140 |
// TODO: There's scope to have amount and currency bundled up into an object.
|
| 141 |
$request = [];
|
| 148 |
$request['metadata'] = $metadata;
|
| 149 |
$request['level3'] = $level3;
|
| 150 |
|
| 151 |
+
if ( $off_session ) {
|
| 152 |
+
$request['off_session'] = true;
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
if ( $save_payment_method ) {
|
| 156 |
$request['setup_future_usage'] = 'off_session';
|
| 157 |
}
|
| 260 |
*
|
| 261 |
* @param string $payment_method_id - ID of payment method to be saved.
|
| 262 |
* @param string $customer_id - ID of the customer.
|
| 263 |
+
* @param bool $confirm - Flag to confirm the intent on creation if true.
|
| 264 |
*
|
| 265 |
* @return array
|
| 266 |
* @throws WC_Payments_API_Exception - Exception thrown on setup intent creation failure.
|
| 267 |
*/
|
| 268 |
+
public function create_setup_intent( $payment_method_id, $customer_id, $confirm = 'false' ) {
|
| 269 |
$request = [
|
| 270 |
'payment_method' => $payment_method_id,
|
| 271 |
'customer' => $customer_id,
|
| 272 |
+
'confirm' => $confirm,
|
| 273 |
];
|
| 274 |
|
| 275 |
return $this->request( $request, self::SETUP_INTENTS_API, self::POST );
|
| 620 |
);
|
| 621 |
}
|
| 622 |
|
| 623 |
+
/**
|
| 624 |
+
* Update Stripe account data
|
| 625 |
+
*
|
| 626 |
+
* @param array $stripe_account_settings Settings to update.
|
| 627 |
+
*
|
| 628 |
+
* @return array Updated account data.
|
| 629 |
+
*/
|
| 630 |
+
public function update_account( $stripe_account_settings ) {
|
| 631 |
+
return $this->request(
|
| 632 |
+
$stripe_account_settings,
|
| 633 |
+
self::ACCOUNTS_API,
|
| 634 |
+
self::POST
|
| 635 |
+
);
|
| 636 |
+
}
|
| 637 |
+
|
| 638 |
/**
|
| 639 |
* Get data needed to initialize the OAuth flow
|
| 640 |
*
|
includes/wc-payment-api/class-wc-payments-http.php
CHANGED
|
@@ -101,7 +101,7 @@ class WC_Payments_Http {
|
|
| 101 |
* @return bool true if Jetpack connection has access token.
|
| 102 |
*/
|
| 103 |
public function is_connected() {
|
| 104 |
-
return $this->connection_manager->is_active();
|
| 105 |
}
|
| 106 |
|
| 107 |
/**
|
|
@@ -113,15 +113,18 @@ class WC_Payments_Http {
|
|
| 113 |
* @throws WC_Payments_API_Exception - Exception thrown on failure.
|
| 114 |
*/
|
| 115 |
public function start_connection( $redirect ) {
|
| 116 |
-
//
|
| 117 |
-
|
|
|
|
|
|
|
|
|
|
| 118 |
$result = $this->connection_manager->register();
|
| 119 |
if ( is_wp_error( $result ) ) {
|
| 120 |
throw new WC_Payments_API_Exception( $result->get_error_message(), 'wcpay_jetpack_register_site_failed', 500 );
|
| 121 |
}
|
| 122 |
}
|
| 123 |
|
| 124 |
-
//
|
| 125 |
add_filter( 'jetpack_use_iframe_authorization_flow', '__return_false' );
|
| 126 |
// Same logic as in WC-Admin.
|
| 127 |
$calypso_env = defined( 'WOOCOMMERCE_CALYPSO_ENVIRONMENT' ) && in_array( WOOCOMMERCE_CALYPSO_ENVIRONMENT, [ 'development', 'wpcalypso', 'horizon', 'stage' ], true ) ? WOOCOMMERCE_CALYPSO_ENVIRONMENT : 'production';
|
| 101 |
* @return bool true if Jetpack connection has access token.
|
| 102 |
*/
|
| 103 |
public function is_connected() {
|
| 104 |
+
return $this->connection_manager->is_plugin_enabled() && $this->connection_manager->is_active();
|
| 105 |
}
|
| 106 |
|
| 107 |
/**
|
| 113 |
* @throws WC_Payments_API_Exception - Exception thrown on failure.
|
| 114 |
*/
|
| 115 |
public function start_connection( $redirect ) {
|
| 116 |
+
// Mark the plugin as enabled in case it had been soft-disconnected.
|
| 117 |
+
$this->connection_manager->enable_plugin();
|
| 118 |
+
|
| 119 |
+
// Register the site to wp.com.
|
| 120 |
+
if ( ! $this->connection_manager->is_registered() ) {
|
| 121 |
$result = $this->connection_manager->register();
|
| 122 |
if ( is_wp_error( $result ) ) {
|
| 123 |
throw new WC_Payments_API_Exception( $result->get_error_message(), 'wcpay_jetpack_register_site_failed', 500 );
|
| 124 |
}
|
| 125 |
}
|
| 126 |
|
| 127 |
+
// Redirect the user to the Jetpack user connection flow.
|
| 128 |
add_filter( 'jetpack_use_iframe_authorization_flow', '__return_false' );
|
| 129 |
// Same logic as in WC-Admin.
|
| 130 |
$calypso_env = defined( 'WOOCOMMERCE_CALYPSO_ENVIRONMENT' ) && in_array( WOOCOMMERCE_CALYPSO_ENVIRONMENT, [ 'development', 'wpcalypso', 'horizon', 'stage' ], true ) ? WOOCOMMERCE_CALYPSO_ENVIRONMENT : 'production';
|
readme.txt
CHANGED
|
@@ -1,10 +1,10 @@
|
|
| 1 |
=== WooCommerce Payments ===
|
| 2 |
-
Contributors: automattic
|
| 3 |
Tags: woocommerce, payment, payment request, credit card, automattic
|
| 4 |
Requires at least: 5.3
|
| 5 |
Tested up to: 5.4
|
| 6 |
Requires PHP: 7.0
|
| 7 |
-
Stable tag: 1.
|
| 8 |
License: GPLv2 or later
|
| 9 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
| 10 |
|
|
@@ -90,6 +90,14 @@ You can read our Terms of Service [here](https://en.wordpress.com/tos).
|
|
| 90 |
|
| 91 |
== Changelog ==
|
| 92 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 93 |
= 1.3.0 - 2020-08-17 =
|
| 94 |
* Add - Support for saved cards.
|
| 95 |
* Add - Search bar for transactions.
|
| 1 |
=== WooCommerce Payments ===
|
| 2 |
+
Contributors: woocommerce, automattic
|
| 3 |
Tags: woocommerce, payment, payment request, credit card, automattic
|
| 4 |
Requires at least: 5.3
|
| 5 |
Tested up to: 5.4
|
| 6 |
Requires PHP: 7.0
|
| 7 |
+
Stable tag: 1.4.0
|
| 8 |
License: GPLv2 or later
|
| 9 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
| 10 |
|
| 90 |
|
| 91 |
== Changelog ==
|
| 92 |
|
| 93 |
+
= 1.4.0 - 2020-09-02 =
|
| 94 |
+
* Add - Initial support for WooCommerce Subscriptions: Signing up for subscriptions, scheduled payments, and customer-initiated payment method changes.
|
| 95 |
+
* Add - Added a link to transaction details from order screens.
|
| 96 |
+
* Add - Allow merchant to edit statement descriptor.
|
| 97 |
+
* Fix - Do not redirect to the onboarding page after completing the WC4.5-beta wizard.
|
| 98 |
+
* Fix - Save order metadata before the payment is completed to avoid missing payments.
|
| 99 |
+
* Update - Bumped the minimum Jetpack requirement to version 8.2.
|
| 100 |
+
|
| 101 |
= 1.3.0 - 2020-08-17 =
|
| 102 |
* Add - Support for saved cards.
|
| 103 |
* Add - Search bar for transactions.
|
vendor/autoload.php
CHANGED
|
@@ -4,4 +4,4 @@
|
|
| 4 |
|
| 5 |
require_once __DIR__ . '/composer/autoload_real.php';
|
| 6 |
|
| 7 |
-
return
|
| 4 |
|
| 5 |
require_once __DIR__ . '/composer/autoload_real.php';
|
| 6 |
|
| 7 |
+
return ComposerAutoloaderInit0a651f92f6dec0685e6f92fb5fc9b1f9::getLoader();
|
vendor/autoload_packages.php
CHANGED
|
@@ -179,7 +179,7 @@ if ( ! function_exists( __NAMESPACE__ . '\autoloader' ) ) {
|
|
| 179 |
/**
|
| 180 |
* Prepare all the classes for autoloading.
|
| 181 |
*/
|
| 182 |
-
function
|
| 183 |
$class_map = require_once dirname( __FILE__ ) . '/composer/autoload_classmap_package.php';
|
| 184 |
foreach ( $class_map as $class_name => $class_info ) {
|
| 185 |
enqueue_package_class( $class_name, $class_info['version'], $class_info['path'] );
|
|
@@ -203,4 +203,4 @@ function enqueue_packages_996f9e0187d1cf069c402189f248054f() {
|
|
| 203 |
file_loader(); // Either WordPress is not loaded or plugin is doing it wrong. Either way we'll load the files so nothing breaks.
|
| 204 |
}
|
| 205 |
}
|
| 206 |
-
|
| 179 |
/**
|
| 180 |
* Prepare all the classes for autoloading.
|
| 181 |
*/
|
| 182 |
+
function enqueue_packages_1c17c81d6bb0e789d15762cdc7617239() {
|
| 183 |
$class_map = require_once dirname( __FILE__ ) . '/composer/autoload_classmap_package.php';
|
| 184 |
foreach ( $class_map as $class_name => $class_info ) {
|
| 185 |
enqueue_package_class( $class_name, $class_info['version'], $class_info['path'] );
|
| 203 |
file_loader(); // Either WordPress is not loaded or plugin is doing it wrong. Either way we'll load the files so nothing breaks.
|
| 204 |
}
|
| 205 |
}
|
| 206 |
+
enqueue_packages_1c17c81d6bb0e789d15762cdc7617239();
|
vendor/automattic/jetpack-config/src/class-config.php
CHANGED
|
@@ -8,7 +8,8 @@
|
|
| 8 |
namespace Automattic\Jetpack;
|
| 9 |
|
| 10 |
use Automattic\Jetpack\Connection\Manager;
|
| 11 |
-
use Automattic\Jetpack\JITMS\JITM;
|
|
|
|
| 12 |
use Automattic\Jetpack\Connection\Plugin;
|
| 13 |
use Automattic\Jetpack\Plugin\Tracking as Plugin_Tracking;
|
| 14 |
use Automattic\Jetpack\Sync\Main as Sync_Main;
|
|
@@ -91,8 +92,10 @@ class Config {
|
|
| 91 |
}
|
| 92 |
|
| 93 |
if ( $this->config['jitm'] ) {
|
| 94 |
-
|
| 95 |
-
|
|
|
|
|
|
|
| 96 |
}
|
| 97 |
}
|
| 98 |
|
|
@@ -100,13 +103,15 @@ class Config {
|
|
| 100 |
* Returns true if the required class is available and alerts the user if it's not available
|
| 101 |
* in case the site is in debug mode.
|
| 102 |
*
|
| 103 |
-
* @param String
|
|
|
|
|
|
|
| 104 |
* @return Boolean whether the class is available.
|
| 105 |
*/
|
| 106 |
-
protected function ensure_class( $classname ) {
|
| 107 |
$available = class_exists( $classname );
|
| 108 |
|
| 109 |
-
if ( ! $available && defined( 'WP_DEBUG' ) && WP_DEBUG ) {
|
| 110 |
trigger_error( // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
|
| 111 |
sprintf(
|
| 112 |
/* translators: %1$s is a PHP class name. */
|
|
@@ -190,7 +195,12 @@ class Config {
|
|
| 190 |
* Enables the JITM feature.
|
| 191 |
*/
|
| 192 |
protected function enable_jitm() {
|
| 193 |
-
JITM
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 194 |
|
| 195 |
return true;
|
| 196 |
}
|
| 8 |
namespace Automattic\Jetpack;
|
| 9 |
|
| 10 |
use Automattic\Jetpack\Connection\Manager;
|
| 11 |
+
use Automattic\Jetpack\JITMS\JITM as JITMS_JITM;
|
| 12 |
+
use Automattic\Jetpack\JITM as JITM;
|
| 13 |
use Automattic\Jetpack\Connection\Plugin;
|
| 14 |
use Automattic\Jetpack\Plugin\Tracking as Plugin_Tracking;
|
| 15 |
use Automattic\Jetpack\Sync\Main as Sync_Main;
|
| 92 |
}
|
| 93 |
|
| 94 |
if ( $this->config['jitm'] ) {
|
| 95 |
+
// Check for the JITM class in both namespaces. The namespace was changed in jetpack-jitm v1.6.
|
| 96 |
+
( $this->ensure_class( 'Automattic\Jetpack\JITMS\JITM', false )
|
| 97 |
+
|| $this->ensure_class( 'Automattic\Jetpack\JITM' ) )
|
| 98 |
+
&& $this->ensure_feature( 'jitm' );
|
| 99 |
}
|
| 100 |
}
|
| 101 |
|
| 103 |
* Returns true if the required class is available and alerts the user if it's not available
|
| 104 |
* in case the site is in debug mode.
|
| 105 |
*
|
| 106 |
+
* @param String $classname a fully qualified class name.
|
| 107 |
+
* @param Boolean $log_notice whether the E_USER_NOTICE should be generated if the class is not found.
|
| 108 |
+
*
|
| 109 |
* @return Boolean whether the class is available.
|
| 110 |
*/
|
| 111 |
+
protected function ensure_class( $classname, $log_notice = true ) {
|
| 112 |
$available = class_exists( $classname );
|
| 113 |
|
| 114 |
+
if ( $log_notice && ! $available && defined( 'WP_DEBUG' ) && WP_DEBUG ) {
|
| 115 |
trigger_error( // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_trigger_error
|
| 116 |
sprintf(
|
| 117 |
/* translators: %1$s is a PHP class name. */
|
| 195 |
* Enables the JITM feature.
|
| 196 |
*/
|
| 197 |
protected function enable_jitm() {
|
| 198 |
+
if ( class_exists( 'Automattic\Jetpack\JITMS\JITM' ) ) {
|
| 199 |
+
JITMS_JITM::configure();
|
| 200 |
+
} else {
|
| 201 |
+
// Provides compatibility with jetpack-jitm <v1.6.
|
| 202 |
+
JITM::configure();
|
| 203 |
+
}
|
| 204 |
|
| 205 |
return true;
|
| 206 |
}
|
vendor/automattic/jetpack-connection/.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
| 1 |
+
wordpress
|
vendor/automattic/jetpack-connection/composer.json
CHANGED
|
@@ -4,13 +4,15 @@
|
|
| 4 |
"type": "library",
|
| 5 |
"license": "GPL-2.0-or-later",
|
| 6 |
"require": {
|
| 7 |
-
"automattic/jetpack-constants": "1.
|
| 8 |
-
"automattic/jetpack-options": "1.
|
| 9 |
-
"automattic/jetpack-roles": "1.0
|
|
|
|
| 10 |
},
|
| 11 |
"require-dev": {
|
| 12 |
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5",
|
| 13 |
-
"php-mock/php-mock": "^2.1"
|
|
|
|
| 14 |
},
|
| 15 |
"autoload": {
|
| 16 |
"files": [
|
|
@@ -25,7 +27,8 @@
|
|
| 25 |
"phpunit": [
|
| 26 |
"@composer install",
|
| 27 |
"./vendor/phpunit/phpunit/phpunit --colors=always"
|
| 28 |
-
]
|
|
|
|
| 29 |
},
|
| 30 |
"repositories": [
|
| 31 |
{
|
| 4 |
"type": "library",
|
| 5 |
"license": "GPL-2.0-or-later",
|
| 6 |
"require": {
|
| 7 |
+
"automattic/jetpack-constants": "1.4.0",
|
| 8 |
+
"automattic/jetpack-options": "1.7.0",
|
| 9 |
+
"automattic/jetpack-roles": "1.2.0",
|
| 10 |
+
"automattic/jetpack-status": "1.3.0"
|
| 11 |
},
|
| 12 |
"require-dev": {
|
| 13 |
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5",
|
| 14 |
+
"php-mock/php-mock": "^2.1",
|
| 15 |
+
"automattic/wordbless": "@dev"
|
| 16 |
},
|
| 17 |
"autoload": {
|
| 18 |
"files": [
|
| 27 |
"phpunit": [
|
| 28 |
"@composer install",
|
| 29 |
"./vendor/phpunit/phpunit/phpunit --colors=always"
|
| 30 |
+
],
|
| 31 |
+
"post-update-cmd": "php -r \"copy('vendor/automattic/wordbless/src/dbless-wpdb.php', 'wordpress/wp-content/db.php');\""
|
| 32 |
},
|
| 33 |
"repositories": [
|
| 34 |
{
|
vendor/automattic/jetpack-connection/docs/register-site.md
CHANGED
|
@@ -69,7 +69,15 @@ add_action( 'admin_post_register_site', 'your_plugin_register_site' );
|
|
| 69 |
|
| 70 |
function your_plugin_register_site() {
|
| 71 |
check_admin_referer( 'register-site' );
|
| 72 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
|
| 74 |
// This is where you could put your error handling, redirects, or whatever decorations you need.
|
| 75 |
}
|
|
@@ -101,12 +109,91 @@ use Automattic\Jetpack\Connection\Manager;
|
|
| 101 |
function your_plugin_disconnect_site() {
|
| 102 |
check_admin_referer( 'disconnect-site' );
|
| 103 |
|
| 104 |
-
|
| 105 |
-
( new Manager( 'plugin-slug' ) )->disconnect_site_wpcom();
|
| 106 |
|
| 107 |
-
//
|
| 108 |
-
|
|
|
|
|
|
|
| 109 |
|
| 110 |
// Your error handling and decorations
|
| 111 |
}
|
| 112 |
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
|
| 70 |
function your_plugin_register_site() {
|
| 71 |
check_admin_referer( 'register-site' );
|
| 72 |
+
$manager = new Manager( 'plugin-slug' );
|
| 73 |
+
|
| 74 |
+
// Mark the plugin connection as enabled, in case it was disabled earlier.
|
| 75 |
+
$manager->enable_plugin();
|
| 76 |
+
|
| 77 |
+
// If the token doesn't exist (see "Soft and Hard Disconnect" section below), we need to register the site.
|
| 78 |
+
if ( ! $manager->get_access_token() ) {
|
| 79 |
+
$manager->register();
|
| 80 |
+
}
|
| 81 |
|
| 82 |
// This is where you could put your error handling, redirects, or whatever decorations you need.
|
| 83 |
}
|
| 109 |
function your_plugin_disconnect_site() {
|
| 110 |
check_admin_referer( 'disconnect-site' );
|
| 111 |
|
| 112 |
+
$manager = new Manager( 'plugin-slug' );
|
|
|
|
| 113 |
|
| 114 |
+
// Mark the plugin connection as disabled.
|
| 115 |
+
// If there are no other plugins using the connection, destroy blog and user tokens,
|
| 116 |
+
// as well as the tokens stored in wordpress.com
|
| 117 |
+
$manager->remove_connection();
|
| 118 |
|
| 119 |
// Your error handling and decorations
|
| 120 |
}
|
| 121 |
```
|
| 122 |
+
|
| 123 |
+
|
| 124 |
+
#### Custom Disconnect
|
| 125 |
+
|
| 126 |
+
Method `$manager->remove_connection()` essentially calls `disable_plugin()`, `disconnect_site_wpcom()`, and `delete_all_connection_tokens()`.
|
| 127 |
+
Its purpose is to simplify the disconnection process.
|
| 128 |
+
If you need to customize the disconnect process, or perform a partial disconnect, you can call these methods one by one.
|
| 129 |
+
|
| 130 |
+
```php
|
| 131 |
+
// Mark the plugin connection as disabled.
|
| 132 |
+
|
| 133 |
+
$manager = new Manager( 'plugin-slug' );
|
| 134 |
+
|
| 135 |
+
// Mark the plugin connection as disabled.
|
| 136 |
+
$manager->disable_plugin();
|
| 137 |
+
|
| 138 |
+
// If no other plugins use the connection, this will destroy the blog tokens on both this site, and the tokens stored on wordpress.com
|
| 139 |
+
$manager->disconnect_site_wpcom();
|
| 140 |
+
|
| 141 |
+
// If no other plugins use the connection, this will clear all the tokens!
|
| 142 |
+
$manager->delete_all_connection_tokens();
|
| 143 |
+
```
|
| 144 |
+
|
| 145 |
+
### Soft and Hard Disconnect
|
| 146 |
+
|
| 147 |
+
There are two types of disconnection happening when you request a disconnect: *Soft Disconnect* and *Hard Disconnect*.
|
| 148 |
+
The package API takes care of that under the hood, so in most cases there won't be any need to differentiate them in your code.
|
| 149 |
+
Below is some basic information on how they differ.
|
| 150 |
+
|
| 151 |
+
#### Soft Disconnect
|
| 152 |
+
|
| 153 |
+
Soft disconnect means that all the tokens are preserved, and the connection for other plugins stays active.
|
| 154 |
+
Technically speaking, soft disconnect happens when you call `$manager->disable_plugin();`.
|
| 155 |
+
Next time you try to use the connection, you call `$manager->is_plugin_enabled()`, which will return `false`.
|
| 156 |
+
|
| 157 |
+
Calling `$manager->disconnect_site_wpcom()` and `$manager->delete_all_connection_tokens()` afterwards is still needed.
|
| 158 |
+
These calls will determine if the aforementioned plugin is the only one using the connection, and perform *soft* or *hard* disconnect accordingly.
|
| 159 |
+
|
| 160 |
+
#### Hard Disconnect
|
| 161 |
+
|
| 162 |
+
If there are no other plugins using the connection, or all of them have already been *softly disconnected*, the package will perform the *hard disconnect*.
|
| 163 |
+
In that case methods `disconnect_site_wpcom()` and `delete_all_connection_tokens()` will actually remove the tokens and run the `deregister` API request.
|
| 164 |
+
|
| 165 |
+
You can explicitly request hard disconnect by providing the argument `$ignore_connected_plugins`:
|
| 166 |
+
```php
|
| 167 |
+
$manager = new Manager( 'plugin-slug' );
|
| 168 |
+
|
| 169 |
+
$manager->disable_plugin();
|
| 170 |
+
|
| 171 |
+
// The `$ignore_connected_plugins` argument is set to `true`, so the Connection Manager will perform the hard disconnect.
|
| 172 |
+
$manager->disconnect_site_wpcom( true );
|
| 173 |
+
$manager->delete_all_connection_tokens( true );
|
| 174 |
+
```
|
| 175 |
+
|
| 176 |
+
#### Using the connection
|
| 177 |
+
If the plugin was *softly* disconnected, the access tokens will still be accessible.
|
| 178 |
+
However, the user explicitly requested the plugin to be disabled, so you need to check for that before you utilize the connection in any way:
|
| 179 |
+
```php
|
| 180 |
+
$manager = new Manager( 'plugin-slug' );
|
| 181 |
+
|
| 182 |
+
if ( $manager->is_plugin_enabled() && $manager->get_access_token() ) {
|
| 183 |
+
// Perform the API requests.
|
| 184 |
+
} else {
|
| 185 |
+
// Assume the plugin is disconnected, no matter if the tokens actually exist.
|
| 186 |
+
}
|
| 187 |
+
```
|
| 188 |
+
|
| 189 |
+
#### Reconnecting
|
| 190 |
+
Whether a *soft* or *hard* disconnect was performed, the plugin will be marked as "disconnected", so if the connect is being reestablished, you need to call `$manager->enable_plugin()` to remove that flag.
|
| 191 |
+
If the plugin was *softly* disconnected, removing the flag is enough for it to work. Otherwise, you'll need to register the website again:
|
| 192 |
+
```php
|
| 193 |
+
$manager = new Manager( 'plugin-slug' );
|
| 194 |
+
$manager->enable_plugin();
|
| 195 |
+
|
| 196 |
+
if ( ! $manager->get_access_token() ) {
|
| 197 |
+
$manager->register();
|
| 198 |
+
}
|
| 199 |
+
```
|
vendor/automattic/jetpack-connection/legacy/class-jetpack-ixr-client.php
CHANGED
|
@@ -49,10 +49,11 @@ class Jetpack_IXR_Client extends IXR_Client {
|
|
| 49 |
/**
|
| 50 |
* Perform the IXR request.
|
| 51 |
*
|
|
|
|
|
|
|
| 52 |
* @return bool True if request succeeded, false otherwise.
|
| 53 |
*/
|
| 54 |
-
public function query() {
|
| 55 |
-
$args = func_get_args();
|
| 56 |
$method = array_shift( $args );
|
| 57 |
$request = new IXR_Request( $method, $args );
|
| 58 |
$xml = trim( $request->getXml() );
|
| 49 |
/**
|
| 50 |
* Perform the IXR request.
|
| 51 |
*
|
| 52 |
+
* @param string[] ...$args IXR args.
|
| 53 |
+
*
|
| 54 |
* @return bool True if request succeeded, false otherwise.
|
| 55 |
*/
|
| 56 |
+
public function query( ...$args ) {
|
|
|
|
| 57 |
$method = array_shift( $args );
|
| 58 |
$request = new IXR_Request( $method, $args );
|
| 59 |
$xml = trim( $request->getXml() );
|
vendor/automattic/jetpack-connection/legacy/class-jetpack-ixr-clientmulticall.php
CHANGED
|
@@ -23,9 +23,10 @@ class Jetpack_IXR_ClientMulticall extends Jetpack_IXR_Client {
|
|
| 23 |
* Add a IXR call to the client.
|
| 24 |
* First argument is the method name.
|
| 25 |
* The rest of the arguments are the params specified to the method.
|
|
|
|
|
|
|
| 26 |
*/
|
| 27 |
-
public function addCall() {
|
| 28 |
-
$args = func_get_args();
|
| 29 |
$method_name = array_shift( $args );
|
| 30 |
$struct = array(
|
| 31 |
'methodName' => $method_name,
|
|
@@ -37,9 +38,11 @@ class Jetpack_IXR_ClientMulticall extends Jetpack_IXR_Client {
|
|
| 37 |
/**
|
| 38 |
* Perform the IXR multicall request.
|
| 39 |
*
|
|
|
|
|
|
|
| 40 |
* @return bool True if request succeeded, false otherwise.
|
| 41 |
*/
|
| 42 |
-
public function query() {
|
| 43 |
usort( $this->calls, array( $this, 'sort_calls' ) );
|
| 44 |
|
| 45 |
// Prepare multicall, then call the parent::query() method.
|
| 23 |
* Add a IXR call to the client.
|
| 24 |
* First argument is the method name.
|
| 25 |
* The rest of the arguments are the params specified to the method.
|
| 26 |
+
*
|
| 27 |
+
* @param string[] ...$args IXR args.
|
| 28 |
*/
|
| 29 |
+
public function addCall( ...$args ) {
|
|
|
|
| 30 |
$method_name = array_shift( $args );
|
| 31 |
$struct = array(
|
| 32 |
'methodName' => $method_name,
|
| 38 |
/**
|
| 39 |
* Perform the IXR multicall request.
|
| 40 |
*
|
| 41 |
+
* @param string[] ...$args IXR args.
|
| 42 |
+
*
|
| 43 |
* @return bool True if request succeeded, false otherwise.
|
| 44 |
*/
|
| 45 |
+
public function query( ...$args ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
|
| 46 |
usort( $this->calls, array( $this, 'sort_calls' ) );
|
| 47 |
|
| 48 |
// Prepare multicall, then call the parent::query() method.
|
vendor/automattic/jetpack-connection/legacy/class-jetpack-xmlrpc-server.php
CHANGED
|
@@ -56,29 +56,35 @@ class Jetpack_XMLRPC_Server {
|
|
| 56 |
*/
|
| 57 |
public function xmlrpc_methods( $core_methods ) {
|
| 58 |
$jetpack_methods = array(
|
| 59 |
-
'jetpack.jsonAPI' => array( $this, 'json_api' ),
|
| 60 |
'jetpack.verifyAction' => array( $this, 'verify_action' ),
|
| 61 |
'jetpack.getUser' => array( $this, 'get_user' ),
|
| 62 |
'jetpack.remoteRegister' => array( $this, 'remote_register' ),
|
| 63 |
'jetpack.remoteProvision' => array( $this, 'remote_provision' ),
|
| 64 |
);
|
| 65 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 66 |
$this->user = $this->login();
|
| 67 |
|
| 68 |
if ( $this->user ) {
|
| 69 |
$jetpack_methods = array_merge(
|
| 70 |
$jetpack_methods,
|
| 71 |
array(
|
| 72 |
-
'jetpack.
|
| 73 |
-
'jetpack.
|
| 74 |
-
'jetpack.
|
| 75 |
-
'jetpack.
|
| 76 |
-
'jetpack.disconnectBlog' => array( $this, 'disconnect_blog' ),
|
| 77 |
-
'jetpack.unlinkUser' => array( $this, 'unlink_user' ),
|
| 78 |
-
'jetpack.idcUrlValidation' => array( $this, 'validate_urls_for_idc_mitigation' ),
|
| 79 |
)
|
| 80 |
);
|
| 81 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 82 |
if ( isset( $core_methods['metaWeblog.editPost'] ) ) {
|
| 83 |
$jetpack_methods['metaWeblog.newMediaObject'] = $core_methods['metaWeblog.newMediaObject'];
|
| 84 |
$jetpack_methods['jetpack.updateAttachmentParent'] = array( $this, 'update_attachment_parent' );
|
|
@@ -159,7 +165,7 @@ class Jetpack_XMLRPC_Server {
|
|
| 159 |
|
| 160 |
if ( ! $user_id ) {
|
| 161 |
return $this->error(
|
| 162 |
-
new
|
| 163 |
'invalid_user',
|
| 164 |
__( 'Invalid user identifier.', 'jetpack' ),
|
| 165 |
400
|
|
@@ -172,7 +178,7 @@ class Jetpack_XMLRPC_Server {
|
|
| 172 |
|
| 173 |
if ( ! $user ) {
|
| 174 |
return $this->error(
|
| 175 |
-
new
|
| 176 |
'user_unknown',
|
| 177 |
__( 'User not found.', 'jetpack' ),
|
| 178 |
404
|
|
@@ -230,18 +236,18 @@ class Jetpack_XMLRPC_Server {
|
|
| 230 |
foreach ( array( 'secret', 'state', 'redirect_uri', 'code' ) as $required ) {
|
| 231 |
if ( ! isset( $request[ $required ] ) || empty( $request[ $required ] ) ) {
|
| 232 |
return $this->error(
|
| 233 |
-
new
|
| 234 |
'remote_authorize'
|
| 235 |
);
|
| 236 |
}
|
| 237 |
}
|
| 238 |
|
| 239 |
if ( ! $user ) {
|
| 240 |
-
return $this->error( new
|
| 241 |
}
|
| 242 |
|
| 243 |
if ( $this->connection->is_active() && $this->connection->is_user_connected( $request['state'] ) ) {
|
| 244 |
-
return $this->error( new
|
| 245 |
}
|
| 246 |
|
| 247 |
$verified = $this->verify_action( array( 'authorize', $request['secret'], $request['state'] ) );
|
|
@@ -293,7 +299,7 @@ class Jetpack_XMLRPC_Server {
|
|
| 293 |
|
| 294 |
if ( empty( $request['nonce'] ) ) {
|
| 295 |
return $this->error(
|
| 296 |
-
new
|
| 297 |
'nonce_missing',
|
| 298 |
__( 'The required "nonce" parameter is missing.', 'jetpack' ),
|
| 299 |
400
|
|
@@ -319,7 +325,7 @@ class Jetpack_XMLRPC_Server {
|
|
| 319 |
'OK' !== trim( wp_remote_retrieve_body( $response ) )
|
| 320 |
) {
|
| 321 |
return $this->error(
|
| 322 |
-
new
|
| 323 |
'invalid_nonce',
|
| 324 |
__( 'There was an issue validating this request.', 'jetpack' ),
|
| 325 |
400
|
|
@@ -338,7 +344,7 @@ class Jetpack_XMLRPC_Server {
|
|
| 338 |
return $this->error( $registered, 'remote_register' );
|
| 339 |
} elseif ( ! $registered ) {
|
| 340 |
return $this->error(
|
| 341 |
-
new
|
| 342 |
'registration_error',
|
| 343 |
__( 'There was an unspecified error registering the site', 'jetpack' ),
|
| 344 |
400
|
|
@@ -506,7 +512,7 @@ class Jetpack_XMLRPC_Server {
|
|
| 506 |
private function fetch_and_verify_local_user( $request ) {
|
| 507 |
if ( empty( $request['local_user'] ) ) {
|
| 508 |
return $this->error(
|
| 509 |
-
new
|
| 510 |
'local_user_missing',
|
| 511 |
__( 'The required "local_user" parameter is missing.', 'jetpack' ),
|
| 512 |
400
|
|
@@ -589,13 +595,13 @@ class Jetpack_XMLRPC_Server {
|
|
| 589 |
$user = wp_authenticate( 'username', 'password' );
|
| 590 |
if ( is_wp_error( $user ) ) {
|
| 591 |
if ( 'authentication_failed' === $user->get_error_code() ) { // Generic error could mean most anything.
|
| 592 |
-
$this->error = new
|
| 593 |
} else {
|
| 594 |
$this->error = $user;
|
| 595 |
}
|
| 596 |
return false;
|
| 597 |
} elseif ( ! $user ) { // Shouldn't happen.
|
| 598 |
-
$this->error = new
|
| 599 |
return false;
|
| 600 |
}
|
| 601 |
|
| 56 |
*/
|
| 57 |
public function xmlrpc_methods( $core_methods ) {
|
| 58 |
$jetpack_methods = array(
|
|
|
|
| 59 |
'jetpack.verifyAction' => array( $this, 'verify_action' ),
|
| 60 |
'jetpack.getUser' => array( $this, 'get_user' ),
|
| 61 |
'jetpack.remoteRegister' => array( $this, 'remote_register' ),
|
| 62 |
'jetpack.remoteProvision' => array( $this, 'remote_provision' ),
|
| 63 |
);
|
| 64 |
|
| 65 |
+
if ( class_exists( 'Jetpack' ) ) {
|
| 66 |
+
$jetpack_methods['jetpack.jsonAPI'] = array( $this, 'json_api' );
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
$this->user = $this->login();
|
| 70 |
|
| 71 |
if ( $this->user ) {
|
| 72 |
$jetpack_methods = array_merge(
|
| 73 |
$jetpack_methods,
|
| 74 |
array(
|
| 75 |
+
'jetpack.testAPIUserCode' => array( $this, 'test_api_user_code' ),
|
| 76 |
+
'jetpack.disconnectBlog' => array( $this, 'disconnect_blog' ),
|
| 77 |
+
'jetpack.unlinkUser' => array( $this, 'unlink_user' ),
|
| 78 |
+
'jetpack.idcUrlValidation' => array( $this, 'validate_urls_for_idc_mitigation' ),
|
|
|
|
|
|
|
|
|
|
| 79 |
)
|
| 80 |
);
|
| 81 |
|
| 82 |
+
if ( class_exists( 'Jetpack' ) ) {
|
| 83 |
+
$jetpack_methods['jetpack.testConnection'] = array( $this, 'test_connection' );
|
| 84 |
+
$jetpack_methods['jetpack.featuresAvailable'] = array( $this, 'features_available' );
|
| 85 |
+
$jetpack_methods['jetpack.featuresEnabled'] = array( $this, 'features_enabled' );
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
if ( isset( $core_methods['metaWeblog.editPost'] ) ) {
|
| 89 |
$jetpack_methods['metaWeblog.newMediaObject'] = $core_methods['metaWeblog.newMediaObject'];
|
| 90 |
$jetpack_methods['jetpack.updateAttachmentParent'] = array( $this, 'update_attachment_parent' );
|
| 165 |
|
| 166 |
if ( ! $user_id ) {
|
| 167 |
return $this->error(
|
| 168 |
+
new \WP_Error(
|
| 169 |
'invalid_user',
|
| 170 |
__( 'Invalid user identifier.', 'jetpack' ),
|
| 171 |
400
|
| 178 |
|
| 179 |
if ( ! $user ) {
|
| 180 |
return $this->error(
|
| 181 |
+
new \WP_Error(
|
| 182 |
'user_unknown',
|
| 183 |
__( 'User not found.', 'jetpack' ),
|
| 184 |
404
|
| 236 |
foreach ( array( 'secret', 'state', 'redirect_uri', 'code' ) as $required ) {
|
| 237 |
if ( ! isset( $request[ $required ] ) || empty( $request[ $required ] ) ) {
|
| 238 |
return $this->error(
|
| 239 |
+
new \WP_Error( 'missing_parameter', 'One or more parameters is missing from the request.', 400 ),
|
| 240 |
'remote_authorize'
|
| 241 |
);
|
| 242 |
}
|
| 243 |
}
|
| 244 |
|
| 245 |
if ( ! $user ) {
|
| 246 |
+
return $this->error( new \WP_Error( 'user_unknown', 'User not found.', 404 ), 'remote_authorize' );
|
| 247 |
}
|
| 248 |
|
| 249 |
if ( $this->connection->is_active() && $this->connection->is_user_connected( $request['state'] ) ) {
|
| 250 |
+
return $this->error( new \WP_Error( 'already_connected', 'User already connected.', 400 ), 'remote_authorize' );
|
| 251 |
}
|
| 252 |
|
| 253 |
$verified = $this->verify_action( array( 'authorize', $request['secret'], $request['state'] ) );
|
| 299 |
|
| 300 |
if ( empty( $request['nonce'] ) ) {
|
| 301 |
return $this->error(
|
| 302 |
+
new \WP_Error(
|
| 303 |
'nonce_missing',
|
| 304 |
__( 'The required "nonce" parameter is missing.', 'jetpack' ),
|
| 305 |
400
|
| 325 |
'OK' !== trim( wp_remote_retrieve_body( $response ) )
|
| 326 |
) {
|
| 327 |
return $this->error(
|
| 328 |
+
new \WP_Error(
|
| 329 |
'invalid_nonce',
|
| 330 |
__( 'There was an issue validating this request.', 'jetpack' ),
|
| 331 |
400
|
| 344 |
return $this->error( $registered, 'remote_register' );
|
| 345 |
} elseif ( ! $registered ) {
|
| 346 |
return $this->error(
|
| 347 |
+
new \WP_Error(
|
| 348 |
'registration_error',
|
| 349 |
__( 'There was an unspecified error registering the site', 'jetpack' ),
|
| 350 |
400
|
| 512 |
private function fetch_and_verify_local_user( $request ) {
|
| 513 |
if ( empty( $request['local_user'] ) ) {
|
| 514 |
return $this->error(
|
| 515 |
+
new \WP_Error(
|
| 516 |
'local_user_missing',
|
| 517 |
__( 'The required "local_user" parameter is missing.', 'jetpack' ),
|
| 518 |
400
|
| 595 |
$user = wp_authenticate( 'username', 'password' );
|
| 596 |
if ( is_wp_error( $user ) ) {
|
| 597 |
if ( 'authentication_failed' === $user->get_error_code() ) { // Generic error could mean most anything.
|
| 598 |
+
$this->error = new \WP_Error( 'invalid_request', 'Invalid Request', 403 );
|
| 599 |
} else {
|
| 600 |
$this->error = $user;
|
| 601 |
}
|
| 602 |
return false;
|
| 603 |
} elseif ( ! $user ) { // Shouldn't happen.
|
| 604 |
+
$this->error = new \WP_Error( 'invalid_request', 'Invalid Request', 403 );
|
| 605 |
return false;
|
| 606 |
}
|
| 607 |
|
vendor/automattic/jetpack-connection/src/class-error-handler.php
ADDED
|
@@ -0,0 +1,621 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
/**
|
| 3 |
+
* The Jetpack Connection error class file.
|
| 4 |
+
*
|
| 5 |
+
* @package automattic/jetpack-connection
|
| 6 |
+
*/
|
| 7 |
+
|
| 8 |
+
namespace Automattic\Jetpack\Connection;
|
| 9 |
+
|
| 10 |
+
/**
|
| 11 |
+
* The Jetpack Connection Errors that handles errors
|
| 12 |
+
*
|
| 13 |
+
* This class handles the following workflow:
|
| 14 |
+
*
|
| 15 |
+
* 1. A XML-RCP request with an invalid signature triggers a error
|
| 16 |
+
* 2. Applies a gate to only process each error code once an hour to avoid overflow
|
| 17 |
+
* 3. It stores the error on the database, but we don't know yet if this is a valid error, because
|
| 18 |
+
* we can't confirm it came from WP.com.
|
| 19 |
+
* 4. It encrypts the error details and send it to thw wp.com server
|
| 20 |
+
* 5. wp.com checks it and, if valid, sends a new request back to this site using the verify_xml_rpc_error REST endpoint
|
| 21 |
+
* 6. This endpoint add this error to the Verified errors in the database
|
| 22 |
+
* 7. Triggers a workflow depending on the error (display user an error message, do some self healing, etc.)
|
| 23 |
+
*
|
| 24 |
+
* Errors are stored in the database as options in the following format:
|
| 25 |
+
*
|
| 26 |
+
* [
|
| 27 |
+
* $error_code => [
|
| 28 |
+
* $user_id => [
|
| 29 |
+
* $error_details
|
| 30 |
+
* ]
|
| 31 |
+
* ]
|
| 32 |
+
* ]
|
| 33 |
+
*
|
| 34 |
+
* For each error code we store a maximum of 5 errors for 5 different user ids.
|
| 35 |
+
*
|
| 36 |
+
* An user ID can be
|
| 37 |
+
* * 0 for blog tokens
|
| 38 |
+
* * positive integer for user tokens
|
| 39 |
+
* * 'invalid' for malformed tokens
|
| 40 |
+
*
|
| 41 |
+
* @since 8.7.0
|
| 42 |
+
*/
|
| 43 |
+
class Error_Handler {
|
| 44 |
+
|
| 45 |
+
/**
|
| 46 |
+
* The name of the option that stores the errors
|
| 47 |
+
*
|
| 48 |
+
* @since 8.7.0
|
| 49 |
+
*
|
| 50 |
+
* @var string
|
| 51 |
+
*/
|
| 52 |
+
const STORED_ERRORS_OPTION = 'jetpack_connection_xmlrpc_errors';
|
| 53 |
+
|
| 54 |
+
/**
|
| 55 |
+
* The name of the option that stores the errors
|
| 56 |
+
*
|
| 57 |
+
* @since 8.7.0
|
| 58 |
+
*
|
| 59 |
+
* @var string
|
| 60 |
+
*/
|
| 61 |
+
const STORED_VERIFIED_ERRORS_OPTION = 'jetpack_connection_xmlrpc_verified_errors';
|
| 62 |
+
|
| 63 |
+
/**
|
| 64 |
+
* The prefix of the transient that controls the gate for each error code
|
| 65 |
+
*
|
| 66 |
+
* @since 8.7.0
|
| 67 |
+
*
|
| 68 |
+
* @var string
|
| 69 |
+
*/
|
| 70 |
+
const ERROR_REPORTING_GATE = 'jetpack_connection_error_reporting_gate_';
|
| 71 |
+
|
| 72 |
+
/**
|
| 73 |
+
* Time in seconds a test should live in the database before being discarded
|
| 74 |
+
*
|
| 75 |
+
* @since 8.7.0
|
| 76 |
+
*/
|
| 77 |
+
const ERROR_LIFE_TIME = DAY_IN_SECONDS;
|
| 78 |
+
/**
|
| 79 |
+
* List of known errors. Only error codes in this list will be handled
|
| 80 |
+
*
|
| 81 |
+
* @since 8.7.0
|
| 82 |
+
*
|
| 83 |
+
* @var array
|
| 84 |
+
*/
|
| 85 |
+
public $known_errors = array(
|
| 86 |
+
'malformed_token',
|
| 87 |
+
'malformed_user_id',
|
| 88 |
+
'unknown_user',
|
| 89 |
+
'no_user_tokens',
|
| 90 |
+
'empty_master_user_option',
|
| 91 |
+
'no_token_for_user',
|
| 92 |
+
'token_malformed',
|
| 93 |
+
'user_id_mismatch',
|
| 94 |
+
'no_possible_tokens',
|
| 95 |
+
'no_valid_token',
|
| 96 |
+
'unknown_token',
|
| 97 |
+
'could_not_sign',
|
| 98 |
+
'invalid_scheme',
|
| 99 |
+
'invalid_secret',
|
| 100 |
+
'invalid_token',
|
| 101 |
+
'token_mismatch',
|
| 102 |
+
'invalid_body',
|
| 103 |
+
'invalid_signature',
|
| 104 |
+
'invalid_body_hash',
|
| 105 |
+
'invalid_nonce',
|
| 106 |
+
'signature_mismatch',
|
| 107 |
+
);
|
| 108 |
+
|
| 109 |
+
/**
|
| 110 |
+
* Holds the instance of this singleton class
|
| 111 |
+
*
|
| 112 |
+
* @since 8.7.0
|
| 113 |
+
*
|
| 114 |
+
* @var Error_Handler $instance
|
| 115 |
+
*/
|
| 116 |
+
public static $instance = null;
|
| 117 |
+
|
| 118 |
+
/**
|
| 119 |
+
* Initialize instance, hookds and load verified errors handlers
|
| 120 |
+
*
|
| 121 |
+
* @since 8.7.0
|
| 122 |
+
*/
|
| 123 |
+
private function __construct() {
|
| 124 |
+
defined( 'JETPACK__ERRORS_PUBLIC_KEY' ) || define( 'JETPACK__ERRORS_PUBLIC_KEY', 'KdZY80axKX+nWzfrOcizf0jqiFHnrWCl9X8yuaClKgM=' );
|
| 125 |
+
|
| 126 |
+
add_action( 'rest_api_init', array( $this, 'register_verify_error_endpoint' ) );
|
| 127 |
+
|
| 128 |
+
$this->handle_verified_errors();
|
| 129 |
+
|
| 130 |
+
// If the site gets reconnected, clear errors.
|
| 131 |
+
add_action( 'jetpack_site_registered', array( $this, 'delete_all_errors' ) );
|
| 132 |
+
add_action( 'jetpack_get_site_data_success', array( $this, 'delete_all_errors' ) );
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
/**
|
| 136 |
+
* Gets the list of verified errors and act upon them
|
| 137 |
+
*
|
| 138 |
+
* @since 8.7.0
|
| 139 |
+
*
|
| 140 |
+
* @return void
|
| 141 |
+
*/
|
| 142 |
+
public function handle_verified_errors() {
|
| 143 |
+
$verified_errors = $this->get_verified_errors();
|
| 144 |
+
foreach ( $verified_errors as $error_code => $user_errors ) {
|
| 145 |
+
|
| 146 |
+
switch ( $error_code ) {
|
| 147 |
+
case 'malformed_token':
|
| 148 |
+
case 'token_malformed':
|
| 149 |
+
case 'no_possible_tokens':
|
| 150 |
+
case 'no_valid_token':
|
| 151 |
+
case 'unknown_token':
|
| 152 |
+
case 'could_not_sign':
|
| 153 |
+
case 'invalid_token':
|
| 154 |
+
case 'token_mismatch':
|
| 155 |
+
case 'invalid_signature':
|
| 156 |
+
case 'signature_mismatch':
|
| 157 |
+
new Error_Handlers\Invalid_Blog_Token( $user_errors );
|
| 158 |
+
break;
|
| 159 |
+
}
|
| 160 |
+
}
|
| 161 |
+
}
|
| 162 |
+
|
| 163 |
+
/**
|
| 164 |
+
* Gets the instance of this singleton class
|
| 165 |
+
*
|
| 166 |
+
* @since 8.7.0
|
| 167 |
+
*
|
| 168 |
+
* @return Error_Handler $instance
|
| 169 |
+
*/
|
| 170 |
+
public static function get_instance() {
|
| 171 |
+
if ( is_null( self::$instance ) ) {
|
| 172 |
+
self::$instance = new self();
|
| 173 |
+
}
|
| 174 |
+
return self::$instance;
|
| 175 |
+
}
|
| 176 |
+
|
| 177 |
+
/**
|
| 178 |
+
* Keep track of a connection error that was encountered
|
| 179 |
+
*
|
| 180 |
+
* @since 8.7.0
|
| 181 |
+
*
|
| 182 |
+
* @param \WP_Error $error the error object.
|
| 183 |
+
* @param boolean $force Force the report, even if should_report_error is false.
|
| 184 |
+
* @return void
|
| 185 |
+
*/
|
| 186 |
+
public function report_error( \WP_Error $error, $force = false ) {
|
| 187 |
+
if ( in_array( $error->get_error_code(), $this->known_errors, true ) && $this->should_report_error( $error ) || $force ) {
|
| 188 |
+
$stored_error = $this->store_error( $error );
|
| 189 |
+
if ( $stored_error ) {
|
| 190 |
+
$this->send_error_to_wpcom( $stored_error );
|
| 191 |
+
}
|
| 192 |
+
}
|
| 193 |
+
}
|
| 194 |
+
|
| 195 |
+
/**
|
| 196 |
+
* Checks the status of the gate
|
| 197 |
+
*
|
| 198 |
+
* This protects the site (and WPCOM) against over loads.
|
| 199 |
+
*
|
| 200 |
+
* @since 8.7.0
|
| 201 |
+
*
|
| 202 |
+
* @param \WP_Error $error the error object.
|
| 203 |
+
* @return boolean $should_report True if gate is open and the error should be reported.
|
| 204 |
+
*/
|
| 205 |
+
public function should_report_error( \WP_Error $error ) {
|
| 206 |
+
|
| 207 |
+
if ( defined( 'JETPACK_DEV_DEBUG' ) && JETPACK_DEV_DEBUG ) {
|
| 208 |
+
return true;
|
| 209 |
+
}
|
| 210 |
+
|
| 211 |
+
/**
|
| 212 |
+
* Whether to bypass the gate for XML-RPC error handling
|
| 213 |
+
*
|
| 214 |
+
* By default, we only process XML-RPC errors once an hour for each error code.
|
| 215 |
+
* This is done to avoid overflows. If you need to disable this gate, you can set this variable to true.
|
| 216 |
+
*
|
| 217 |
+
* This filter is useful for unit testing
|
| 218 |
+
*
|
| 219 |
+
* @since 8.7.0
|
| 220 |
+
*
|
| 221 |
+
* @param boolean $bypass_gate whether to bypass the gate. Default is false, do not bypass.
|
| 222 |
+
*/
|
| 223 |
+
$bypass_gate = apply_filters( 'jetpack_connection_bypass_error_reporting_gate', false );
|
| 224 |
+
if ( true === $bypass_gate ) {
|
| 225 |
+
return true;
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
$transient = self::ERROR_REPORTING_GATE . $error->get_error_code();
|
| 229 |
+
|
| 230 |
+
if ( get_transient( $transient ) ) {
|
| 231 |
+
return false;
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
set_transient( $transient, true, HOUR_IN_SECONDS );
|
| 235 |
+
return true;
|
| 236 |
+
}
|
| 237 |
+
|
| 238 |
+
/**
|
| 239 |
+
* Stores the error in the database so we know there is an issue and can inform the user
|
| 240 |
+
*
|
| 241 |
+
* @since 8.7.0
|
| 242 |
+
*
|
| 243 |
+
* @param \WP_Error $error the error object.
|
| 244 |
+
* @return boolean|array False if stored errors were not updated and the error array if it was successfully stored.
|
| 245 |
+
*/
|
| 246 |
+
public function store_error( \WP_Error $error ) {
|
| 247 |
+
|
| 248 |
+
$stored_errors = $this->get_stored_errors();
|
| 249 |
+
$error_array = $this->wp_error_to_array( $error );
|
| 250 |
+
$error_code = $error->get_error_code();
|
| 251 |
+
$user_id = $error_array['user_id'];
|
| 252 |
+
|
| 253 |
+
if ( ! isset( $stored_errors[ $error_code ] ) || ! is_array( $stored_errors[ $error_code ] ) ) {
|
| 254 |
+
$stored_errors[ $error_code ] = array();
|
| 255 |
+
}
|
| 256 |
+
|
| 257 |
+
$stored_errors[ $error_code ][ $user_id ] = $error_array;
|
| 258 |
+
|
| 259 |
+
// Let's store a maximum of 5 different user ids for each error code.
|
| 260 |
+
if ( count( $stored_errors[ $error_code ] ) > 5 ) {
|
| 261 |
+
// array_shift will destroy keys here because they are numeric, so manually remove first item.
|
| 262 |
+
$keys = array_keys( $stored_errors[ $error_code ] );
|
| 263 |
+
unset( $stored_errors[ $error_code ][ $keys[0] ] );
|
| 264 |
+
}
|
| 265 |
+
|
| 266 |
+
if ( update_option( self::STORED_ERRORS_OPTION, $stored_errors ) ) {
|
| 267 |
+
return $error_array;
|
| 268 |
+
}
|
| 269 |
+
|
| 270 |
+
return false;
|
| 271 |
+
|
| 272 |
+
}
|
| 273 |
+
|
| 274 |
+
/**
|
| 275 |
+
* Converts a WP_Error object in the array representation we store in the database
|
| 276 |
+
*
|
| 277 |
+
* @since 8.7.0
|
| 278 |
+
*
|
| 279 |
+
* @param \WP_Error $error the error object.
|
| 280 |
+
* @return boolean|array False if error is invalid or the error array
|
| 281 |
+
*/
|
| 282 |
+
public function wp_error_to_array( \WP_Error $error ) {
|
| 283 |
+
|
| 284 |
+
$data = $error->get_error_data();
|
| 285 |
+
|
| 286 |
+
if ( ! isset( $data['signature_details'] ) || ! is_array( $data['signature_details'] ) ) {
|
| 287 |
+
return false;
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
$data = $data['signature_details'];
|
| 291 |
+
|
| 292 |
+
if ( ! isset( $data['token'] ) || empty( $data['token'] ) ) {
|
| 293 |
+
return false;
|
| 294 |
+
}
|
| 295 |
+
|
| 296 |
+
$user_id = $this->get_user_id_from_token( $data['token'] );
|
| 297 |
+
|
| 298 |
+
$error_array = array(
|
| 299 |
+
'error_code' => $error->get_error_code(),
|
| 300 |
+
'user_id' => $user_id,
|
| 301 |
+
'error_message' => $error->get_error_message(),
|
| 302 |
+
'error_data' => $data,
|
| 303 |
+
'timestamp' => time(),
|
| 304 |
+
'nonce' => wp_generate_password( 10, false ),
|
| 305 |
+
);
|
| 306 |
+
|
| 307 |
+
if ( $this->track_lost_active_master_user( $error->get_error_code(), $data['token'], $user_id ) ) {
|
| 308 |
+
$error_array['error_message'] = 'Site has a deleted but active master user token';
|
| 309 |
+
}
|
| 310 |
+
|
| 311 |
+
return $error_array;
|
| 312 |
+
|
| 313 |
+
}
|
| 314 |
+
|
| 315 |
+
/**
|
| 316 |
+
* This is been used to track blogs with deleted master user but whose tokens are still actively being used
|
| 317 |
+
*
|
| 318 |
+
* See p9dueE-1GB-p2
|
| 319 |
+
*
|
| 320 |
+
* This tracking should be removed as long as we no longer need, possibly in 8.9
|
| 321 |
+
*
|
| 322 |
+
* @since 8.8.1
|
| 323 |
+
*
|
| 324 |
+
* @param string $error_code The error code.
|
| 325 |
+
* @param string $token The token that triggered the error.
|
| 326 |
+
* @param integer $user_id The user ID used to make the request that triggered the error.
|
| 327 |
+
* @return boolean
|
| 328 |
+
*/
|
| 329 |
+
private function track_lost_active_master_user( $error_code, $token, $user_id ) {
|
| 330 |
+
if ( 'unknown_user' === $error_code ) {
|
| 331 |
+
$manager = new Manager();
|
| 332 |
+
// If the Unknown user is the master user (master user has been deleted).
|
| 333 |
+
if ( $manager->is_missing_connection_owner() && (int) $user_id === (int) $manager->get_connection_owner_id() ) {
|
| 334 |
+
$user_token = $manager->get_access_token( JETPACK_MASTER_USER );
|
| 335 |
+
// If there's still a token stored for the deleted master user.
|
| 336 |
+
if ( $user_token && is_object( $user_token ) && isset( $user_token->secret ) ) {
|
| 337 |
+
$token_parts = explode( ':', wp_unslash( $token ) );
|
| 338 |
+
// If the token stored for the deleted master user matches the token user by wpcom to make the request.
|
| 339 |
+
// This means that requests FROM this site TO wpcom using the JETPACK_MASTER_USER constant are still working.
|
| 340 |
+
if ( isset( $token_parts[0] ) && ! empty( $token_parts[0] ) && false !== strpos( $user_token->secret, $token_parts[0] ) ) {
|
| 341 |
+
return true;
|
| 342 |
+
}
|
| 343 |
+
}
|
| 344 |
+
}
|
| 345 |
+
}
|
| 346 |
+
return false;
|
| 347 |
+
}
|
| 348 |
+
|
| 349 |
+
/**
|
| 350 |
+
* Sends the error to WP.com to be verified
|
| 351 |
+
*
|
| 352 |
+
* @since 8.7.0
|
| 353 |
+
*
|
| 354 |
+
* @param array $error_array The array representation of the error as it is stored in the database.
|
| 355 |
+
* @return bool
|
| 356 |
+
*/
|
| 357 |
+
public function send_error_to_wpcom( $error_array ) {
|
| 358 |
+
|
| 359 |
+
$blog_id = \Jetpack_Options::get_option( 'id' );
|
| 360 |
+
|
| 361 |
+
$encrypted_data = $this->encrypt_data_to_wpcom( $error_array );
|
| 362 |
+
|
| 363 |
+
if ( false === $encrypted_data ) {
|
| 364 |
+
return false;
|
| 365 |
+
}
|
| 366 |
+
|
| 367 |
+
$args = array(
|
| 368 |
+
'body' => array(
|
| 369 |
+
'error_data' => $encrypted_data,
|
| 370 |
+
),
|
| 371 |
+
);
|
| 372 |
+
|
| 373 |
+
// send encrypted data to WP.com Public-API v2.
|
| 374 |
+
wp_remote_post( "https://public-api.wordpress.com/wpcom/v2/sites/{$blog_id}/jetpack-report-error/", $args );
|
| 375 |
+
return true;
|
| 376 |
+
}
|
| 377 |
+
|
| 378 |
+
/**
|
| 379 |
+
* Encrypt data to be sent over to WP.com
|
| 380 |
+
*
|
| 381 |
+
* @since 8.7.0
|
| 382 |
+
*
|
| 383 |
+
* @param array|string $data the data to be encoded.
|
| 384 |
+
* @return boolean|string The encoded string on success, false on failure
|
| 385 |
+
*/
|
| 386 |
+
public function encrypt_data_to_wpcom( $data ) {
|
| 387 |
+
|
| 388 |
+
try {
|
| 389 |
+
// phpcs:disable WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
|
| 390 |
+
// phpcs:disable WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
|
| 391 |
+
$encrypted_data = base64_encode( sodium_crypto_box_seal( wp_json_encode( $data ), base64_decode( JETPACK__ERRORS_PUBLIC_KEY ) ) );
|
| 392 |
+
// phpcs:enable WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
|
| 393 |
+
// phpcs:enable WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
|
| 394 |
+
} catch ( \SodiumException $e ) {
|
| 395 |
+
// error encrypting data.
|
| 396 |
+
return false;
|
| 397 |
+
}
|
| 398 |
+
|
| 399 |
+
return $encrypted_data;
|
| 400 |
+
|
| 401 |
+
}
|
| 402 |
+
|
| 403 |
+
/**
|
| 404 |
+
* Extracts the user ID from a token
|
| 405 |
+
*
|
| 406 |
+
* @since 8.7.0
|
| 407 |
+
*
|
| 408 |
+
* @param string $token the token used to make the xml-rpc request.
|
| 409 |
+
* @return string $the user id or `invalid` if user id not present.
|
| 410 |
+
*/
|
| 411 |
+
public function get_user_id_from_token( $token ) {
|
| 412 |
+
$parsed_token = explode( ':', wp_unslash( $token ) );
|
| 413 |
+
|
| 414 |
+
if ( isset( $parsed_token[2] ) && ! empty( $parsed_token[2] ) && ctype_digit( $parsed_token[2] ) ) {
|
| 415 |
+
$user_id = $parsed_token[2];
|
| 416 |
+
} else {
|
| 417 |
+
$user_id = 'invalid';
|
| 418 |
+
}
|
| 419 |
+
|
| 420 |
+
return $user_id;
|
| 421 |
+
|
| 422 |
+
}
|
| 423 |
+
|
| 424 |
+
/**
|
| 425 |
+
* Gets the reported errors stored in the database
|
| 426 |
+
*
|
| 427 |
+
* @since 8.7.0
|
| 428 |
+
*
|
| 429 |
+
* @return array $errors
|
| 430 |
+
*/
|
| 431 |
+
public function get_stored_errors() {
|
| 432 |
+
|
| 433 |
+
$stored_errors = get_option( self::STORED_ERRORS_OPTION );
|
| 434 |
+
|
| 435 |
+
if ( ! is_array( $stored_errors ) ) {
|
| 436 |
+
$stored_errors = array();
|
| 437 |
+
}
|
| 438 |
+
|
| 439 |
+
$stored_errors = $this->garbage_collector( $stored_errors );
|
| 440 |
+
|
| 441 |
+
return $stored_errors;
|
| 442 |
+
}
|
| 443 |
+
|
| 444 |
+
/**
|
| 445 |
+
* Gets the verified errors stored in the database
|
| 446 |
+
*
|
| 447 |
+
* @since 8.7.0
|
| 448 |
+
*
|
| 449 |
+
* @return array $errors
|
| 450 |
+
*/
|
| 451 |
+
public function get_verified_errors() {
|
| 452 |
+
|
| 453 |
+
$verified_errors = get_option( self::STORED_VERIFIED_ERRORS_OPTION );
|
| 454 |
+
|
| 455 |
+
if ( ! is_array( $verified_errors ) ) {
|
| 456 |
+
$verified_errors = array();
|
| 457 |
+
}
|
| 458 |
+
|
| 459 |
+
$verified_errors = $this->garbage_collector( $verified_errors );
|
| 460 |
+
|
| 461 |
+
return $verified_errors;
|
| 462 |
+
}
|
| 463 |
+
|
| 464 |
+
/**
|
| 465 |
+
* Removes expired errors from the array
|
| 466 |
+
*
|
| 467 |
+
* This method is called by get_stored_errors and get_verified errors and filters their result
|
| 468 |
+
* Whenever a new error is stored to the database or verified, this will be triggered and the
|
| 469 |
+
* expired error will be permantently removed from the database
|
| 470 |
+
*
|
| 471 |
+
* @since 8.7.0
|
| 472 |
+
*
|
| 473 |
+
* @param array $errors array of errors as stored in the database.
|
| 474 |
+
* @return array
|
| 475 |
+
*/
|
| 476 |
+
private function garbage_collector( $errors ) {
|
| 477 |
+
foreach ( $errors as $error_code => $users ) {
|
| 478 |
+
foreach ( $users as $user_id => $error ) {
|
| 479 |
+
if ( self::ERROR_LIFE_TIME < time() - (int) $error['timestamp'] ) {
|
| 480 |
+
unset( $errors[ $error_code ][ $user_id ] );
|
| 481 |
+
}
|
| 482 |
+
}
|
| 483 |
+
}
|
| 484 |
+
// Clear empty error codes.
|
| 485 |
+
$errors = array_filter(
|
| 486 |
+
$errors,
|
| 487 |
+
function( $user_errors ) {
|
| 488 |
+
return ! empty( $user_errors );
|
| 489 |
+
}
|
| 490 |
+
);
|
| 491 |
+
return $errors;
|
| 492 |
+
}
|
| 493 |
+
|
| 494 |
+
/**
|
| 495 |
+
* Delete all stored and verified errors from the database
|
| 496 |
+
*
|
| 497 |
+
* @since 8.7.0
|
| 498 |
+
*
|
| 499 |
+
* @return void
|
| 500 |
+
*/
|
| 501 |
+
public function delete_all_errors() {
|
| 502 |
+
$this->delete_stored_errors();
|
| 503 |
+
$this->delete_verified_errors();
|
| 504 |
+
}
|
| 505 |
+
|
| 506 |
+
/**
|
| 507 |
+
* Delete the reported errors stored in the database
|
| 508 |
+
*
|
| 509 |
+
* @since 8.7.0
|
| 510 |
+
*
|
| 511 |
+
* @return boolean True, if option is successfully deleted. False on failure.
|
| 512 |
+
*/
|
| 513 |
+
public function delete_stored_errors() {
|
| 514 |
+
return delete_option( self::STORED_ERRORS_OPTION );
|
| 515 |
+
}
|
| 516 |
+
|
| 517 |
+
/**
|
| 518 |
+
* Delete the verified errors stored in the database
|
| 519 |
+
*
|
| 520 |
+
* @since 8.7.0
|
| 521 |
+
*
|
| 522 |
+
* @return boolean True, if option is successfully deleted. False on failure.
|
| 523 |
+
*/
|
| 524 |
+
public function delete_verified_errors() {
|
| 525 |
+
return delete_option( self::STORED_VERIFIED_ERRORS_OPTION );
|
| 526 |
+
}
|
| 527 |
+
|
| 528 |
+
/**
|
| 529 |
+
* Gets an error based on the nonce
|
| 530 |
+
*
|
| 531 |
+
* Receives a nonce and finds the related error.
|
| 532 |
+
*
|
| 533 |
+
* @since 8.7.0
|
| 534 |
+
*
|
| 535 |
+
* @param string $nonce The nonce created for the error we want to get.
|
| 536 |
+
* @return null|array Returns the error array representation or null if error not found.
|
| 537 |
+
*/
|
| 538 |
+
public function get_error_by_nonce( $nonce ) {
|
| 539 |
+
$errors = $this->get_stored_errors();
|
| 540 |
+
foreach ( $errors as $user_group ) {
|
| 541 |
+
foreach ( $user_group as $error ) {
|
| 542 |
+
if ( $error['nonce'] === $nonce ) {
|
| 543 |
+
return $error;
|
| 544 |
+
}
|
| 545 |
+
}
|
| 546 |
+
}
|
| 547 |
+
return null;
|
| 548 |
+
}
|
| 549 |
+
|
| 550 |
+
/**
|
| 551 |
+
* Adds an error to the verified error list
|
| 552 |
+
*
|
| 553 |
+
* @since 8.7.0
|
| 554 |
+
*
|
| 555 |
+
* @param array $error The error array, as it was saved in the unverified errors list.
|
| 556 |
+
* @return void
|
| 557 |
+
*/
|
| 558 |
+
public function verify_error( $error ) {
|
| 559 |
+
|
| 560 |
+
$verified_errors = $this->get_verified_errors();
|
| 561 |
+
$error_code = $error['error_code'];
|
| 562 |
+
$user_id = $error['user_id'];
|
| 563 |
+
|
| 564 |
+
if ( ! isset( $verified_errors[ $error_code ] ) ) {
|
| 565 |
+
$verified_errors[ $error_code ] = array();
|
| 566 |
+
}
|
| 567 |
+
|
| 568 |
+
$verified_errors[ $error_code ][ $user_id ] = $error;
|
| 569 |
+
|
| 570 |
+
update_option( self::STORED_VERIFIED_ERRORS_OPTION, $verified_errors );
|
| 571 |
+
|
| 572 |
+
}
|
| 573 |
+
|
| 574 |
+
/**
|
| 575 |
+
* Register REST API end point for error hanlding.
|
| 576 |
+
*
|
| 577 |
+
* @since 8.7.0
|
| 578 |
+
*
|
| 579 |
+
* @return void
|
| 580 |
+
*/
|
| 581 |
+
public function register_verify_error_endpoint() {
|
| 582 |
+
register_rest_route(
|
| 583 |
+
'jetpack/v4',
|
| 584 |
+
'/verify_xmlrpc_error',
|
| 585 |
+
array(
|
| 586 |
+
'methods' => \WP_REST_Server::CREATABLE,
|
| 587 |
+
'callback' => array( $this, 'verify_xml_rpc_error' ),
|
| 588 |
+
'permission_callback' => '__return_true',
|
| 589 |
+
'args' => array(
|
| 590 |
+
'nonce' => array(
|
| 591 |
+
'required' => true,
|
| 592 |
+
'type' => 'string',
|
| 593 |
+
),
|
| 594 |
+
),
|
| 595 |
+
)
|
| 596 |
+
);
|
| 597 |
+
}
|
| 598 |
+
|
| 599 |
+
/**
|
| 600 |
+
* Handles verification that a xml rpc error is legit and came from WordPres.com
|
| 601 |
+
*
|
| 602 |
+
* @since 8.7.0
|
| 603 |
+
*
|
| 604 |
+
* @param \WP_REST_Request $request The request sent to the WP REST API.
|
| 605 |
+
*
|
| 606 |
+
* @return boolean
|
| 607 |
+
*/
|
| 608 |
+
public function verify_xml_rpc_error( \WP_REST_Request $request ) {
|
| 609 |
+
|
| 610 |
+
$error = $this->get_error_by_nonce( $request['nonce'] );
|
| 611 |
+
|
| 612 |
+
if ( $error ) {
|
| 613 |
+
$this->verify_error( $error );
|
| 614 |
+
return new \WP_REST_Response( true, 200 );
|
| 615 |
+
}
|
| 616 |
+
|
| 617 |
+
return new \WP_REST_Response( false, 200 );
|
| 618 |
+
|
| 619 |
+
}
|
| 620 |
+
|
| 621 |
+
}
|
vendor/automattic/jetpack-connection/src/class-manager.php
CHANGED
|
@@ -9,7 +9,9 @@ namespace Automattic\Jetpack\Connection;
|
|
| 9 |
|
| 10 |
use Automattic\Jetpack\Constants;
|
| 11 |
use Automattic\Jetpack\Roles;
|
|
|
|
| 12 |
use Automattic\Jetpack\Tracking;
|
|
|
|
| 13 |
|
| 14 |
/**
|
| 15 |
* The Jetpack Connection Manager class that is used as a single gateway between WordPress.com
|
|
@@ -74,32 +76,35 @@ class Manager {
|
|
| 74 |
public static function configure() {
|
| 75 |
$manager = new self();
|
| 76 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
$manager->setup_xmlrpc_handlers(
|
| 78 |
$_GET, // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
| 79 |
$manager->is_active(),
|
| 80 |
$manager->verify_xml_rpc_signature()
|
| 81 |
);
|
| 82 |
|
|
|
|
|
|
|
| 83 |
if ( $manager->is_active() ) {
|
| 84 |
add_filter( 'xmlrpc_methods', array( $manager, 'public_xmlrpc_methods' ) );
|
| 85 |
-
} else {
|
| 86 |
-
add_action( 'rest_api_init', array( $manager, 'initialize_rest_api_registration_connector' ) );
|
| 87 |
}
|
| 88 |
|
|
|
|
|
|
|
| 89 |
add_action( 'jetpack_clean_nonces', array( $manager, 'clean_nonces' ) );
|
| 90 |
if ( ! wp_next_scheduled( 'jetpack_clean_nonces' ) ) {
|
| 91 |
wp_schedule_event( time(), 'hourly', 'jetpack_clean_nonces' );
|
| 92 |
}
|
| 93 |
|
| 94 |
-
add_filter(
|
| 95 |
-
'jetpack_constant_default_value',
|
| 96 |
-
__NAMESPACE__ . '\Utils::jetpack_api_constant_filter',
|
| 97 |
-
10,
|
| 98 |
-
2
|
| 99 |
-
);
|
| 100 |
-
|
| 101 |
add_action( 'plugins_loaded', __NAMESPACE__ . '\Plugin_Storage::configure', 100 );
|
| 102 |
|
|
|
|
| 103 |
}
|
| 104 |
|
| 105 |
/**
|
|
@@ -279,7 +284,7 @@ class Manager {
|
|
| 279 |
* @param String $password password string.
|
| 280 |
* @return WP_User|Mixed authenticated user or error.
|
| 281 |
*/
|
| 282 |
-
public function authenticate_jetpack( $user, $username, $password ) {
|
| 283 |
if ( is_a( $user, '\\WP_User' ) ) {
|
| 284 |
return $user;
|
| 285 |
}
|
|
@@ -316,19 +321,14 @@ class Manager {
|
|
| 316 |
/**
|
| 317 |
* Action for logging XMLRPC signature verification errors. This data is sensitive.
|
| 318 |
*
|
| 319 |
-
* Error codes:
|
| 320 |
-
* - malformed_token
|
| 321 |
-
* - malformed_user_id
|
| 322 |
-
* - unknown_token
|
| 323 |
-
* - could_not_sign
|
| 324 |
-
* - invalid_nonce
|
| 325 |
-
* - signature_mismatch
|
| 326 |
-
*
|
| 327 |
* @since 7.5.0
|
| 328 |
*
|
| 329 |
* @param WP_Error $signature_verification_error The verification error
|
| 330 |
*/
|
| 331 |
do_action( 'jetpack_verify_signature_error', $this->xmlrpc_verification );
|
|
|
|
|
|
|
|
|
|
| 332 |
}
|
| 333 |
}
|
| 334 |
|
|
@@ -519,9 +519,9 @@ class Manager {
|
|
| 519 |
* @return bool
|
| 520 |
*/
|
| 521 |
public function is_registered() {
|
| 522 |
-
$
|
| 523 |
-
$
|
| 524 |
-
return $
|
| 525 |
}
|
| 526 |
|
| 527 |
/**
|
|
@@ -728,6 +728,10 @@ class Manager {
|
|
| 728 |
|
| 729 |
\Jetpack_Options::update_option( 'user_tokens', $tokens );
|
| 730 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 731 |
/**
|
| 732 |
* Fires after the current user has been unlinked from WordPress.com.
|
| 733 |
*
|
|
@@ -804,7 +808,7 @@ class Manager {
|
|
| 804 |
* WordPress.com.
|
| 805 |
*
|
| 806 |
* @param String $api_endpoint (optional) an API endpoint to use, defaults to 'register'.
|
| 807 |
-
* @return
|
| 808 |
*/
|
| 809 |
public function register( $api_endpoint = 'register' ) {
|
| 810 |
add_action( 'pre_update_jetpack_option_register', array( '\\Jetpack_Options', 'delete_option' ) );
|
|
@@ -843,20 +847,21 @@ class Manager {
|
|
| 843 |
$body = apply_filters(
|
| 844 |
'jetpack_register_request_body',
|
| 845 |
array(
|
| 846 |
-
'siteurl'
|
| 847 |
-
'home'
|
| 848 |
-
'gmt_offset'
|
| 849 |
-
'timezone_string'
|
| 850 |
-
'site_name'
|
| 851 |
-
'secret_1'
|
| 852 |
-
'secret_2'
|
| 853 |
-
'site_lang'
|
| 854 |
-
'timeout'
|
| 855 |
-
'stats_id'
|
| 856 |
-
'state'
|
| 857 |
-
'site_created'
|
| 858 |
-
'jetpack_version'
|
| 859 |
-
'ABSPATH'
|
|
|
|
| 860 |
)
|
| 861 |
);
|
| 862 |
|
|
@@ -950,7 +955,7 @@ class Manager {
|
|
| 950 |
* @since 2.6
|
| 951 |
*
|
| 952 |
* @param Mixed $response the response object, or the error object.
|
| 953 |
-
* @return string|WP_Error A JSON object on success or
|
| 954 |
**/
|
| 955 |
protected function validate_remote_register_response( $response ) {
|
| 956 |
if ( is_wp_error( $response ) ) {
|
|
@@ -1097,6 +1102,46 @@ class Manager {
|
|
| 1097 |
}
|
| 1098 |
}
|
| 1099 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1100 |
/**
|
| 1101 |
* Builds the timeout limit for queries talking with the wpcom servers.
|
| 1102 |
*
|
|
@@ -1319,8 +1364,30 @@ class Manager {
|
|
| 1319 |
|
| 1320 |
/**
|
| 1321 |
* Deletes all connection tokens and transients from the local Jetpack site.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1322 |
*/
|
| 1323 |
-
public function delete_all_connection_tokens() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1324 |
\Jetpack_Options::delete_option(
|
| 1325 |
array(
|
| 1326 |
'blog_token',
|
|
@@ -1337,14 +1404,74 @@ class Manager {
|
|
| 1337 |
// Delete cached connected user data.
|
| 1338 |
$transient_key = 'jetpack_connected_user_data_' . get_current_user_id();
|
| 1339 |
delete_transient( $transient_key );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1340 |
}
|
| 1341 |
|
| 1342 |
/**
|
| 1343 |
* Tells WordPress.com to disconnect the site and clear all tokens from cached site.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1344 |
*/
|
| 1345 |
-
public function disconnect_site_wpcom() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1346 |
$xml = new \Jetpack_IXR_Client();
|
| 1347 |
$xml->query( 'jetpack.deregister', get_current_user_id() );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1348 |
}
|
| 1349 |
|
| 1350 |
/**
|
|
@@ -2025,23 +2152,26 @@ class Manager {
|
|
| 2025 |
|
| 2026 |
if ( $user_id ) {
|
| 2027 |
if ( ! $user_tokens ) {
|
| 2028 |
-
return $suppress_errors ? false : new \WP_Error( 'no_user_tokens' );
|
| 2029 |
}
|
| 2030 |
if ( self::JETPACK_MASTER_USER === $user_id ) {
|
| 2031 |
$user_id = \Jetpack_Options::get_option( 'master_user' );
|
| 2032 |
if ( ! $user_id ) {
|
| 2033 |
-
return $suppress_errors ? false : new \WP_Error( 'empty_master_user_option' );
|
| 2034 |
}
|
| 2035 |
}
|
| 2036 |
if ( ! isset( $user_tokens[ $user_id ] ) || ! $user_tokens[ $user_id ] ) {
|
| 2037 |
-
|
|
|
|
| 2038 |
}
|
| 2039 |
$user_token_chunks = explode( '.', $user_tokens[ $user_id ] );
|
| 2040 |
if ( empty( $user_token_chunks[1] ) || empty( $user_token_chunks[2] ) ) {
|
| 2041 |
-
|
|
|
|
| 2042 |
}
|
| 2043 |
if ( $user_token_chunks[2] !== (string) $user_id ) {
|
| 2044 |
-
|
|
|
|
| 2045 |
}
|
| 2046 |
$possible_normal_tokens[] = "{$user_token_chunks[0]}.{$user_token_chunks[1]}";
|
| 2047 |
} else {
|
|
@@ -2071,7 +2201,8 @@ class Manager {
|
|
| 2071 |
}
|
| 2072 |
|
| 2073 |
if ( ! $possible_tokens ) {
|
| 2074 |
-
|
|
|
|
| 2075 |
}
|
| 2076 |
|
| 2077 |
$valid_token = false;
|
|
@@ -2096,7 +2227,12 @@ class Manager {
|
|
| 2096 |
}
|
| 2097 |
|
| 2098 |
if ( ! $valid_token ) {
|
| 2099 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2100 |
}
|
| 2101 |
|
| 2102 |
return (object) array(
|
|
@@ -2268,12 +2404,64 @@ class Manager {
|
|
| 2268 |
}
|
| 2269 |
|
| 2270 |
/**
|
| 2271 |
-
* Get all connected plugins information.
|
|
|
|
|
|
|
|
|
|
| 2272 |
*
|
| 2273 |
-
* @return array
|
| 2274 |
*/
|
| 2275 |
public function get_connected_plugins() {
|
| 2276 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2277 |
}
|
| 2278 |
|
| 2279 |
}
|
| 9 |
|
| 10 |
use Automattic\Jetpack\Constants;
|
| 11 |
use Automattic\Jetpack\Roles;
|
| 12 |
+
use Automattic\Jetpack\Status;
|
| 13 |
use Automattic\Jetpack\Tracking;
|
| 14 |
+
use WP_Error;
|
| 15 |
|
| 16 |
/**
|
| 17 |
* The Jetpack Connection Manager class that is used as a single gateway between WordPress.com
|
| 76 |
public static function configure() {
|
| 77 |
$manager = new self();
|
| 78 |
|
| 79 |
+
add_filter(
|
| 80 |
+
'jetpack_constant_default_value',
|
| 81 |
+
__NAMESPACE__ . '\Utils::jetpack_api_constant_filter',
|
| 82 |
+
10,
|
| 83 |
+
2
|
| 84 |
+
);
|
| 85 |
+
|
| 86 |
$manager->setup_xmlrpc_handlers(
|
| 87 |
$_GET, // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
| 88 |
$manager->is_active(),
|
| 89 |
$manager->verify_xml_rpc_signature()
|
| 90 |
);
|
| 91 |
|
| 92 |
+
$manager->error_handler = Error_Handler::get_instance();
|
| 93 |
+
|
| 94 |
if ( $manager->is_active() ) {
|
| 95 |
add_filter( 'xmlrpc_methods', array( $manager, 'public_xmlrpc_methods' ) );
|
|
|
|
|
|
|
| 96 |
}
|
| 97 |
|
| 98 |
+
add_action( 'rest_api_init', array( $manager, 'initialize_rest_api_registration_connector' ) );
|
| 99 |
+
|
| 100 |
add_action( 'jetpack_clean_nonces', array( $manager, 'clean_nonces' ) );
|
| 101 |
if ( ! wp_next_scheduled( 'jetpack_clean_nonces' ) ) {
|
| 102 |
wp_schedule_event( time(), 'hourly', 'jetpack_clean_nonces' );
|
| 103 |
}
|
| 104 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 105 |
add_action( 'plugins_loaded', __NAMESPACE__ . '\Plugin_Storage::configure', 100 );
|
| 106 |
|
| 107 |
+
add_filter( 'map_meta_cap', array( $manager, 'jetpack_connection_custom_caps' ), 1, 4 );
|
| 108 |
}
|
| 109 |
|
| 110 |
/**
|
| 284 |
* @param String $password password string.
|
| 285 |
* @return WP_User|Mixed authenticated user or error.
|
| 286 |
*/
|
| 287 |
+
public function authenticate_jetpack( $user, $username, $password ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
|
| 288 |
if ( is_a( $user, '\\WP_User' ) ) {
|
| 289 |
return $user;
|
| 290 |
}
|
| 321 |
/**
|
| 322 |
* Action for logging XMLRPC signature verification errors. This data is sensitive.
|
| 323 |
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 324 |
* @since 7.5.0
|
| 325 |
*
|
| 326 |
* @param WP_Error $signature_verification_error The verification error
|
| 327 |
*/
|
| 328 |
do_action( 'jetpack_verify_signature_error', $this->xmlrpc_verification );
|
| 329 |
+
|
| 330 |
+
Error_Handler::get_instance()->report_error( $this->xmlrpc_verification );
|
| 331 |
+
|
| 332 |
}
|
| 333 |
}
|
| 334 |
|
| 519 |
* @return bool
|
| 520 |
*/
|
| 521 |
public function is_registered() {
|
| 522 |
+
$has_blog_id = (bool) \Jetpack_Options::get_option( 'id' );
|
| 523 |
+
$has_blog_token = (bool) $this->get_access_token( false );
|
| 524 |
+
return $has_blog_id && $has_blog_token;
|
| 525 |
}
|
| 526 |
|
| 527 |
/**
|
| 728 |
|
| 729 |
\Jetpack_Options::update_option( 'user_tokens', $tokens );
|
| 730 |
|
| 731 |
+
// Delete cached connected user data.
|
| 732 |
+
$transient_key = "jetpack_connected_user_data_$user_id";
|
| 733 |
+
delete_transient( $transient_key );
|
| 734 |
+
|
| 735 |
/**
|
| 736 |
* Fires after the current user has been unlinked from WordPress.com.
|
| 737 |
*
|
| 808 |
* WordPress.com.
|
| 809 |
*
|
| 810 |
* @param String $api_endpoint (optional) an API endpoint to use, defaults to 'register'.
|
| 811 |
+
* @return true|WP_Error The error object.
|
| 812 |
*/
|
| 813 |
public function register( $api_endpoint = 'register' ) {
|
| 814 |
add_action( 'pre_update_jetpack_option_register', array( '\\Jetpack_Options', 'delete_option' ) );
|
| 847 |
$body = apply_filters(
|
| 848 |
'jetpack_register_request_body',
|
| 849 |
array(
|
| 850 |
+
'siteurl' => site_url(),
|
| 851 |
+
'home' => home_url(),
|
| 852 |
+
'gmt_offset' => $gmt_offset,
|
| 853 |
+
'timezone_string' => (string) get_option( 'timezone_string' ),
|
| 854 |
+
'site_name' => (string) get_option( 'blogname' ),
|
| 855 |
+
'secret_1' => $secrets['secret_1'],
|
| 856 |
+
'secret_2' => $secrets['secret_2'],
|
| 857 |
+
'site_lang' => get_locale(),
|
| 858 |
+
'timeout' => $timeout,
|
| 859 |
+
'stats_id' => $stats_id,
|
| 860 |
+
'state' => get_current_user_id(),
|
| 861 |
+
'site_created' => $this->get_assumed_site_creation_date(),
|
| 862 |
+
'jetpack_version' => Constants::get_constant( 'JETPACK__VERSION' ),
|
| 863 |
+
'ABSPATH' => Constants::get_constant( 'ABSPATH' ),
|
| 864 |
+
'current_user_email' => wp_get_current_user()->user_email,
|
| 865 |
)
|
| 866 |
);
|
| 867 |
|
| 955 |
* @since 2.6
|
| 956 |
*
|
| 957 |
* @param Mixed $response the response object, or the error object.
|
| 958 |
+
* @return string|WP_Error A JSON object on success or WP_Error on failures
|
| 959 |
**/
|
| 960 |
protected function validate_remote_register_response( $response ) {
|
| 961 |
if ( is_wp_error( $response ) ) {
|
| 1102 |
}
|
| 1103 |
}
|
| 1104 |
|
| 1105 |
+
/**
|
| 1106 |
+
* Sets the Connection custom capabilities.
|
| 1107 |
+
*
|
| 1108 |
+
* @param string[] $caps Array of the user's capabilities.
|
| 1109 |
+
* @param string $cap Capability name.
|
| 1110 |
+
* @param int $user_id The user ID.
|
| 1111 |
+
* @param array $args Adds the context to the cap. Typically the object ID.
|
| 1112 |
+
*/
|
| 1113 |
+
public function jetpack_connection_custom_caps( $caps, $cap, $user_id, $args ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
|
| 1114 |
+
$is_offline_mode = ( new Status() )->is_offline_mode();
|
| 1115 |
+
switch ( $cap ) {
|
| 1116 |
+
case 'jetpack_connect':
|
| 1117 |
+
case 'jetpack_reconnect':
|
| 1118 |
+
if ( $is_offline_mode ) {
|
| 1119 |
+
$caps = array( 'do_not_allow' );
|
| 1120 |
+
break;
|
| 1121 |
+
}
|
| 1122 |
+
// Pass through. If it's not offline mode, these should match disconnect.
|
| 1123 |
+
// Let users disconnect if it's offline mode, just in case things glitch.
|
| 1124 |
+
case 'jetpack_disconnect':
|
| 1125 |
+
/**
|
| 1126 |
+
* Filters the jetpack_disconnect capability.
|
| 1127 |
+
*
|
| 1128 |
+
* @since 8.7.0
|
| 1129 |
+
*
|
| 1130 |
+
* @param array An array containing the capability name.
|
| 1131 |
+
*/
|
| 1132 |
+
$caps = apply_filters( 'jetpack_disconnect_cap', array( 'manage_options' ) );
|
| 1133 |
+
break;
|
| 1134 |
+
case 'jetpack_connect_user':
|
| 1135 |
+
if ( $is_offline_mode ) {
|
| 1136 |
+
$caps = array( 'do_not_allow' );
|
| 1137 |
+
break;
|
| 1138 |
+
}
|
| 1139 |
+
$caps = array( 'read' );
|
| 1140 |
+
break;
|
| 1141 |
+
}
|
| 1142 |
+
return $caps;
|
| 1143 |
+
}
|
| 1144 |
+
|
| 1145 |
/**
|
| 1146 |
* Builds the timeout limit for queries talking with the wpcom servers.
|
| 1147 |
*
|
| 1364 |
|
| 1365 |
/**
|
| 1366 |
* Deletes all connection tokens and transients from the local Jetpack site.
|
| 1367 |
+
* If the plugin object has been provided in the constructor, the function first checks
|
| 1368 |
+
* whether it's the only active connection.
|
| 1369 |
+
* If there are any other connections, the function will do nothing and return `false`
|
| 1370 |
+
* (unless `$ignore_connected_plugins` is set to `true`).
|
| 1371 |
+
*
|
| 1372 |
+
* @param bool $ignore_connected_plugins Delete the tokens even if there are other connected plugins.
|
| 1373 |
+
*
|
| 1374 |
+
* @return bool True if disconnected successfully, false otherwise.
|
| 1375 |
*/
|
| 1376 |
+
public function delete_all_connection_tokens( $ignore_connected_plugins = false ) {
|
| 1377 |
+
if ( ! $ignore_connected_plugins && null !== $this->plugin && ! $this->plugin->is_only() ) {
|
| 1378 |
+
return false;
|
| 1379 |
+
}
|
| 1380 |
+
|
| 1381 |
+
/**
|
| 1382 |
+
* Fires upon the disconnect attempt.
|
| 1383 |
+
* Return `false` to prevent the disconnect.
|
| 1384 |
+
*
|
| 1385 |
+
* @since 8.7.0
|
| 1386 |
+
*/
|
| 1387 |
+
if ( ! apply_filters( 'jetpack_connection_delete_all_tokens', true, $this ) ) {
|
| 1388 |
+
return false;
|
| 1389 |
+
}
|
| 1390 |
+
|
| 1391 |
\Jetpack_Options::delete_option(
|
| 1392 |
array(
|
| 1393 |
'blog_token',
|
| 1404 |
// Delete cached connected user data.
|
| 1405 |
$transient_key = 'jetpack_connected_user_data_' . get_current_user_id();
|
| 1406 |
delete_transient( $transient_key );
|
| 1407 |
+
|
| 1408 |
+
// Delete all XML-RPC errors.
|
| 1409 |
+
Error_Handler::get_instance()->delete_all_errors();
|
| 1410 |
+
|
| 1411 |
+
return true;
|
| 1412 |
}
|
| 1413 |
|
| 1414 |
/**
|
| 1415 |
* Tells WordPress.com to disconnect the site and clear all tokens from cached site.
|
| 1416 |
+
* If the plugin object has been provided in the constructor, the function first check
|
| 1417 |
+
* whether it's the only active connection.
|
| 1418 |
+
* If there are any other connections, the function will do nothing and return `false`
|
| 1419 |
+
* (unless `$ignore_connected_plugins` is set to `true`).
|
| 1420 |
+
*
|
| 1421 |
+
* @param bool $ignore_connected_plugins Delete the tokens even if there are other connected plugins.
|
| 1422 |
+
*
|
| 1423 |
+
* @return bool True if disconnected successfully, false otherwise.
|
| 1424 |
*/
|
| 1425 |
+
public function disconnect_site_wpcom( $ignore_connected_plugins = false ) {
|
| 1426 |
+
if ( ! $ignore_connected_plugins && null !== $this->plugin && ! $this->plugin->is_only() ) {
|
| 1427 |
+
return false;
|
| 1428 |
+
}
|
| 1429 |
+
|
| 1430 |
+
/**
|
| 1431 |
+
* Fires upon the disconnect attempt.
|
| 1432 |
+
* Return `false` to prevent the disconnect.
|
| 1433 |
+
*
|
| 1434 |
+
* @since 8.7.0
|
| 1435 |
+
*/
|
| 1436 |
+
if ( ! apply_filters( 'jetpack_connection_disconnect_site_wpcom', true, $this ) ) {
|
| 1437 |
+
return false;
|
| 1438 |
+
}
|
| 1439 |
+
|
| 1440 |
$xml = new \Jetpack_IXR_Client();
|
| 1441 |
$xml->query( 'jetpack.deregister', get_current_user_id() );
|
| 1442 |
+
|
| 1443 |
+
return true;
|
| 1444 |
+
}
|
| 1445 |
+
|
| 1446 |
+
/**
|
| 1447 |
+
* Disconnect the plugin and remove the tokens.
|
| 1448 |
+
* This function will automatically perform "soft" or "hard" disconnect depending on whether other plugins are using the connection.
|
| 1449 |
+
* This is a proxy method to simplify the Connection package API.
|
| 1450 |
+
*
|
| 1451 |
+
* @see Manager::disable_plugin()
|
| 1452 |
+
* @see Manager::disconnect_site_wpcom()
|
| 1453 |
+
* @see Manager::delete_all_connection_tokens()
|
| 1454 |
+
*
|
| 1455 |
+
* @return bool
|
| 1456 |
+
*/
|
| 1457 |
+
public function remove_connection() {
|
| 1458 |
+
$this->disable_plugin();
|
| 1459 |
+
$this->disconnect_site_wpcom();
|
| 1460 |
+
$this->delete_all_connection_tokens();
|
| 1461 |
+
|
| 1462 |
+
return true;
|
| 1463 |
+
}
|
| 1464 |
+
|
| 1465 |
+
/**
|
| 1466 |
+
* Completely clearing up the connection, and initiating reconnect.
|
| 1467 |
+
*
|
| 1468 |
+
* @return true|WP_Error True if reconnected successfully, a `WP_Error` object otherwise.
|
| 1469 |
+
*/
|
| 1470 |
+
public function reconnect() {
|
| 1471 |
+
$this->disconnect_site_wpcom( true );
|
| 1472 |
+
$this->delete_all_connection_tokens( true );
|
| 1473 |
+
|
| 1474 |
+
return $this->register();
|
| 1475 |
}
|
| 1476 |
|
| 1477 |
/**
|
| 2152 |
|
| 2153 |
if ( $user_id ) {
|
| 2154 |
if ( ! $user_tokens ) {
|
| 2155 |
+
return $suppress_errors ? false : new \WP_Error( 'no_user_tokens', __( 'No user tokens found', 'jetpack' ) );
|
| 2156 |
}
|
| 2157 |
if ( self::JETPACK_MASTER_USER === $user_id ) {
|
| 2158 |
$user_id = \Jetpack_Options::get_option( 'master_user' );
|
| 2159 |
if ( ! $user_id ) {
|
| 2160 |
+
return $suppress_errors ? false : new \WP_Error( 'empty_master_user_option', __( 'No primary user defined', 'jetpack' ) );
|
| 2161 |
}
|
| 2162 |
}
|
| 2163 |
if ( ! isset( $user_tokens[ $user_id ] ) || ! $user_tokens[ $user_id ] ) {
|
| 2164 |
+
// translators: %s is the user ID.
|
| 2165 |
+
return $suppress_errors ? false : new \WP_Error( 'no_token_for_user', sprintf( __( 'No token for user %d', 'jetpack' ), $user_id ) );
|
| 2166 |
}
|
| 2167 |
$user_token_chunks = explode( '.', $user_tokens[ $user_id ] );
|
| 2168 |
if ( empty( $user_token_chunks[1] ) || empty( $user_token_chunks[2] ) ) {
|
| 2169 |
+
// translators: %s is the user ID.
|
| 2170 |
+
return $suppress_errors ? false : new \WP_Error( 'token_malformed', sprintf( __( 'Token for user %d is malformed', 'jetpack' ), $user_id ) );
|
| 2171 |
}
|
| 2172 |
if ( $user_token_chunks[2] !== (string) $user_id ) {
|
| 2173 |
+
// translators: %1$d is the ID of the requested user. %2$d is the user ID found in the token.
|
| 2174 |
+
return $suppress_errors ? false : new \WP_Error( 'user_id_mismatch', sprintf( __( 'Requesting user_id %1$d does not match token user_id %2$d', 'jetpack' ), $user_id, $user_token_chunks[2] ) );
|
| 2175 |
}
|
| 2176 |
$possible_normal_tokens[] = "{$user_token_chunks[0]}.{$user_token_chunks[1]}";
|
| 2177 |
} else {
|
| 2201 |
}
|
| 2202 |
|
| 2203 |
if ( ! $possible_tokens ) {
|
| 2204 |
+
// If no user tokens were found, it would have failed earlier, so this is about blog token.
|
| 2205 |
+
return $suppress_errors ? false : new \WP_Error( 'no_possible_tokens', __( 'No blog token found', 'jetpack' ) );
|
| 2206 |
}
|
| 2207 |
|
| 2208 |
$valid_token = false;
|
| 2227 |
}
|
| 2228 |
|
| 2229 |
if ( ! $valid_token ) {
|
| 2230 |
+
if ( $user_id ) {
|
| 2231 |
+
// translators: %d is the user ID.
|
| 2232 |
+
return $suppress_errors ? false : new \WP_Error( 'no_valid_token', sprintf( __( 'Invalid token for user %d', 'jetpack' ), $user_id ) );
|
| 2233 |
+
} else {
|
| 2234 |
+
return $suppress_errors ? false : new \WP_Error( 'no_valid_token', __( 'Invalid blog token', 'jetpack' ) );
|
| 2235 |
+
}
|
| 2236 |
}
|
| 2237 |
|
| 2238 |
return (object) array(
|
| 2404 |
}
|
| 2405 |
|
| 2406 |
/**
|
| 2407 |
+
* Get all connected plugins information, excluding those disconnected by user.
|
| 2408 |
+
* WARNING: the method cannot be called until Plugin_Storage::configure is called, which happens on plugins_loaded
|
| 2409 |
+
* Even if you don't use Jetpack Config, it may be introduced later by other plugins,
|
| 2410 |
+
* so please make sure not to run the method too early in the code.
|
| 2411 |
*
|
| 2412 |
+
* @return array|WP_Error
|
| 2413 |
*/
|
| 2414 |
public function get_connected_plugins() {
|
| 2415 |
+
$maybe_plugins = Plugin_Storage::get_all( true );
|
| 2416 |
+
|
| 2417 |
+
if ( $maybe_plugins instanceof WP_Error ) {
|
| 2418 |
+
return $maybe_plugins;
|
| 2419 |
+
}
|
| 2420 |
+
|
| 2421 |
+
return $maybe_plugins;
|
| 2422 |
+
}
|
| 2423 |
+
|
| 2424 |
+
/**
|
| 2425 |
+
* Force plugin disconnect. After its called, the plugin will not be allowed to use the connection.
|
| 2426 |
+
* Note: this method does not remove any access tokens.
|
| 2427 |
+
*
|
| 2428 |
+
* @return bool
|
| 2429 |
+
*/
|
| 2430 |
+
public function disable_plugin() {
|
| 2431 |
+
if ( ! $this->plugin ) {
|
| 2432 |
+
return false;
|
| 2433 |
+
}
|
| 2434 |
+
|
| 2435 |
+
return $this->plugin->disable();
|
| 2436 |
+
}
|
| 2437 |
+
|
| 2438 |
+
/**
|
| 2439 |
+
* Force plugin reconnect after user-initiated disconnect.
|
| 2440 |
+
* After its called, the plugin will be allowed to use the connection again.
|
| 2441 |
+
* Note: this method does not initialize access tokens.
|
| 2442 |
+
*
|
| 2443 |
+
* @return bool
|
| 2444 |
+
*/
|
| 2445 |
+
public function enable_plugin() {
|
| 2446 |
+
if ( ! $this->plugin ) {
|
| 2447 |
+
return false;
|
| 2448 |
+
}
|
| 2449 |
+
|
| 2450 |
+
return $this->plugin->enable();
|
| 2451 |
+
}
|
| 2452 |
+
|
| 2453 |
+
/**
|
| 2454 |
+
* Whether the plugin is allowed to use the connection, or it's been disconnected by user.
|
| 2455 |
+
* If no plugin slug was passed into the constructor, always returns true.
|
| 2456 |
+
*
|
| 2457 |
+
* @return bool
|
| 2458 |
+
*/
|
| 2459 |
+
public function is_plugin_enabled() {
|
| 2460 |
+
if ( ! $this->plugin ) {
|
| 2461 |
+
return true;
|
| 2462 |
+
}
|
| 2463 |
+
|
| 2464 |
+
return $this->plugin->is_enabled();
|
| 2465 |
}
|
| 2466 |
|
| 2467 |
}
|
vendor/automattic/jetpack-connection/src/class-plugin-storage.php
CHANGED
|
@@ -7,20 +7,17 @@
|
|
| 7 |
|
| 8 |
namespace Automattic\Jetpack\Connection;
|
| 9 |
|
| 10 |
-
use Automattic\Jetpack\Config;
|
| 11 |
use WP_Error;
|
| 12 |
|
| 13 |
/**
|
| 14 |
-
* The class serves a single purpose - to store the data
|
| 15 |
-
* Well, we don't really store all that. The information is provided on runtime,
|
| 16 |
-
* so all we need to do is to save the data into the class property and retrieve it from there on demand.
|
| 17 |
-
*
|
| 18 |
-
* @todo Adapt for multisite installations.
|
| 19 |
*/
|
| 20 |
class Plugin_Storage {
|
| 21 |
|
| 22 |
const ACTIVE_PLUGINS_OPTION_NAME = 'jetpack_connection_active_plugins';
|
| 23 |
|
|
|
|
|
|
|
| 24 |
/**
|
| 25 |
* Whether this class was configured for the first time or not.
|
| 26 |
*
|
|
@@ -42,14 +39,6 @@ class Plugin_Storage {
|
|
| 42 |
*/
|
| 43 |
private static $plugins = array();
|
| 44 |
|
| 45 |
-
/**
|
| 46 |
-
* Whether the plugins were configured.
|
| 47 |
-
* To make sure we don't call the configuration process again and again.
|
| 48 |
-
*
|
| 49 |
-
* @var bool
|
| 50 |
-
*/
|
| 51 |
-
private static $plugins_configuration_finished = false;
|
| 52 |
-
|
| 53 |
/**
|
| 54 |
* Add or update the plugin information in the storage.
|
| 55 |
*
|
|
@@ -62,7 +51,7 @@ class Plugin_Storage {
|
|
| 62 |
self::$plugins[ $slug ] = $args;
|
| 63 |
|
| 64 |
// if plugin is not in the list of active plugins, refresh the list.
|
| 65 |
-
if ( ! array_key_exists( $slug, get_option( self::ACTIVE_PLUGINS_OPTION_NAME, array() ) ) ) {
|
| 66 |
self::$refresh_connected_plugins = true;
|
| 67 |
}
|
| 68 |
|
|
@@ -95,16 +84,18 @@ class Plugin_Storage {
|
|
| 95 |
* Even if you don't use Jetpack Config, it may be introduced later by other plugins,
|
| 96 |
* so please make sure not to run the method too early in the code.
|
| 97 |
*
|
|
|
|
|
|
|
| 98 |
* @return array|WP_Error
|
| 99 |
*/
|
| 100 |
-
public static function get_all() {
|
| 101 |
$maybe_error = self::ensure_configured();
|
| 102 |
|
| 103 |
if ( $maybe_error instanceof WP_Error ) {
|
| 104 |
return $maybe_error;
|
| 105 |
}
|
| 106 |
|
| 107 |
-
return self::$plugins;
|
| 108 |
}
|
| 109 |
|
| 110 |
/**
|
|
@@ -156,7 +147,7 @@ class Plugin_Storage {
|
|
| 156 |
}
|
| 157 |
|
| 158 |
// If a plugin was activated or deactivated.
|
| 159 |
-
$number_of_plugins_differ = count( self::$plugins ) !== count( get_option( self::ACTIVE_PLUGINS_OPTION_NAME, array() ) );
|
| 160 |
|
| 161 |
if ( $number_of_plugins_differ || true === self::$refresh_connected_plugins ) {
|
| 162 |
self::update_active_plugins_option();
|
|
@@ -176,4 +167,50 @@ class Plugin_Storage {
|
|
| 176 |
update_option( self::ACTIVE_PLUGINS_OPTION_NAME, self::$plugins );
|
| 177 |
}
|
| 178 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 179 |
}
|
| 7 |
|
| 8 |
namespace Automattic\Jetpack\Connection;
|
| 9 |
|
|
|
|
| 10 |
use WP_Error;
|
| 11 |
|
| 12 |
/**
|
| 13 |
+
* The class serves a single purpose - to store the data which plugins use the connection, along with some auxiliary information.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
*/
|
| 15 |
class Plugin_Storage {
|
| 16 |
|
| 17 |
const ACTIVE_PLUGINS_OPTION_NAME = 'jetpack_connection_active_plugins';
|
| 18 |
|
| 19 |
+
const PLUGINS_DISABLED_OPTION_NAME = 'jetpack_connection_disabled_plugins';
|
| 20 |
+
|
| 21 |
/**
|
| 22 |
* Whether this class was configured for the first time or not.
|
| 23 |
*
|
| 39 |
*/
|
| 40 |
private static $plugins = array();
|
| 41 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 42 |
/**
|
| 43 |
* Add or update the plugin information in the storage.
|
| 44 |
*
|
| 51 |
self::$plugins[ $slug ] = $args;
|
| 52 |
|
| 53 |
// if plugin is not in the list of active plugins, refresh the list.
|
| 54 |
+
if ( ! array_key_exists( $slug, (array) get_option( self::ACTIVE_PLUGINS_OPTION_NAME, array() ) ) ) {
|
| 55 |
self::$refresh_connected_plugins = true;
|
| 56 |
}
|
| 57 |
|
| 84 |
* Even if you don't use Jetpack Config, it may be introduced later by other plugins,
|
| 85 |
* so please make sure not to run the method too early in the code.
|
| 86 |
*
|
| 87 |
+
* @param bool $connected_only Exclude plugins that were explicitly disconnected.
|
| 88 |
+
*
|
| 89 |
* @return array|WP_Error
|
| 90 |
*/
|
| 91 |
+
public static function get_all( $connected_only = false ) {
|
| 92 |
$maybe_error = self::ensure_configured();
|
| 93 |
|
| 94 |
if ( $maybe_error instanceof WP_Error ) {
|
| 95 |
return $maybe_error;
|
| 96 |
}
|
| 97 |
|
| 98 |
+
return $connected_only ? array_diff_key( self::$plugins, array_flip( self::get_all_disabled_plugins() ) ) : self::$plugins;
|
| 99 |
}
|
| 100 |
|
| 101 |
/**
|
| 147 |
}
|
| 148 |
|
| 149 |
// If a plugin was activated or deactivated.
|
| 150 |
+
$number_of_plugins_differ = count( self::$plugins ) !== count( (array) get_option( self::ACTIVE_PLUGINS_OPTION_NAME, array() ) );
|
| 151 |
|
| 152 |
if ( $number_of_plugins_differ || true === self::$refresh_connected_plugins ) {
|
| 153 |
self::update_active_plugins_option();
|
| 167 |
update_option( self::ACTIVE_PLUGINS_OPTION_NAME, self::$plugins );
|
| 168 |
}
|
| 169 |
|
| 170 |
+
/**
|
| 171 |
+
* Add the plugin to the set of disconnected ones.
|
| 172 |
+
*
|
| 173 |
+
* @param string $slug Plugin slug.
|
| 174 |
+
*
|
| 175 |
+
* @return bool
|
| 176 |
+
*/
|
| 177 |
+
public static function disable_plugin( $slug ) {
|
| 178 |
+
$disconnects = self::get_all_disabled_plugins();
|
| 179 |
+
|
| 180 |
+
if ( ! in_array( $slug, $disconnects, true ) ) {
|
| 181 |
+
$disconnects[] = $slug;
|
| 182 |
+
update_option( self::PLUGINS_DISABLED_OPTION_NAME, $disconnects );
|
| 183 |
+
}
|
| 184 |
+
|
| 185 |
+
return true;
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
/**
|
| 189 |
+
* Remove the plugin from the set of disconnected ones.
|
| 190 |
+
*
|
| 191 |
+
* @param string $slug Plugin slug.
|
| 192 |
+
*
|
| 193 |
+
* @return bool
|
| 194 |
+
*/
|
| 195 |
+
public static function enable_plugin( $slug ) {
|
| 196 |
+
$disconnects = self::get_all_disabled_plugins();
|
| 197 |
+
|
| 198 |
+
$slug_index = array_search( $slug, $disconnects, true );
|
| 199 |
+
if ( false !== $slug_index ) {
|
| 200 |
+
unset( $disconnects[ $slug_index ] );
|
| 201 |
+
update_option( self::PLUGINS_DISABLED_OPTION_NAME, $disconnects );
|
| 202 |
+
}
|
| 203 |
+
|
| 204 |
+
return true;
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
/**
|
| 208 |
+
* Get all plugins that were disconnected by user.
|
| 209 |
+
*
|
| 210 |
+
* @return array
|
| 211 |
+
*/
|
| 212 |
+
public static function get_all_disabled_plugins() {
|
| 213 |
+
return (array) get_option( self::PLUGINS_DISABLED_OPTION_NAME, array() );
|
| 214 |
+
}
|
| 215 |
+
|
| 216 |
}
|
vendor/automattic/jetpack-connection/src/class-plugin.php
CHANGED
|
@@ -74,9 +74,36 @@ class Plugin {
|
|
| 74 |
* @return bool
|
| 75 |
*/
|
| 76 |
public function is_only() {
|
| 77 |
-
$plugins = Plugin_Storage::get_all();
|
| 78 |
|
| 79 |
return ! $plugins || ( array_key_exists( $this->slug, $plugins ) && 1 === count( $plugins ) );
|
| 80 |
}
|
| 81 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 82 |
}
|
| 74 |
* @return bool
|
| 75 |
*/
|
| 76 |
public function is_only() {
|
| 77 |
+
$plugins = Plugin_Storage::get_all( true );
|
| 78 |
|
| 79 |
return ! $plugins || ( array_key_exists( $this->slug, $plugins ) && 1 === count( $plugins ) );
|
| 80 |
}
|
| 81 |
|
| 82 |
+
/**
|
| 83 |
+
* Add the plugin to the set of disconnected ones.
|
| 84 |
+
*
|
| 85 |
+
* @return bool
|
| 86 |
+
*/
|
| 87 |
+
public function disable() {
|
| 88 |
+
return Plugin_Storage::disable_plugin( $this->slug );
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
/**
|
| 92 |
+
* Remove the plugin from the set of disconnected ones.
|
| 93 |
+
*
|
| 94 |
+
* @return bool
|
| 95 |
+
*/
|
| 96 |
+
public function enable() {
|
| 97 |
+
return Plugin_Storage::enable_plugin( $this->slug );
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
/**
|
| 101 |
+
* Whether this plugin is allowed to use the connection.
|
| 102 |
+
*
|
| 103 |
+
* @return bool
|
| 104 |
+
*/
|
| 105 |
+
public function is_enabled() {
|
| 106 |
+
return ! in_array( $this->slug, Plugin_Storage::get_all_disabled_plugins(), true );
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
}
|
vendor/automattic/jetpack-connection/src/class-rest-connector.php
CHANGED
|
@@ -7,6 +7,13 @@
|
|
| 7 |
|
| 8 |
namespace Automattic\Jetpack\Connection;
|
| 9 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
/**
|
| 11 |
* Registers the REST routes for Connections.
|
| 12 |
*/
|
|
@@ -18,6 +25,13 @@ class REST_Connector {
|
|
| 18 |
*/
|
| 19 |
private $connection;
|
| 20 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
/**
|
| 22 |
* Constructor.
|
| 23 |
*
|
|
@@ -26,13 +40,72 @@ class REST_Connector {
|
|
| 26 |
public function __construct( Manager $connection ) {
|
| 27 |
$this->connection = $connection;
|
| 28 |
|
| 29 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
register_rest_route(
|
| 31 |
'jetpack/v4',
|
| 32 |
-
'/
|
| 33 |
array(
|
| 34 |
-
'methods'
|
| 35 |
-
'callback'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
)
|
| 37 |
);
|
| 38 |
}
|
|
@@ -42,13 +115,168 @@ class REST_Connector {
|
|
| 42 |
*
|
| 43 |
* @since 5.4.0
|
| 44 |
*
|
| 45 |
-
* @param
|
| 46 |
*
|
| 47 |
* @return string|WP_Error
|
| 48 |
*/
|
| 49 |
-
public function verify_registration(
|
| 50 |
$registration_data = array( $request['secret_1'], $request['state'] );
|
| 51 |
|
| 52 |
return $this->connection->handle_registration( $registration_data );
|
| 53 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
}
|
| 7 |
|
| 8 |
namespace Automattic\Jetpack\Connection;
|
| 9 |
|
| 10 |
+
use Automattic\Jetpack\Status;
|
| 11 |
+
use Jetpack_XMLRPC_Server;
|
| 12 |
+
use WP_Error;
|
| 13 |
+
use WP_REST_Request;
|
| 14 |
+
use WP_REST_Response;
|
| 15 |
+
use WP_REST_Server;
|
| 16 |
+
|
| 17 |
/**
|
| 18 |
* Registers the REST routes for Connections.
|
| 19 |
*/
|
| 25 |
*/
|
| 26 |
private $connection;
|
| 27 |
|
| 28 |
+
/**
|
| 29 |
+
* This property stores the localized "Insufficient Permissions" error message.
|
| 30 |
+
*
|
| 31 |
+
* @var string Generic error message when user is not allowed to perform an action.
|
| 32 |
+
*/
|
| 33 |
+
private static $user_permissions_error_msg;
|
| 34 |
+
|
| 35 |
/**
|
| 36 |
* Constructor.
|
| 37 |
*
|
| 40 |
public function __construct( Manager $connection ) {
|
| 41 |
$this->connection = $connection;
|
| 42 |
|
| 43 |
+
self::$user_permissions_error_msg = esc_html__(
|
| 44 |
+
'You do not have the correct user permissions to perform this action.
|
| 45 |
+
Please contact your site admin if you think this is a mistake.',
|
| 46 |
+
'jetpack'
|
| 47 |
+
);
|
| 48 |
+
|
| 49 |
+
if ( ! $this->connection->is_active() ) {
|
| 50 |
+
// Register a site.
|
| 51 |
+
register_rest_route(
|
| 52 |
+
'jetpack/v4',
|
| 53 |
+
'/verify_registration',
|
| 54 |
+
array(
|
| 55 |
+
'methods' => WP_REST_Server::EDITABLE,
|
| 56 |
+
'callback' => array( $this, 'verify_registration' ),
|
| 57 |
+
'permission_callback' => '__return_true',
|
| 58 |
+
)
|
| 59 |
+
);
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
// Authorize a remote user.
|
| 63 |
+
register_rest_route(
|
| 64 |
+
'jetpack/v4',
|
| 65 |
+
'/remote_authorize',
|
| 66 |
+
array(
|
| 67 |
+
'methods' => WP_REST_Server::EDITABLE,
|
| 68 |
+
'callback' => __CLASS__ . '::remote_authorize',
|
| 69 |
+
'permission_callback' => '__return_true',
|
| 70 |
+
)
|
| 71 |
+
);
|
| 72 |
+
|
| 73 |
+
// Get current connection status of Jetpack.
|
| 74 |
+
register_rest_route(
|
| 75 |
+
'jetpack/v4',
|
| 76 |
+
'/connection',
|
| 77 |
+
array(
|
| 78 |
+
'methods' => WP_REST_Server::READABLE,
|
| 79 |
+
'callback' => __CLASS__ . '::connection_status',
|
| 80 |
+
'permission_callback' => '__return_true',
|
| 81 |
+
)
|
| 82 |
+
);
|
| 83 |
+
|
| 84 |
+
// Get list of plugins that use the Jetpack connection.
|
| 85 |
+
register_rest_route(
|
| 86 |
+
'jetpack/v4',
|
| 87 |
+
'/connection/plugins',
|
| 88 |
+
array(
|
| 89 |
+
'methods' => WP_REST_Server::READABLE,
|
| 90 |
+
'callback' => array( $this, 'get_connection_plugins' ),
|
| 91 |
+
'permission_callback' => __CLASS__ . '::activate_plugins_permission_check',
|
| 92 |
+
)
|
| 93 |
+
);
|
| 94 |
+
|
| 95 |
+
// Full or partial reconnect in case of connection issues.
|
| 96 |
register_rest_route(
|
| 97 |
'jetpack/v4',
|
| 98 |
+
'/connection/reconnect',
|
| 99 |
array(
|
| 100 |
+
'methods' => WP_REST_Server::EDITABLE,
|
| 101 |
+
'callback' => array( $this, 'connection_reconnect' ),
|
| 102 |
+
'args' => array(
|
| 103 |
+
'action' => array(
|
| 104 |
+
'type' => 'string',
|
| 105 |
+
'required' => true,
|
| 106 |
+
),
|
| 107 |
+
),
|
| 108 |
+
'permission_callback' => __CLASS__ . '::jetpack_disconnect_permission_check',
|
| 109 |
)
|
| 110 |
);
|
| 111 |
}
|
| 115 |
*
|
| 116 |
* @since 5.4.0
|
| 117 |
*
|
| 118 |
+
* @param WP_REST_Request $request The request sent to the WP REST API.
|
| 119 |
*
|
| 120 |
* @return string|WP_Error
|
| 121 |
*/
|
| 122 |
+
public function verify_registration( WP_REST_Request $request ) {
|
| 123 |
$registration_data = array( $request['secret_1'], $request['state'] );
|
| 124 |
|
| 125 |
return $this->connection->handle_registration( $registration_data );
|
| 126 |
}
|
| 127 |
+
|
| 128 |
+
/**
|
| 129 |
+
* Handles verification that a site is registered
|
| 130 |
+
*
|
| 131 |
+
* @since 5.4.0
|
| 132 |
+
*
|
| 133 |
+
* @param WP_REST_Request $request The request sent to the WP REST API.
|
| 134 |
+
*
|
| 135 |
+
* @return array|wp-error
|
| 136 |
+
*/
|
| 137 |
+
public static function remote_authorize( $request ) {
|
| 138 |
+
$xmlrpc_server = new Jetpack_XMLRPC_Server();
|
| 139 |
+
$result = $xmlrpc_server->remote_authorize( $request );
|
| 140 |
+
|
| 141 |
+
if ( is_a( $result, 'IXR_Error' ) ) {
|
| 142 |
+
$result = new WP_Error( $result->code, $result->message );
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
return $result;
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
/**
|
| 149 |
+
* Get connection status for this Jetpack site.
|
| 150 |
+
*
|
| 151 |
+
* @since 4.3.0
|
| 152 |
+
*
|
| 153 |
+
* @param bool $rest_response Should we return a rest response or a simple array. Default to rest response.
|
| 154 |
+
*
|
| 155 |
+
* @return WP_REST_Response|array Connection information.
|
| 156 |
+
*/
|
| 157 |
+
public static function connection_status( $rest_response = true ) {
|
| 158 |
+
$status = new Status();
|
| 159 |
+
$connection = new Manager();
|
| 160 |
+
|
| 161 |
+
$connection_status = array(
|
| 162 |
+
'isActive' => $connection->is_active(),
|
| 163 |
+
'isStaging' => $status->is_staging_site(),
|
| 164 |
+
'isRegistered' => $connection->is_registered(),
|
| 165 |
+
'offlineMode' => array(
|
| 166 |
+
'isActive' => $status->is_offline_mode(),
|
| 167 |
+
'constant' => defined( 'JETPACK_DEV_DEBUG' ) && JETPACK_DEV_DEBUG,
|
| 168 |
+
'url' => $status->is_local_site(),
|
| 169 |
+
/** This filter is documented in packages/status/src/class-status.php */
|
| 170 |
+
'filter' => ( apply_filters( 'jetpack_development_mode', false ) || apply_filters( 'jetpack_offline_mode', false ) ), // jetpack_development_mode is deprecated.
|
| 171 |
+
'wpLocalConstant' => defined( 'WP_LOCAL_DEV' ) && WP_LOCAL_DEV,
|
| 172 |
+
),
|
| 173 |
+
'isPublic' => '1' == get_option( 'blog_public' ), // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
|
| 174 |
+
);
|
| 175 |
+
|
| 176 |
+
if ( $rest_response ) {
|
| 177 |
+
return rest_ensure_response(
|
| 178 |
+
$connection_status
|
| 179 |
+
);
|
| 180 |
+
} else {
|
| 181 |
+
return $connection_status;
|
| 182 |
+
}
|
| 183 |
+
}
|
| 184 |
+
|
| 185 |
+
|
| 186 |
+
/**
|
| 187 |
+
* Get plugins connected to the Jetpack.
|
| 188 |
+
*
|
| 189 |
+
* @since 8.6.0
|
| 190 |
+
*
|
| 191 |
+
* @return WP_REST_Response|WP_Error Response or error object, depending on the request result.
|
| 192 |
+
*/
|
| 193 |
+
public function get_connection_plugins() {
|
| 194 |
+
$plugins = $this->connection->get_connected_plugins();
|
| 195 |
+
|
| 196 |
+
if ( is_wp_error( $plugins ) ) {
|
| 197 |
+
return $plugins;
|
| 198 |
+
}
|
| 199 |
+
|
| 200 |
+
array_walk(
|
| 201 |
+
$plugins,
|
| 202 |
+
function( &$data, $slug ) {
|
| 203 |
+
$data['slug'] = $slug;
|
| 204 |
+
}
|
| 205 |
+
);
|
| 206 |
+
|
| 207 |
+
return rest_ensure_response( array_values( $plugins ) );
|
| 208 |
+
}
|
| 209 |
+
|
| 210 |
+
/**
|
| 211 |
+
* Verify that user can view Jetpack admin page and can activate plugins.
|
| 212 |
+
*
|
| 213 |
+
* @since 8.8.0
|
| 214 |
+
*
|
| 215 |
+
* @return bool|WP_Error Whether user has the capability 'activate_plugins'.
|
| 216 |
+
*/
|
| 217 |
+
public static function activate_plugins_permission_check() {
|
| 218 |
+
if ( current_user_can( 'activate_plugins' ) ) {
|
| 219 |
+
return true;
|
| 220 |
+
}
|
| 221 |
+
|
| 222 |
+
return new WP_Error( 'invalid_user_permission_activate_plugins', self::get_user_permissions_error_msg(), array( 'status' => rest_authorization_required_code() ) );
|
| 223 |
+
}
|
| 224 |
+
|
| 225 |
+
/**
|
| 226 |
+
* Verify that user is allowed to disconnect Jetpack.
|
| 227 |
+
*
|
| 228 |
+
* @since 8.8.0
|
| 229 |
+
*
|
| 230 |
+
* @return bool|WP_Error Whether user has the capability 'jetpack_disconnect'.
|
| 231 |
+
*/
|
| 232 |
+
public static function jetpack_disconnect_permission_check() {
|
| 233 |
+
if ( current_user_can( 'jetpack_disconnect' ) ) {
|
| 234 |
+
return true;
|
| 235 |
+
}
|
| 236 |
+
|
| 237 |
+
return new WP_Error( 'invalid_user_permission_jetpack_disconnect', self::get_user_permissions_error_msg(), array( 'status' => rest_authorization_required_code() ) );
|
| 238 |
+
}
|
| 239 |
+
|
| 240 |
+
/**
|
| 241 |
+
* Returns generic error message when user is not allowed to perform an action.
|
| 242 |
+
*
|
| 243 |
+
* @return string The error message.
|
| 244 |
+
*/
|
| 245 |
+
public static function get_user_permissions_error_msg() {
|
| 246 |
+
return self::$user_permissions_error_msg;
|
| 247 |
+
}
|
| 248 |
+
|
| 249 |
+
/**
|
| 250 |
+
* The endpoint tried to partially or fully reconnect the website to WP.com.
|
| 251 |
+
*
|
| 252 |
+
* @since 8.8.0
|
| 253 |
+
*
|
| 254 |
+
* @param WP_REST_Request $request The request sent to the WP REST API.
|
| 255 |
+
*
|
| 256 |
+
* @return \WP_REST_Response|WP_Error
|
| 257 |
+
*/
|
| 258 |
+
public function connection_reconnect( WP_REST_Request $request ) {
|
| 259 |
+
$params = $request->get_json_params();
|
| 260 |
+
|
| 261 |
+
$response = array();
|
| 262 |
+
|
| 263 |
+
switch ( $params['action'] ) {
|
| 264 |
+
case 'reconnect':
|
| 265 |
+
$result = $this->connection->reconnect();
|
| 266 |
+
|
| 267 |
+
if ( true === $result ) {
|
| 268 |
+
$response['status'] = 'in_progress';
|
| 269 |
+
$response['authorizeUrl'] = $this->connection->get_authorization_url();
|
| 270 |
+
} elseif ( is_wp_error( $result ) ) {
|
| 271 |
+
$response = $result;
|
| 272 |
+
}
|
| 273 |
+
break;
|
| 274 |
+
default:
|
| 275 |
+
$response = new WP_Error( 'Unknown action' );
|
| 276 |
+
break;
|
| 277 |
+
}
|
| 278 |
+
|
| 279 |
+
return rest_ensure_response( $response );
|
| 280 |
+
}
|
| 281 |
+
|
| 282 |
}
|
vendor/automattic/jetpack-connection/src/error-handlers/class-invalid-blog-token.php
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
/**
|
| 3 |
+
* The Jetpack Connection error handler class for invalid blog tokens
|
| 4 |
+
*
|
| 5 |
+
* @package automattic/jetpack-connection
|
| 6 |
+
*/
|
| 7 |
+
|
| 8 |
+
namespace Automattic\Jetpack\Connection\Error_Handlers;
|
| 9 |
+
|
| 10 |
+
/**
|
| 11 |
+
* This class handles all the error codes that indicates a broken blog token and
|
| 12 |
+
* suggests the user to reconnect.
|
| 13 |
+
*
|
| 14 |
+
* @since 8.7.0
|
| 15 |
+
*/
|
| 16 |
+
class Invalid_Blog_Token {
|
| 17 |
+
|
| 18 |
+
/**
|
| 19 |
+
* Set up hooks
|
| 20 |
+
*
|
| 21 |
+
* @since 8.7.0
|
| 22 |
+
*
|
| 23 |
+
* @param array $errors The array containing verified errors stored in the database.
|
| 24 |
+
*/
|
| 25 |
+
public function __construct( $errors ) {
|
| 26 |
+
|
| 27 |
+
/**
|
| 28 |
+
* Filters the message to be displayed in the admin notices area when there's a invalid blog token xmlrpc error
|
| 29 |
+
*
|
| 30 |
+
* Return an empty value to disable the message.
|
| 31 |
+
*
|
| 32 |
+
* @since 8.7.0
|
| 33 |
+
*
|
| 34 |
+
* @param string $message The error message.
|
| 35 |
+
*/
|
| 36 |
+
$this->message = apply_filters( 'jetpack_connection_invalid_blog_token_admin_notice', __( 'Your connection with WordPress.com seems to be broken. If you\'re experiencing issues, please try reconnecting.', 'jetpack' ) );
|
| 37 |
+
|
| 38 |
+
if ( empty( $this->message ) ) {
|
| 39 |
+
return;
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
// In this class, we will only handle errors with the blog token, so ignoring if there are only errors with user tokens.
|
| 43 |
+
if ( ! isset( $errors[0] ) && ! isset( $errors['invalid'] ) ) {
|
| 44 |
+
return;
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
add_action( 'react_connection_errors_initial_state', array( $this, 'jetpack_react_dashboard_error' ) );
|
| 48 |
+
// do not add admin notice to the jetpack dashboard.
|
| 49 |
+
global $pagenow;
|
| 50 |
+
if ( 'admin.php' === $pagenow || isset( $_GET['page'] ) && 'jetpack' === $_GET['page'] ) { // phpcs:ignore
|
| 51 |
+
return;
|
| 52 |
+
}
|
| 53 |
+
add_action( 'admin_notices', array( $this, 'admin_notice' ) );
|
| 54 |
+
|
| 55 |
+
}
|
| 56 |
+
|
| 57 |
+
/**
|
| 58 |
+
* Prints an admin notice for the blog token error
|
| 59 |
+
*
|
| 60 |
+
* @since 8.7.0
|
| 61 |
+
*
|
| 62 |
+
* @return void
|
| 63 |
+
*/
|
| 64 |
+
public function admin_notice() {
|
| 65 |
+
|
| 66 |
+
if ( ! current_user_can( 'jetpack_connect' ) ) {
|
| 67 |
+
return;
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
?>
|
| 71 |
+
<div class="notice notice-error is-dismissible jetpack-message jp-connect" style="display:block !important;">
|
| 72 |
+
<p><?php echo esc_html( $this->message ); ?></p>
|
| 73 |
+
</div>
|
| 74 |
+
<?php
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
/**
|
| 78 |
+
* Adds the error message to the Jetpack React Dashboard
|
| 79 |
+
*
|
| 80 |
+
* @param array $errors The array of errors.
|
| 81 |
+
* @return array
|
| 82 |
+
*/
|
| 83 |
+
public function jetpack_react_dashboard_error( $errors ) {
|
| 84 |
+
|
| 85 |
+
$errors[] = array(
|
| 86 |
+
'code' => 'invalid_blog_token',
|
| 87 |
+
'message' => $this->message,
|
| 88 |
+
'action' => 'reconnect',
|
| 89 |
+
);
|
| 90 |
+
return $errors;
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
|
| 94 |
+
}
|
vendor/automattic/jetpack-constants/phpunit.xml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<phpunit bootstrap="tests/php/bootstrap.php" backupGlobals="false" colors="true">
|
| 2 |
+
<testsuites>
|
| 3 |
+
<testsuite name="main">
|
| 4 |
+
<directory prefix="test" suffix=".php">tests/php</directory>
|
| 5 |
+
</testsuite>
|
| 6 |
+
</testsuites>
|
| 7 |
+
</phpunit>
|
vendor/automattic/jetpack-options/composer.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
| 4 |
"type": "library",
|
| 5 |
"license": "GPL-2.0-or-later",
|
| 6 |
"require": {
|
| 7 |
-
"automattic/jetpack-constants": "1.
|
| 8 |
},
|
| 9 |
"require-dev": {
|
| 10 |
"phpunit/phpunit": "7.*.*",
|
| 4 |
"type": "library",
|
| 5 |
"license": "GPL-2.0-or-later",
|
| 6 |
"require": {
|
| 7 |
+
"automattic/jetpack-constants": "1.4.0"
|
| 8 |
},
|
| 9 |
"require-dev": {
|
| 10 |
"phpunit/phpunit": "7.*.*",
|
vendor/automattic/jetpack-options/legacy/class-jetpack-options.php
CHANGED
|
@@ -167,7 +167,8 @@ class Jetpack_Options {
|
|
| 167 |
}
|
| 168 |
|
| 169 |
/**
|
| 170 |
-
*
|
|
|
|
| 171 |
*
|
| 172 |
* @param string $name Option name. It must come _without_ `jetpack_%` prefix. The method will prefix the option name.
|
| 173 |
* @param mixed $default (optional).
|
|
@@ -175,6 +176,28 @@ class Jetpack_Options {
|
|
| 175 |
* @return mixed
|
| 176 |
*/
|
| 177 |
public static function get_option( $name, $default = false ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 178 |
if ( self::is_valid( $name, 'non_compact' ) ) {
|
| 179 |
if ( self::is_network_option( $name ) ) {
|
| 180 |
return get_site_option( "jetpack_$name", $default );
|
|
@@ -481,7 +504,7 @@ class Jetpack_Options {
|
|
| 481 |
|
| 482 |
/**
|
| 483 |
* This function checks for a constant that, if present, will disable direct DB queries Jetpack uses to manage certain options and force Jetpack to always use Options API instead.
|
| 484 |
-
* Options can be selectively managed via a
|
| 485 |
*
|
| 486 |
* @param string $name Option name.
|
| 487 |
*
|
|
@@ -497,7 +520,7 @@ class Jetpack_Options {
|
|
| 497 |
*
|
| 498 |
* @since 5.5.0
|
| 499 |
*
|
| 500 |
-
* @param array $disabled_raw_options An array of option names that you can selectively
|
| 501 |
*/
|
| 502 |
$disabled_raw_options = apply_filters( 'jetpack_disabled_raw_options', array() );
|
| 503 |
return isset( $disabled_raw_options[ $name ] );
|
| 167 |
}
|
| 168 |
|
| 169 |
/**
|
| 170 |
+
* Filters the requested option.
|
| 171 |
+
* This is a wrapper around `get_option_from_database` so that we can filter the option.
|
| 172 |
*
|
| 173 |
* @param string $name Option name. It must come _without_ `jetpack_%` prefix. The method will prefix the option name.
|
| 174 |
* @param mixed $default (optional).
|
| 176 |
* @return mixed
|
| 177 |
*/
|
| 178 |
public static function get_option( $name, $default = false ) {
|
| 179 |
+
/**
|
| 180 |
+
* Filter Jetpack Options.
|
| 181 |
+
* Can be useful in environments when Jetpack is running with a different setup
|
| 182 |
+
*
|
| 183 |
+
* @since 8.8.0
|
| 184 |
+
*
|
| 185 |
+
* @param string $value The value from the database.
|
| 186 |
+
* @param string $name Option name, _without_ `jetpack_%` prefix.
|
| 187 |
+
* @return string $value, unless the filters modify it.
|
| 188 |
+
*/
|
| 189 |
+
return apply_filters( 'jetpack_options', self::get_option_from_database( $name, $default ), $name );
|
| 190 |
+
}
|
| 191 |
+
|
| 192 |
+
/**
|
| 193 |
+
* Returns the requested option. Looks in jetpack_options or jetpack_$name as appropriate.
|
| 194 |
+
*
|
| 195 |
+
* @param string $name Option name. It must come _without_ `jetpack_%` prefix. The method will prefix the option name.
|
| 196 |
+
* @param mixed $default (optional).
|
| 197 |
+
*
|
| 198 |
+
* @return mixed
|
| 199 |
+
*/
|
| 200 |
+
private static function get_option_from_database( $name, $default = false ) {
|
| 201 |
if ( self::is_valid( $name, 'non_compact' ) ) {
|
| 202 |
if ( self::is_network_option( $name ) ) {
|
| 203 |
return get_site_option( "jetpack_$name", $default );
|
| 504 |
|
| 505 |
/**
|
| 506 |
* This function checks for a constant that, if present, will disable direct DB queries Jetpack uses to manage certain options and force Jetpack to always use Options API instead.
|
| 507 |
+
* Options can be selectively managed via a blocklist by filtering option names via the jetpack_disabled_raw_option filter.
|
| 508 |
*
|
| 509 |
* @param string $name Option name.
|
| 510 |
*
|
| 520 |
*
|
| 521 |
* @since 5.5.0
|
| 522 |
*
|
| 523 |
+
* @param array $disabled_raw_options An array of option names that you can selectively blocklist from being managed via direct database queries.
|
| 524 |
*/
|
| 525 |
$disabled_raw_options = apply_filters( 'jetpack_disabled_raw_options', array() );
|
| 526 |
return isset( $disabled_raw_options[ $name ] );
|
vendor/automattic/jetpack-roles/phpunit.xml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<phpunit bootstrap="tests/php/bootstrap.php" backupGlobals="false" colors="true">
|
| 2 |
+
<testsuites>
|
| 3 |
+
<testsuite name="main">
|
| 4 |
+
<directory prefix="test" suffix=".php">tests/php</directory>
|
| 5 |
+
</testsuite>
|
| 6 |
+
</testsuites>
|
| 7 |
+
</phpunit>
|
vendor/automattic/jetpack-status/README.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Jetpack Status
|
| 2 |
+
|
| 3 |
+
A status class for Jetpack.
|
| 4 |
+
|
| 5 |
+
Used to retrieve information about the current status of Jetpack and the site overall.
|
| 6 |
+
|
| 7 |
+
### Usage
|
| 8 |
+
|
| 9 |
+
Find out whether the site is in offline mode:
|
| 10 |
+
|
| 11 |
+
```php
|
| 12 |
+
use Automattic\Jetpack\Status;
|
| 13 |
+
|
| 14 |
+
$status = new Status();
|
| 15 |
+
$is_offline_mode = $status->is_offline_mode();
|
| 16 |
+
```
|
| 17 |
+
|
| 18 |
+
Find out whether this is a system with multiple networks:
|
| 19 |
+
|
| 20 |
+
```php
|
| 21 |
+
use Automattic\Jetpack\Status;
|
| 22 |
+
|
| 23 |
+
$status = new Status();
|
| 24 |
+
$is_multi_network = $status->is_multi_network();
|
| 25 |
+
```
|
| 26 |
+
|
| 27 |
+
Find out whether this site is a single user site:
|
| 28 |
+
|
| 29 |
+
```php
|
| 30 |
+
use Automattic\Jetpack\Status;
|
| 31 |
+
|
| 32 |
+
$status = new Status();
|
| 33 |
+
$is_single_user_site = $status->is_single_user_site();
|
| 34 |
+
```
|
vendor/automattic/jetpack-status/composer.json
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"name": "automattic/jetpack-status",
|
| 3 |
+
"description": "Used to retrieve information about the current status of Jetpack and the site overall.",
|
| 4 |
+
"type": "library",
|
| 5 |
+
"license": "GPL-2.0-or-later",
|
| 6 |
+
"require": {},
|
| 7 |
+
"require-dev": {
|
| 8 |
+
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5",
|
| 9 |
+
"php-mock/php-mock": "^2.1",
|
| 10 |
+
"brain/monkey": "2.4.0"
|
| 11 |
+
},
|
| 12 |
+
"autoload": {
|
| 13 |
+
"classmap": [
|
| 14 |
+
"src/"
|
| 15 |
+
]
|
| 16 |
+
},
|
| 17 |
+
"scripts": {
|
| 18 |
+
"phpunit": [
|
| 19 |
+
"@composer install",
|
| 20 |
+
"./vendor/phpunit/phpunit/phpunit --colors=always"
|
| 21 |
+
]
|
| 22 |
+
},
|
| 23 |
+
"repositories": [
|
| 24 |
+
{
|
| 25 |
+
"type": "path",
|
| 26 |
+
"url": "../*"
|
| 27 |
+
}
|
| 28 |
+
],
|
| 29 |
+
"minimum-stability": "dev",
|
| 30 |
+
"prefer-stable": true
|
| 31 |
+
}
|
vendor/automattic/jetpack-status/src/class-status.php
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<?php
|
| 2 |
+
/**
|
| 3 |
+
* A status class for Jetpack.
|
| 4 |
+
*
|
| 5 |
+
* @package automattic/jetpack-status
|
| 6 |
+
*/
|
| 7 |
+
|
| 8 |
+
namespace Automattic\Jetpack;
|
| 9 |
+
|
| 10 |
+
/**
|
| 11 |
+
* Class Automattic\Jetpack\Status
|
| 12 |
+
*
|
| 13 |
+
* Used to retrieve information about the current status of Jetpack and the site overall.
|
| 14 |
+
*/
|
| 15 |
+
class Status {
|
| 16 |
+
/**
|
| 17 |
+
* Is Jetpack in development (offline) mode?
|
| 18 |
+
*
|
| 19 |
+
* @deprecated 8.8.0 Use Status->is_offline_mode().
|
| 20 |
+
*
|
| 21 |
+
* @return bool Whether Jetpack's offline mode is active.
|
| 22 |
+
*/
|
| 23 |
+
public function is_development_mode() {
|
| 24 |
+
_deprecated_function( __FUNCTION__, 'Jetpack 8.8.0', 'Automattic\Jetpack\Status->is_offline_mode' );
|
| 25 |
+
return $this->is_offline_mode();
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
/**
|
| 29 |
+
* Is Jetpack in offline mode?
|
| 30 |
+
*
|
| 31 |
+
* This was formerly called "Development Mode", but sites "in development" aren't always offline/localhost.
|
| 32 |
+
*
|
| 33 |
+
* @since 8.8.0
|
| 34 |
+
*
|
| 35 |
+
* @return bool Whether Jetpack's offline mode is active.
|
| 36 |
+
*/
|
| 37 |
+
public function is_offline_mode() {
|
| 38 |
+
$offline_mode = false;
|
| 39 |
+
|
| 40 |
+
if ( defined( '\\JETPACK_DEV_DEBUG' ) ) {
|
| 41 |
+
$offline_mode = constant( '\\JETPACK_DEV_DEBUG' );
|
| 42 |
+
} elseif ( defined( '\\WP_LOCAL_DEV' ) ) {
|
| 43 |
+
$offline_mode = constant( '\\WP_LOCAL_DEV' );
|
| 44 |
+
} elseif ( $this->is_local_site() ) {
|
| 45 |
+
$offline_mode = true;
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
/**
|
| 49 |
+
* Filters Jetpack's offline mode.
|
| 50 |
+
*
|
| 51 |
+
* @see https://jetpack.com/support/development-mode/
|
| 52 |
+
* @todo Update documentation ^^.
|
| 53 |
+
*
|
| 54 |
+
* @since 2.2.1
|
| 55 |
+
* @deprecated 8.8.0
|
| 56 |
+
*
|
| 57 |
+
* @param bool $offline_mode Is Jetpack's offline mode active.
|
| 58 |
+
*/
|
| 59 |
+
$offline_mode = (bool) apply_filters_deprecated( 'jetpack_development_mode', array( $offline_mode ), '8.8.0', 'jetpack_offline_mode' );
|
| 60 |
+
|
| 61 |
+
/**
|
| 62 |
+
* Filters Jetpack's offline mode.
|
| 63 |
+
*
|
| 64 |
+
* @see https://jetpack.com/support/development-mode/
|
| 65 |
+
* @todo Update documentation ^^.
|
| 66 |
+
*
|
| 67 |
+
* @since 8.8.0
|
| 68 |
+
*
|
| 69 |
+
* @param bool $offline_mode Is Jetpack's offline mode active.
|
| 70 |
+
*/
|
| 71 |
+
$offline_mode = (bool) apply_filters( 'jetpack_offline_mode', $offline_mode );
|
| 72 |
+
|
| 73 |
+
return $offline_mode;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
/**
|
| 77 |
+
* Whether this is a system with a multiple networks.
|
| 78 |
+
* Implemented since there is no core is_multi_network function.
|
| 79 |
+
* Right now there is no way to tell which network is the dominant network on the system.
|
| 80 |
+
*
|
| 81 |
+
* @return boolean
|
| 82 |
+
*/
|
| 83 |
+
public function is_multi_network() {
|
| 84 |
+
global $wpdb;
|
| 85 |
+
|
| 86 |
+
// If we don't have a multi site setup no need to do any more.
|
| 87 |
+
if ( ! is_multisite() ) {
|
| 88 |
+
return false;
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
$num_sites = $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->site}" );
|
| 92 |
+
if ( $num_sites > 1 ) {
|
| 93 |
+
return true;
|
| 94 |
+
}
|
| 95 |
+
|
| 96 |
+
return false;
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
/**
|
| 100 |
+
* Whether the current site is single user site.
|
| 101 |
+
*
|
| 102 |
+
* @return bool
|
| 103 |
+
*/
|
| 104 |
+
public function is_single_user_site() {
|
| 105 |
+
global $wpdb;
|
| 106 |
+
|
| 107 |
+
$some_users = get_transient( 'jetpack_is_single_user' );
|
| 108 |
+
if ( false === $some_users ) {
|
| 109 |
+
$some_users = $wpdb->get_var( "SELECT COUNT(*) FROM (SELECT user_id FROM $wpdb->usermeta WHERE meta_key = '{$wpdb->prefix}capabilities' LIMIT 2) AS someusers" );
|
| 110 |
+
set_transient( 'jetpack_is_single_user', (int) $some_users, 12 * HOUR_IN_SECONDS );
|
| 111 |
+
}
|
| 112 |
+
return 1 === (int) $some_users;
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
/**
|
| 116 |
+
* If the site is a local site.
|
| 117 |
+
*
|
| 118 |
+
* @since 8.8.0
|
| 119 |
+
*
|
| 120 |
+
* @return bool
|
| 121 |
+
*/
|
| 122 |
+
public function is_local_site() {
|
| 123 |
+
// Check for localhost and sites using an IP only first.
|
| 124 |
+
$is_local = site_url() && false === strpos( site_url(), '.' );
|
| 125 |
+
|
| 126 |
+
// Then check for usual usual domains used by local dev tools.
|
| 127 |
+
$known_local = array(
|
| 128 |
+
'#\.local$#i',
|
| 129 |
+
'#\.localhost$#i',
|
| 130 |
+
'#\.test$#i',
|
| 131 |
+
'#\.docksal$#i', // Docksal.
|
| 132 |
+
'#\.docksal\.site$#i', // Docksal.
|
| 133 |
+
'#\.dev\.cc$#i', // ServerPress.
|
| 134 |
+
'#\.lndo\.site$#i', // Lando.
|
| 135 |
+
);
|
| 136 |
+
|
| 137 |
+
if ( ! $is_local ) {
|
| 138 |
+
foreach ( $known_local as $url ) {
|
| 139 |
+
if ( preg_match( $url, site_url() ) ) {
|
| 140 |
+
$is_local = true;
|
| 141 |
+
break;
|
| 142 |
+
}
|
| 143 |
+
}
|
| 144 |
+
}
|
| 145 |
+
|
| 146 |
+
/**
|
| 147 |
+
* Filters is_local_site check.
|
| 148 |
+
*
|
| 149 |
+
* @since 8.8.0
|
| 150 |
+
*
|
| 151 |
+
* @param bool $is_local If the current site is a local site.
|
| 152 |
+
*/
|
| 153 |
+
return apply_filters( 'jetpack_is_local_site', $is_local );
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
/**
|
| 157 |
+
* If is a staging site.
|
| 158 |
+
*
|
| 159 |
+
* @todo Add IDC detection to a package.
|
| 160 |
+
*
|
| 161 |
+
* @return bool
|
| 162 |
+
*/
|
| 163 |
+
public function is_staging_site() {
|
| 164 |
+
// @todo Remove function_exists when WP 5.5 is the minimum version.
|
| 165 |
+
// Core's wp_get_environment_type allows for a few specific options. We should default to bowing out gracefully for anything other than production.
|
| 166 |
+
$is_staging = function_exists( 'wp_get_environment_type' ) && 'production' !== wp_get_environment_type();
|
| 167 |
+
|
| 168 |
+
$known_staging = array(
|
| 169 |
+
'urls' => array(
|
| 170 |
+
'#\.staging\.wpengine\.com$#i', // WP Engine.
|
| 171 |
+
'#\.staging\.kinsta\.com$#i', // Kinsta.com.
|
| 172 |
+
'#\.kinsta\.cloud$#i', // Kinsta.com.
|
| 173 |
+
'#\.stage\.site$#i', // DreamPress.
|
| 174 |
+
'#\.newspackstaging\.com$#i', // Newspack.
|
| 175 |
+
'#\.pantheonsite\.io$#i', // Pantheon.
|
| 176 |
+
'#\.flywheelsites\.com$#i', // Flywheel.
|
| 177 |
+
'#\.flywheelstaging\.com$#i', // Flywheel.
|
| 178 |
+
'#\.cloudwaysapps\.com$#i', // Cloudways.
|
| 179 |
+
'#\.azurewebsites\.net$#i', // Azure.
|
| 180 |
+
'#\.wpserveur\.net$#i', // WPServeur.
|
| 181 |
+
'#\-liquidwebsites\.com$#i', // Liquidweb.
|
| 182 |
+
),
|
| 183 |
+
'constants' => array(
|
| 184 |
+
'IS_WPE_SNAPSHOT', // WP Engine.
|
| 185 |
+
'KINSTA_DEV_ENV', // Kinsta.com.
|
| 186 |
+
'WPSTAGECOACH_STAGING', // WP Stagecoach.
|
| 187 |
+
'JETPACK_STAGING_MODE', // Generic.
|
| 188 |
+
'WP_LOCAL_DEV', // Generic.
|
| 189 |
+
),
|
| 190 |
+
);
|
| 191 |
+
/**
|
| 192 |
+
* Filters the flags of known staging sites.
|
| 193 |
+
*
|
| 194 |
+
* @since 3.9.0
|
| 195 |
+
*
|
| 196 |
+
* @param array $known_staging {
|
| 197 |
+
* An array of arrays that each are used to check if the current site is staging.
|
| 198 |
+
* @type array $urls URLs of staging sites in regex to check against site_url.
|
| 199 |
+
* @type array $constants PHP constants of known staging/developement environments.
|
| 200 |
+
* }
|
| 201 |
+
*/
|
| 202 |
+
$known_staging = apply_filters( 'jetpack_known_staging', $known_staging );
|
| 203 |
+
|
| 204 |
+
if ( isset( $known_staging['urls'] ) ) {
|
| 205 |
+
foreach ( $known_staging['urls'] as $url ) {
|
| 206 |
+
if ( preg_match( $url, site_url() ) ) {
|
| 207 |
+
$is_staging = true;
|
| 208 |
+
break;
|
| 209 |
+
}
|
| 210 |
+
}
|
| 211 |
+
}
|
| 212 |
+
|
| 213 |
+
if ( isset( $known_staging['constants'] ) ) {
|
| 214 |
+
foreach ( $known_staging['constants'] as $constant ) {
|
| 215 |
+
if ( defined( $constant ) && constant( $constant ) ) {
|
| 216 |
+
$is_staging = true;
|
| 217 |
+
}
|
| 218 |
+
}
|
| 219 |
+
}
|
| 220 |
+
|
| 221 |
+
// Last, let's check if sync is erroring due to an IDC. If so, set the site to staging mode.
|
| 222 |
+
if ( ! $is_staging && method_exists( 'Jetpack', 'validate_sync_error_idc_option' ) && \Jetpack::validate_sync_error_idc_option() ) {
|
| 223 |
+
$is_staging = true;
|
| 224 |
+
}
|
| 225 |
+
|
| 226 |
+
/**
|
| 227 |
+
* Filters is_staging_site check.
|
| 228 |
+
*
|
| 229 |
+
* @since 3.9.0
|
| 230 |
+
*
|
| 231 |
+
* @param bool $is_staging If the current site is a staging site.
|
| 232 |
+
*/
|
| 233 |
+
return apply_filters( 'jetpack_is_staging_site', $is_staging );
|
| 234 |
+
}
|
| 235 |
+
}
|
vendor/composer/ClassLoader.php
CHANGED
|
@@ -279,7 +279,7 @@ class ClassLoader
|
|
| 279 |
*/
|
| 280 |
public function setApcuPrefix($apcuPrefix)
|
| 281 |
{
|
| 282 |
-
$this->apcuPrefix = function_exists('apcu_fetch') &&
|
| 283 |
}
|
| 284 |
|
| 285 |
/**
|
| 279 |
*/
|
| 280 |
public function setApcuPrefix($apcuPrefix)
|
| 281 |
{
|
| 282 |
+
$this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
|
| 283 |
}
|
| 284 |
|
| 285 |
/**
|
vendor/composer/autoload_classmap.php
CHANGED
|
@@ -8,6 +8,8 @@ $baseDir = dirname($vendorDir);
|
|
| 8 |
return array(
|
| 9 |
'Automattic\\Jetpack\\Config' => $vendorDir . '/automattic/jetpack-config/src/class-config.php',
|
| 10 |
'Automattic\\Jetpack\\Connection\\Client' => $vendorDir . '/automattic/jetpack-connection/src/class-client.php',
|
|
|
|
|
|
|
| 11 |
'Automattic\\Jetpack\\Connection\\Manager' => $vendorDir . '/automattic/jetpack-connection/src/class-manager.php',
|
| 12 |
'Automattic\\Jetpack\\Connection\\Manager_Interface' => $vendorDir . '/automattic/jetpack-connection/src/interface-manager.php',
|
| 13 |
'Automattic\\Jetpack\\Connection\\Plugin' => $vendorDir . '/automattic/jetpack-connection/src/class-plugin.php',
|
|
@@ -17,6 +19,7 @@ return array(
|
|
| 17 |
'Automattic\\Jetpack\\Connection\\XMLRPC_Connector' => $vendorDir . '/automattic/jetpack-connection/src/class-xmlrpc-connector.php',
|
| 18 |
'Automattic\\Jetpack\\Constants' => $vendorDir . '/automattic/jetpack-constants/src/class-constants.php',
|
| 19 |
'Automattic\\Jetpack\\Roles' => $vendorDir . '/automattic/jetpack-roles/src/class-roles.php',
|
|
|
|
| 20 |
'Jetpack_IXR_Client' => $vendorDir . '/automattic/jetpack-connection/legacy/class-jetpack-ixr-client.php',
|
| 21 |
'Jetpack_IXR_ClientMulticall' => $vendorDir . '/automattic/jetpack-connection/legacy/class-jetpack-ixr-clientmulticall.php',
|
| 22 |
'Jetpack_Options' => $vendorDir . '/automattic/jetpack-options/legacy/class-jetpack-options.php',
|
| 8 |
return array(
|
| 9 |
'Automattic\\Jetpack\\Config' => $vendorDir . '/automattic/jetpack-config/src/class-config.php',
|
| 10 |
'Automattic\\Jetpack\\Connection\\Client' => $vendorDir . '/automattic/jetpack-connection/src/class-client.php',
|
| 11 |
+
'Automattic\\Jetpack\\Connection\\Error_Handler' => $vendorDir . '/automattic/jetpack-connection/src/class-error-handler.php',
|
| 12 |
+
'Automattic\\Jetpack\\Connection\\Error_Handlers\\Invalid_Blog_Token' => $vendorDir . '/automattic/jetpack-connection/src/error-handlers/class-invalid-blog-token.php',
|
| 13 |
'Automattic\\Jetpack\\Connection\\Manager' => $vendorDir . '/automattic/jetpack-connection/src/class-manager.php',
|
| 14 |
'Automattic\\Jetpack\\Connection\\Manager_Interface' => $vendorDir . '/automattic/jetpack-connection/src/interface-manager.php',
|
| 15 |
'Automattic\\Jetpack\\Connection\\Plugin' => $vendorDir . '/automattic/jetpack-connection/src/class-plugin.php',
|
| 19 |
'Automattic\\Jetpack\\Connection\\XMLRPC_Connector' => $vendorDir . '/automattic/jetpack-connection/src/class-xmlrpc-connector.php',
|
| 20 |
'Automattic\\Jetpack\\Constants' => $vendorDir . '/automattic/jetpack-constants/src/class-constants.php',
|
| 21 |
'Automattic\\Jetpack\\Roles' => $vendorDir . '/automattic/jetpack-roles/src/class-roles.php',
|
| 22 |
+
'Automattic\\Jetpack\\Status' => $vendorDir . '/automattic/jetpack-status/src/class-status.php',
|
| 23 |
'Jetpack_IXR_Client' => $vendorDir . '/automattic/jetpack-connection/legacy/class-jetpack-ixr-client.php',
|
| 24 |
'Jetpack_IXR_ClientMulticall' => $vendorDir . '/automattic/jetpack-connection/legacy/class-jetpack-ixr-clientmulticall.php',
|
| 25 |
'Jetpack_Options' => $vendorDir . '/automattic/jetpack-options/legacy/class-jetpack-options.php',
|
vendor/composer/autoload_classmap_package.php
CHANGED
|
@@ -15,67 +15,79 @@ return array(
|
|
| 15 |
'path' => $vendorDir . '/automattic/jetpack-autoloader/src/CustomAutoloaderPlugin.php'
|
| 16 |
),
|
| 17 |
'Jetpack_XMLRPC_Server' => array(
|
| 18 |
-
'version' => '1.
|
| 19 |
'path' => $vendorDir . '/automattic/jetpack-connection/legacy/class-jetpack-xmlrpc-server.php'
|
| 20 |
),
|
| 21 |
'Jetpack_IXR_Client' => array(
|
| 22 |
-
'version' => '1.
|
| 23 |
'path' => $vendorDir . '/automattic/jetpack-connection/legacy/class-jetpack-ixr-client.php'
|
| 24 |
),
|
| 25 |
'Jetpack_Signature' => array(
|
| 26 |
-
'version' => '1.
|
| 27 |
'path' => $vendorDir . '/automattic/jetpack-connection/legacy/class-jetpack-signature.php'
|
| 28 |
),
|
| 29 |
'Jetpack_IXR_ClientMulticall' => array(
|
| 30 |
-
'version' => '1.
|
| 31 |
'path' => $vendorDir . '/automattic/jetpack-connection/legacy/class-jetpack-ixr-clientmulticall.php'
|
| 32 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
'Automattic\\Jetpack\\Connection\\REST_Connector' => array(
|
| 34 |
-
'version' => '1.
|
| 35 |
'path' => $vendorDir . '/automattic/jetpack-connection/src/class-rest-connector.php'
|
| 36 |
),
|
| 37 |
'Automattic\\Jetpack\\Connection\\Plugin_Storage' => array(
|
| 38 |
-
'version' => '1.
|
| 39 |
'path' => $vendorDir . '/automattic/jetpack-connection/src/class-plugin-storage.php'
|
| 40 |
),
|
| 41 |
'Automattic\\Jetpack\\Connection\\Client' => array(
|
| 42 |
-
'version' => '1.
|
| 43 |
'path' => $vendorDir . '/automattic/jetpack-connection/src/class-client.php'
|
| 44 |
),
|
| 45 |
'Automattic\\Jetpack\\Connection\\Utils' => array(
|
| 46 |
-
'version' => '1.
|
| 47 |
'path' => $vendorDir . '/automattic/jetpack-connection/src/class-utils.php'
|
| 48 |
),
|
| 49 |
'Automattic\\Jetpack\\Connection\\Manager_Interface' => array(
|
| 50 |
-
'version' => '1.
|
| 51 |
'path' => $vendorDir . '/automattic/jetpack-connection/src/interface-manager.php'
|
| 52 |
),
|
| 53 |
'Automattic\\Jetpack\\Connection\\Plugin' => array(
|
| 54 |
-
'version' => '1.
|
| 55 |
'path' => $vendorDir . '/automattic/jetpack-connection/src/class-plugin.php'
|
| 56 |
),
|
| 57 |
'Automattic\\Jetpack\\Connection\\Manager' => array(
|
| 58 |
-
'version' => '1.
|
| 59 |
'path' => $vendorDir . '/automattic/jetpack-connection/src/class-manager.php'
|
| 60 |
),
|
| 61 |
'Automattic\\Jetpack\\Connection\\XMLRPC_Connector' => array(
|
| 62 |
-
'version' => '1.
|
| 63 |
'path' => $vendorDir . '/automattic/jetpack-connection/src/class-xmlrpc-connector.php'
|
| 64 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
'Automattic\\Jetpack\\Config' => array(
|
| 66 |
-
'version' => '1.
|
| 67 |
'path' => $vendorDir . '/automattic/jetpack-config/src/class-config.php'
|
| 68 |
),
|
| 69 |
'Jetpack_Options' => array(
|
| 70 |
-
'version' => '1.
|
| 71 |
'path' => $vendorDir . '/automattic/jetpack-options/legacy/class-jetpack-options.php'
|
| 72 |
),
|
| 73 |
'Automattic\\Jetpack\\Roles' => array(
|
| 74 |
-
'version' => '1.0.
|
| 75 |
'path' => $vendorDir . '/automattic/jetpack-roles/src/class-roles.php'
|
| 76 |
),
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
'Automattic\\Jetpack\\Constants' => array(
|
| 78 |
-
'version' => '1.
|
| 79 |
'path' => $vendorDir . '/automattic/jetpack-constants/src/class-constants.php'
|
| 80 |
),
|
| 81 |
);
|
| 15 |
'path' => $vendorDir . '/automattic/jetpack-autoloader/src/CustomAutoloaderPlugin.php'
|
| 16 |
),
|
| 17 |
'Jetpack_XMLRPC_Server' => array(
|
| 18 |
+
'version' => '1.15.2.0',
|
| 19 |
'path' => $vendorDir . '/automattic/jetpack-connection/legacy/class-jetpack-xmlrpc-server.php'
|
| 20 |
),
|
| 21 |
'Jetpack_IXR_Client' => array(
|
| 22 |
+
'version' => '1.15.2.0',
|
| 23 |
'path' => $vendorDir . '/automattic/jetpack-connection/legacy/class-jetpack-ixr-client.php'
|
| 24 |
),
|
| 25 |
'Jetpack_Signature' => array(
|
| 26 |
+
'version' => '1.15.2.0',
|
| 27 |
'path' => $vendorDir . '/automattic/jetpack-connection/legacy/class-jetpack-signature.php'
|
| 28 |
),
|
| 29 |
'Jetpack_IXR_ClientMulticall' => array(
|
| 30 |
+
'version' => '1.15.2.0',
|
| 31 |
'path' => $vendorDir . '/automattic/jetpack-connection/legacy/class-jetpack-ixr-clientmulticall.php'
|
| 32 |
),
|
| 33 |
+
'Automattic\\Jetpack\\Connection\\Error_Handler' => array(
|
| 34 |
+
'version' => '1.15.2.0',
|
| 35 |
+
'path' => $vendorDir . '/automattic/jetpack-connection/src/class-error-handler.php'
|
| 36 |
+
),
|
| 37 |
'Automattic\\Jetpack\\Connection\\REST_Connector' => array(
|
| 38 |
+
'version' => '1.15.2.0',
|
| 39 |
'path' => $vendorDir . '/automattic/jetpack-connection/src/class-rest-connector.php'
|
| 40 |
),
|
| 41 |
'Automattic\\Jetpack\\Connection\\Plugin_Storage' => array(
|
| 42 |
+
'version' => '1.15.2.0',
|
| 43 |
'path' => $vendorDir . '/automattic/jetpack-connection/src/class-plugin-storage.php'
|
| 44 |
),
|
| 45 |
'Automattic\\Jetpack\\Connection\\Client' => array(
|
| 46 |
+
'version' => '1.15.2.0',
|
| 47 |
'path' => $vendorDir . '/automattic/jetpack-connection/src/class-client.php'
|
| 48 |
),
|
| 49 |
'Automattic\\Jetpack\\Connection\\Utils' => array(
|
| 50 |
+
'version' => '1.15.2.0',
|
| 51 |
'path' => $vendorDir . '/automattic/jetpack-connection/src/class-utils.php'
|
| 52 |
),
|
| 53 |
'Automattic\\Jetpack\\Connection\\Manager_Interface' => array(
|
| 54 |
+
'version' => '1.15.2.0',
|
| 55 |
'path' => $vendorDir . '/automattic/jetpack-connection/src/interface-manager.php'
|
| 56 |
),
|
| 57 |
'Automattic\\Jetpack\\Connection\\Plugin' => array(
|
| 58 |
+
'version' => '1.15.2.0',
|
| 59 |
'path' => $vendorDir . '/automattic/jetpack-connection/src/class-plugin.php'
|
| 60 |
),
|
| 61 |
'Automattic\\Jetpack\\Connection\\Manager' => array(
|
| 62 |
+
'version' => '1.15.2.0',
|
| 63 |
'path' => $vendorDir . '/automattic/jetpack-connection/src/class-manager.php'
|
| 64 |
),
|
| 65 |
'Automattic\\Jetpack\\Connection\\XMLRPC_Connector' => array(
|
| 66 |
+
'version' => '1.15.2.0',
|
| 67 |
'path' => $vendorDir . '/automattic/jetpack-connection/src/class-xmlrpc-connector.php'
|
| 68 |
),
|
| 69 |
+
'Automattic\\Jetpack\\Connection\\Error_Handlers\\Invalid_Blog_Token' => array(
|
| 70 |
+
'version' => '1.15.2.0',
|
| 71 |
+
'path' => $vendorDir . '/automattic/jetpack-connection/src/error-handlers/class-invalid-blog-token.php'
|
| 72 |
+
),
|
| 73 |
'Automattic\\Jetpack\\Config' => array(
|
| 74 |
+
'version' => '1.3.0.0',
|
| 75 |
'path' => $vendorDir . '/automattic/jetpack-config/src/class-config.php'
|
| 76 |
),
|
| 77 |
'Jetpack_Options' => array(
|
| 78 |
+
'version' => '1.7.0.0',
|
| 79 |
'path' => $vendorDir . '/automattic/jetpack-options/legacy/class-jetpack-options.php'
|
| 80 |
),
|
| 81 |
'Automattic\\Jetpack\\Roles' => array(
|
| 82 |
+
'version' => '1.2.0.0',
|
| 83 |
'path' => $vendorDir . '/automattic/jetpack-roles/src/class-roles.php'
|
| 84 |
),
|
| 85 |
+
'Automattic\\Jetpack\\Status' => array(
|
| 86 |
+
'version' => '1.3.0.0',
|
| 87 |
+
'path' => $vendorDir . '/automattic/jetpack-status/src/class-status.php'
|
| 88 |
+
),
|
| 89 |
'Automattic\\Jetpack\\Constants' => array(
|
| 90 |
+
'version' => '1.4.0.0',
|
| 91 |
'path' => $vendorDir . '/automattic/jetpack-constants/src/class-constants.php'
|
| 92 |
),
|
| 93 |
);
|
vendor/composer/autoload_files_package.php
CHANGED
|
@@ -7,7 +7,7 @@ $baseDir = dirname($vendorDir);
|
|
| 7 |
|
| 8 |
return array(
|
| 9 |
'bce4ecd6aabb2a2948e06d0e2c4ea9a6' => array(
|
| 10 |
-
'version' => '1.
|
| 11 |
'path' => $vendorDir . '/automattic/jetpack-connection/legacy/load-ixr.php'
|
| 12 |
),
|
| 13 |
);
|
| 7 |
|
| 8 |
return array(
|
| 9 |
'bce4ecd6aabb2a2948e06d0e2c4ea9a6' => array(
|
| 10 |
+
'version' => '1.15.2.0',
|
| 11 |
'path' => $vendorDir . '/automattic/jetpack-connection/legacy/load-ixr.php'
|
| 12 |
),
|
| 13 |
);
|
vendor/composer/autoload_real.php
CHANGED
|
@@ -2,7 +2,7 @@
|
|
| 2 |
|
| 3 |
// autoload_real.php @generated by Composer
|
| 4 |
|
| 5 |
-
class
|
| 6 |
{
|
| 7 |
private static $loader;
|
| 8 |
|
|
@@ -13,24 +13,21 @@ class ComposerAutoloaderInita2447e0d68af485c4e75e9838c0a2df4
|
|
| 13 |
}
|
| 14 |
}
|
| 15 |
|
| 16 |
-
/**
|
| 17 |
-
* @return \Composer\Autoload\ClassLoader
|
| 18 |
-
*/
|
| 19 |
public static function getLoader()
|
| 20 |
{
|
| 21 |
if (null !== self::$loader) {
|
| 22 |
return self::$loader;
|
| 23 |
}
|
| 24 |
|
| 25 |
-
spl_autoload_register(array('
|
| 26 |
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
| 27 |
-
spl_autoload_unregister(array('
|
| 28 |
|
| 29 |
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
| 30 |
if ($useStaticLoader) {
|
| 31 |
require_once __DIR__ . '/autoload_static.php';
|
| 32 |
|
| 33 |
-
call_user_func(\Composer\Autoload\
|
| 34 |
} else {
|
| 35 |
$map = require __DIR__ . '/autoload_namespaces.php';
|
| 36 |
foreach ($map as $namespace => $path) {
|
|
@@ -51,19 +48,19 @@ class ComposerAutoloaderInita2447e0d68af485c4e75e9838c0a2df4
|
|
| 51 |
$loader->register(true);
|
| 52 |
|
| 53 |
if ($useStaticLoader) {
|
| 54 |
-
$includeFiles = Composer\Autoload\
|
| 55 |
} else {
|
| 56 |
$includeFiles = require __DIR__ . '/autoload_files.php';
|
| 57 |
}
|
| 58 |
foreach ($includeFiles as $fileIdentifier => $file) {
|
| 59 |
-
|
| 60 |
}
|
| 61 |
|
| 62 |
return $loader;
|
| 63 |
}
|
| 64 |
}
|
| 65 |
|
| 66 |
-
function
|
| 67 |
{
|
| 68 |
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
| 69 |
require $file;
|
| 2 |
|
| 3 |
// autoload_real.php @generated by Composer
|
| 4 |
|
| 5 |
+
class ComposerAutoloaderInit0a651f92f6dec0685e6f92fb5fc9b1f9
|
| 6 |
{
|
| 7 |
private static $loader;
|
| 8 |
|
| 13 |
}
|
| 14 |
}
|
| 15 |
|
|
|
|
|
|
|
|
|
|
| 16 |
public static function getLoader()
|
| 17 |
{
|
| 18 |
if (null !== self::$loader) {
|
| 19 |
return self::$loader;
|
| 20 |
}
|
| 21 |
|
| 22 |
+
spl_autoload_register(array('ComposerAutoloaderInit0a651f92f6dec0685e6f92fb5fc9b1f9', 'loadClassLoader'), true, true);
|
| 23 |
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
| 24 |
+
spl_autoload_unregister(array('ComposerAutoloaderInit0a651f92f6dec0685e6f92fb5fc9b1f9', 'loadClassLoader'));
|
| 25 |
|
| 26 |
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
| 27 |
if ($useStaticLoader) {
|
| 28 |
require_once __DIR__ . '/autoload_static.php';
|
| 29 |
|
| 30 |
+
call_user_func(\Composer\Autoload\ComposerStaticInit0a651f92f6dec0685e6f92fb5fc9b1f9::getInitializer($loader));
|
| 31 |
} else {
|
| 32 |
$map = require __DIR__ . '/autoload_namespaces.php';
|
| 33 |
foreach ($map as $namespace => $path) {
|
| 48 |
$loader->register(true);
|
| 49 |
|
| 50 |
if ($useStaticLoader) {
|
| 51 |
+
$includeFiles = Composer\Autoload\ComposerStaticInit0a651f92f6dec0685e6f92fb5fc9b1f9::$files;
|
| 52 |
} else {
|
| 53 |
$includeFiles = require __DIR__ . '/autoload_files.php';
|
| 54 |
}
|
| 55 |
foreach ($includeFiles as $fileIdentifier => $file) {
|
| 56 |
+
composerRequire0a651f92f6dec0685e6f92fb5fc9b1f9($fileIdentifier, $file);
|
| 57 |
}
|
| 58 |
|
| 59 |
return $loader;
|
| 60 |
}
|
| 61 |
}
|
| 62 |
|
| 63 |
+
function composerRequire0a651f92f6dec0685e6f92fb5fc9b1f9($fileIdentifier, $file)
|
| 64 |
{
|
| 65 |
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
|
| 66 |
require $file;
|
vendor/composer/autoload_static.php
CHANGED
|
@@ -4,7 +4,7 @@
|
|
| 4 |
|
| 5 |
namespace Composer\Autoload;
|
| 6 |
|
| 7 |
-
class
|
| 8 |
{
|
| 9 |
public static $files = array (
|
| 10 |
'bce4ecd6aabb2a2948e06d0e2c4ea9a6' => __DIR__ . '/..' . '/automattic/jetpack-connection/legacy/load-ixr.php',
|
|
@@ -27,6 +27,8 @@ class ComposerStaticInita2447e0d68af485c4e75e9838c0a2df4
|
|
| 27 |
public static $classMap = array (
|
| 28 |
'Automattic\\Jetpack\\Config' => __DIR__ . '/..' . '/automattic/jetpack-config/src/class-config.php',
|
| 29 |
'Automattic\\Jetpack\\Connection\\Client' => __DIR__ . '/..' . '/automattic/jetpack-connection/src/class-client.php',
|
|
|
|
|
|
|
| 30 |
'Automattic\\Jetpack\\Connection\\Manager' => __DIR__ . '/..' . '/automattic/jetpack-connection/src/class-manager.php',
|
| 31 |
'Automattic\\Jetpack\\Connection\\Manager_Interface' => __DIR__ . '/..' . '/automattic/jetpack-connection/src/interface-manager.php',
|
| 32 |
'Automattic\\Jetpack\\Connection\\Plugin' => __DIR__ . '/..' . '/automattic/jetpack-connection/src/class-plugin.php',
|
|
@@ -36,6 +38,7 @@ class ComposerStaticInita2447e0d68af485c4e75e9838c0a2df4
|
|
| 36 |
'Automattic\\Jetpack\\Connection\\XMLRPC_Connector' => __DIR__ . '/..' . '/automattic/jetpack-connection/src/class-xmlrpc-connector.php',
|
| 37 |
'Automattic\\Jetpack\\Constants' => __DIR__ . '/..' . '/automattic/jetpack-constants/src/class-constants.php',
|
| 38 |
'Automattic\\Jetpack\\Roles' => __DIR__ . '/..' . '/automattic/jetpack-roles/src/class-roles.php',
|
|
|
|
| 39 |
'Jetpack_IXR_Client' => __DIR__ . '/..' . '/automattic/jetpack-connection/legacy/class-jetpack-ixr-client.php',
|
| 40 |
'Jetpack_IXR_ClientMulticall' => __DIR__ . '/..' . '/automattic/jetpack-connection/legacy/class-jetpack-ixr-clientmulticall.php',
|
| 41 |
'Jetpack_Options' => __DIR__ . '/..' . '/automattic/jetpack-options/legacy/class-jetpack-options.php',
|
|
@@ -46,9 +49,9 @@ class ComposerStaticInita2447e0d68af485c4e75e9838c0a2df4
|
|
| 46 |
public static function getInitializer(ClassLoader $loader)
|
| 47 |
{
|
| 48 |
return \Closure::bind(function () use ($loader) {
|
| 49 |
-
$loader->prefixLengthsPsr4 =
|
| 50 |
-
$loader->prefixDirsPsr4 =
|
| 51 |
-
$loader->classMap =
|
| 52 |
|
| 53 |
}, null, ClassLoader::class);
|
| 54 |
}
|
| 4 |
|
| 5 |
namespace Composer\Autoload;
|
| 6 |
|
| 7 |
+
class ComposerStaticInit0a651f92f6dec0685e6f92fb5fc9b1f9
|
| 8 |
{
|
| 9 |
public static $files = array (
|
| 10 |
'bce4ecd6aabb2a2948e06d0e2c4ea9a6' => __DIR__ . '/..' . '/automattic/jetpack-connection/legacy/load-ixr.php',
|
| 27 |
public static $classMap = array (
|
| 28 |
'Automattic\\Jetpack\\Config' => __DIR__ . '/..' . '/automattic/jetpack-config/src/class-config.php',
|
| 29 |
'Automattic\\Jetpack\\Connection\\Client' => __DIR__ . '/..' . '/automattic/jetpack-connection/src/class-client.php',
|
| 30 |
+
'Automattic\\Jetpack\\Connection\\Error_Handler' => __DIR__ . '/..' . '/automattic/jetpack-connection/src/class-error-handler.php',
|
| 31 |
+
'Automattic\\Jetpack\\Connection\\Error_Handlers\\Invalid_Blog_Token' => __DIR__ . '/..' . '/automattic/jetpack-connection/src/error-handlers/class-invalid-blog-token.php',
|
| 32 |
'Automattic\\Jetpack\\Connection\\Manager' => __DIR__ . '/..' . '/automattic/jetpack-connection/src/class-manager.php',
|
| 33 |
'Automattic\\Jetpack\\Connection\\Manager_Interface' => __DIR__ . '/..' . '/automattic/jetpack-connection/src/interface-manager.php',
|
| 34 |
'Automattic\\Jetpack\\Connection\\Plugin' => __DIR__ . '/..' . '/automattic/jetpack-connection/src/class-plugin.php',
|
| 38 |
'Automattic\\Jetpack\\Connection\\XMLRPC_Connector' => __DIR__ . '/..' . '/automattic/jetpack-connection/src/class-xmlrpc-connector.php',
|
| 39 |
'Automattic\\Jetpack\\Constants' => __DIR__ . '/..' . '/automattic/jetpack-constants/src/class-constants.php',
|
| 40 |
'Automattic\\Jetpack\\Roles' => __DIR__ . '/..' . '/automattic/jetpack-roles/src/class-roles.php',
|
| 41 |
+
'Automattic\\Jetpack\\Status' => __DIR__ . '/..' . '/automattic/jetpack-status/src/class-status.php',
|
| 42 |
'Jetpack_IXR_Client' => __DIR__ . '/..' . '/automattic/jetpack-connection/legacy/class-jetpack-ixr-client.php',
|
| 43 |
'Jetpack_IXR_ClientMulticall' => __DIR__ . '/..' . '/automattic/jetpack-connection/legacy/class-jetpack-ixr-clientmulticall.php',
|
| 44 |
'Jetpack_Options' => __DIR__ . '/..' . '/automattic/jetpack-options/legacy/class-jetpack-options.php',
|
| 49 |
public static function getInitializer(ClassLoader $loader)
|
| 50 |
{
|
| 51 |
return \Closure::bind(function () use ($loader) {
|
| 52 |
+
$loader->prefixLengthsPsr4 = ComposerStaticInit0a651f92f6dec0685e6f92fb5fc9b1f9::$prefixLengthsPsr4;
|
| 53 |
+
$loader->prefixDirsPsr4 = ComposerStaticInit0a651f92f6dec0685e6f92fb5fc9b1f9::$prefixDirsPsr4;
|
| 54 |
+
$loader->classMap = ComposerStaticInit0a651f92f6dec0685e6f92fb5fc9b1f9::$classMap;
|
| 55 |
|
| 56 |
}, null, ClassLoader::class);
|
| 57 |
}
|
vendor/composer/installed.json
CHANGED
|
@@ -39,20 +39,20 @@
|
|
| 39 |
},
|
| 40 |
{
|
| 41 |
"name": "automattic/jetpack-config",
|
| 42 |
-
"version": "v1.
|
| 43 |
-
"version_normalized": "1.
|
| 44 |
"source": {
|
| 45 |
"type": "git",
|
| 46 |
"url": "https://github.com/Automattic/jetpack-config.git",
|
| 47 |
-
"reference": "
|
| 48 |
},
|
| 49 |
"dist": {
|
| 50 |
"type": "zip",
|
| 51 |
-
"url": "https://api.github.com/repos/Automattic/jetpack-config/zipball/
|
| 52 |
-
"reference": "
|
| 53 |
"shasum": ""
|
| 54 |
},
|
| 55 |
-
"time": "2020-
|
| 56 |
"type": "library",
|
| 57 |
"installation-source": "dist",
|
| 58 |
"autoload": {
|
|
@@ -68,29 +68,31 @@
|
|
| 68 |
},
|
| 69 |
{
|
| 70 |
"name": "automattic/jetpack-connection",
|
| 71 |
-
"version": "v1.
|
| 72 |
-
"version_normalized": "1.
|
| 73 |
"source": {
|
| 74 |
"type": "git",
|
| 75 |
"url": "https://github.com/Automattic/jetpack-connection.git",
|
| 76 |
-
"reference": "
|
| 77 |
},
|
| 78 |
"dist": {
|
| 79 |
"type": "zip",
|
| 80 |
-
"url": "https://api.github.com/repos/Automattic/jetpack-connection/zipball/
|
| 81 |
-
"reference": "
|
| 82 |
"shasum": ""
|
| 83 |
},
|
| 84 |
"require": {
|
| 85 |
-
"automattic/jetpack-constants": "1.
|
| 86 |
-
"automattic/jetpack-options": "1.
|
| 87 |
-
"automattic/jetpack-roles": "1.0
|
|
|
|
| 88 |
},
|
| 89 |
"require-dev": {
|
|
|
|
| 90 |
"php-mock/php-mock": "^2.1",
|
| 91 |
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5"
|
| 92 |
},
|
| 93 |
-
"time": "2020-
|
| 94 |
"type": "library",
|
| 95 |
"installation-source": "dist",
|
| 96 |
"autoload": {
|
|
@@ -110,24 +112,24 @@
|
|
| 110 |
},
|
| 111 |
{
|
| 112 |
"name": "automattic/jetpack-constants",
|
| 113 |
-
"version": "v1.
|
| 114 |
-
"version_normalized": "1.
|
| 115 |
"source": {
|
| 116 |
"type": "git",
|
| 117 |
"url": "https://github.com/Automattic/jetpack-constants.git",
|
| 118 |
-
"reference": "
|
| 119 |
},
|
| 120 |
"dist": {
|
| 121 |
"type": "zip",
|
| 122 |
-
"url": "https://api.github.com/repos/Automattic/jetpack-constants/zipball/
|
| 123 |
-
"reference": "
|
| 124 |
"shasum": ""
|
| 125 |
},
|
| 126 |
"require-dev": {
|
| 127 |
"php-mock/php-mock": "^2.1",
|
| 128 |
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5"
|
| 129 |
},
|
| 130 |
-
"time": "2020-
|
| 131 |
"type": "library",
|
| 132 |
"installation-source": "dist",
|
| 133 |
"autoload": {
|
|
@@ -143,27 +145,27 @@
|
|
| 143 |
},
|
| 144 |
{
|
| 145 |
"name": "automattic/jetpack-options",
|
| 146 |
-
"version": "v1.
|
| 147 |
-
"version_normalized": "1.
|
| 148 |
"source": {
|
| 149 |
"type": "git",
|
| 150 |
"url": "https://github.com/Automattic/jetpack-options.git",
|
| 151 |
-
"reference": "
|
| 152 |
},
|
| 153 |
"dist": {
|
| 154 |
"type": "zip",
|
| 155 |
-
"url": "https://api.github.com/repos/Automattic/jetpack-options/zipball/
|
| 156 |
-
"reference": "
|
| 157 |
"shasum": ""
|
| 158 |
},
|
| 159 |
"require": {
|
| 160 |
-
"automattic/jetpack-constants": "1.
|
| 161 |
},
|
| 162 |
"require-dev": {
|
| 163 |
"10up/wp_mock": "0.4.2",
|
| 164 |
"phpunit/phpunit": "7.*.*"
|
| 165 |
},
|
| 166 |
-
"time": "2020-
|
| 167 |
"type": "library",
|
| 168 |
"installation-source": "dist",
|
| 169 |
"autoload": {
|
|
@@ -179,24 +181,24 @@
|
|
| 179 |
},
|
| 180 |
{
|
| 181 |
"name": "automattic/jetpack-roles",
|
| 182 |
-
"version": "v1.0
|
| 183 |
-
"version_normalized": "1.0.
|
| 184 |
"source": {
|
| 185 |
"type": "git",
|
| 186 |
"url": "https://github.com/Automattic/jetpack-roles.git",
|
| 187 |
-
"reference": "
|
| 188 |
},
|
| 189 |
"dist": {
|
| 190 |
"type": "zip",
|
| 191 |
-
"url": "https://api.github.com/repos/Automattic/jetpack-roles/zipball/
|
| 192 |
-
"reference": "
|
| 193 |
"shasum": ""
|
| 194 |
},
|
| 195 |
"require-dev": {
|
| 196 |
"php-mock/php-mock": "^2.1",
|
| 197 |
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5"
|
| 198 |
},
|
| 199 |
-
"time": "
|
| 200 |
"type": "library",
|
| 201 |
"installation-source": "dist",
|
| 202 |
"autoload": {
|
|
@@ -209,5 +211,39 @@
|
|
| 209 |
"GPL-2.0-or-later"
|
| 210 |
],
|
| 211 |
"description": "Utilities, related with user roles and capabilities."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 212 |
}
|
| 213 |
]
|
| 39 |
},
|
| 40 |
{
|
| 41 |
"name": "automattic/jetpack-config",
|
| 42 |
+
"version": "v1.3.0",
|
| 43 |
+
"version_normalized": "1.3.0.0",
|
| 44 |
"source": {
|
| 45 |
"type": "git",
|
| 46 |
"url": "https://github.com/Automattic/jetpack-config.git",
|
| 47 |
+
"reference": "a7ae4b6f32c964fb7ea0f715aa5ba272a1f06113"
|
| 48 |
},
|
| 49 |
"dist": {
|
| 50 |
"type": "zip",
|
| 51 |
+
"url": "https://api.github.com/repos/Automattic/jetpack-config/zipball/a7ae4b6f32c964fb7ea0f715aa5ba272a1f06113",
|
| 52 |
+
"reference": "a7ae4b6f32c964fb7ea0f715aa5ba272a1f06113",
|
| 53 |
"shasum": ""
|
| 54 |
},
|
| 55 |
+
"time": "2020-06-26T07:31:13+00:00",
|
| 56 |
"type": "library",
|
| 57 |
"installation-source": "dist",
|
| 58 |
"autoload": {
|
| 68 |
},
|
| 69 |
{
|
| 70 |
"name": "automattic/jetpack-connection",
|
| 71 |
+
"version": "v1.15.2",
|
| 72 |
+
"version_normalized": "1.15.2.0",
|
| 73 |
"source": {
|
| 74 |
"type": "git",
|
| 75 |
"url": "https://github.com/Automattic/jetpack-connection.git",
|
| 76 |
+
"reference": "eff65e640bcec826962475e87dcb236741a2a762"
|
| 77 |
},
|
| 78 |
"dist": {
|
| 79 |
"type": "zip",
|
| 80 |
+
"url": "https://api.github.com/repos/Automattic/jetpack-connection/zipball/eff65e640bcec826962475e87dcb236741a2a762",
|
| 81 |
+
"reference": "eff65e640bcec826962475e87dcb236741a2a762",
|
| 82 |
"shasum": ""
|
| 83 |
},
|
| 84 |
"require": {
|
| 85 |
+
"automattic/jetpack-constants": "1.4.0",
|
| 86 |
+
"automattic/jetpack-options": "1.7.0",
|
| 87 |
+
"automattic/jetpack-roles": "1.2.0",
|
| 88 |
+
"automattic/jetpack-status": "1.3.0"
|
| 89 |
},
|
| 90 |
"require-dev": {
|
| 91 |
+
"automattic/wordbless": "@dev",
|
| 92 |
"php-mock/php-mock": "^2.1",
|
| 93 |
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5"
|
| 94 |
},
|
| 95 |
+
"time": "2020-08-10T15:51:57+00:00",
|
| 96 |
"type": "library",
|
| 97 |
"installation-source": "dist",
|
| 98 |
"autoload": {
|
| 112 |
},
|
| 113 |
{
|
| 114 |
"name": "automattic/jetpack-constants",
|
| 115 |
+
"version": "v1.4.0",
|
| 116 |
+
"version_normalized": "1.4.0.0",
|
| 117 |
"source": {
|
| 118 |
"type": "git",
|
| 119 |
"url": "https://github.com/Automattic/jetpack-constants.git",
|
| 120 |
+
"reference": "b4210d56948529b43785ce31e0055f435eac1f9f"
|
| 121 |
},
|
| 122 |
"dist": {
|
| 123 |
"type": "zip",
|
| 124 |
+
"url": "https://api.github.com/repos/Automattic/jetpack-constants/zipball/b4210d56948529b43785ce31e0055f435eac1f9f",
|
| 125 |
+
"reference": "b4210d56948529b43785ce31e0055f435eac1f9f",
|
| 126 |
"shasum": ""
|
| 127 |
},
|
| 128 |
"require-dev": {
|
| 129 |
"php-mock/php-mock": "^2.1",
|
| 130 |
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5"
|
| 131 |
},
|
| 132 |
+
"time": "2020-07-01T15:55:35+00:00",
|
| 133 |
"type": "library",
|
| 134 |
"installation-source": "dist",
|
| 135 |
"autoload": {
|
| 145 |
},
|
| 146 |
{
|
| 147 |
"name": "automattic/jetpack-options",
|
| 148 |
+
"version": "v1.7.0",
|
| 149 |
+
"version_normalized": "1.7.0.0",
|
| 150 |
"source": {
|
| 151 |
"type": "git",
|
| 152 |
"url": "https://github.com/Automattic/jetpack-options.git",
|
| 153 |
+
"reference": "8006d330476d93a1cb768f30a875f0b17d16f7f6"
|
| 154 |
},
|
| 155 |
"dist": {
|
| 156 |
"type": "zip",
|
| 157 |
+
"url": "https://api.github.com/repos/Automattic/jetpack-options/zipball/8006d330476d93a1cb768f30a875f0b17d16f7f6",
|
| 158 |
+
"reference": "8006d330476d93a1cb768f30a875f0b17d16f7f6",
|
| 159 |
"shasum": ""
|
| 160 |
},
|
| 161 |
"require": {
|
| 162 |
+
"automattic/jetpack-constants": "1.4.0"
|
| 163 |
},
|
| 164 |
"require-dev": {
|
| 165 |
"10up/wp_mock": "0.4.2",
|
| 166 |
"phpunit/phpunit": "7.*.*"
|
| 167 |
},
|
| 168 |
+
"time": "2020-07-28T14:03:34+00:00",
|
| 169 |
"type": "library",
|
| 170 |
"installation-source": "dist",
|
| 171 |
"autoload": {
|
| 181 |
},
|
| 182 |
{
|
| 183 |
"name": "automattic/jetpack-roles",
|
| 184 |
+
"version": "v1.2.0",
|
| 185 |
+
"version_normalized": "1.2.0.0",
|
| 186 |
"source": {
|
| 187 |
"type": "git",
|
| 188 |
"url": "https://github.com/Automattic/jetpack-roles.git",
|
| 189 |
+
"reference": "0148108451db7ee5bfb68669671fc50ddb6d1474"
|
| 190 |
},
|
| 191 |
"dist": {
|
| 192 |
"type": "zip",
|
| 193 |
+
"url": "https://api.github.com/repos/Automattic/jetpack-roles/zipball/0148108451db7ee5bfb68669671fc50ddb6d1474",
|
| 194 |
+
"reference": "0148108451db7ee5bfb68669671fc50ddb6d1474",
|
| 195 |
"shasum": ""
|
| 196 |
},
|
| 197 |
"require-dev": {
|
| 198 |
"php-mock/php-mock": "^2.1",
|
| 199 |
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5"
|
| 200 |
},
|
| 201 |
+
"time": "2020-07-01T15:55:45+00:00",
|
| 202 |
"type": "library",
|
| 203 |
"installation-source": "dist",
|
| 204 |
"autoload": {
|
| 211 |
"GPL-2.0-or-later"
|
| 212 |
],
|
| 213 |
"description": "Utilities, related with user roles and capabilities."
|
| 214 |
+
},
|
| 215 |
+
{
|
| 216 |
+
"name": "automattic/jetpack-status",
|
| 217 |
+
"version": "v1.3.0",
|
| 218 |
+
"version_normalized": "1.3.0.0",
|
| 219 |
+
"source": {
|
| 220 |
+
"type": "git",
|
| 221 |
+
"url": "https://github.com/Automattic/jetpack-status.git",
|
| 222 |
+
"reference": "09bd04d677832f348d3b9d520eecd856c2f0cafb"
|
| 223 |
+
},
|
| 224 |
+
"dist": {
|
| 225 |
+
"type": "zip",
|
| 226 |
+
"url": "https://api.github.com/repos/Automattic/jetpack-status/zipball/09bd04d677832f348d3b9d520eecd856c2f0cafb",
|
| 227 |
+
"reference": "09bd04d677832f348d3b9d520eecd856c2f0cafb",
|
| 228 |
+
"shasum": ""
|
| 229 |
+
},
|
| 230 |
+
"require-dev": {
|
| 231 |
+
"brain/monkey": "2.4.0",
|
| 232 |
+
"php-mock/php-mock": "^2.1",
|
| 233 |
+
"phpunit/phpunit": "^5.7 || ^6.5 || ^7.5"
|
| 234 |
+
},
|
| 235 |
+
"time": "2020-07-28T08:21:54+00:00",
|
| 236 |
+
"type": "library",
|
| 237 |
+
"installation-source": "dist",
|
| 238 |
+
"autoload": {
|
| 239 |
+
"classmap": [
|
| 240 |
+
"src/"
|
| 241 |
+
]
|
| 242 |
+
},
|
| 243 |
+
"notification-url": "https://packagist.org/downloads/",
|
| 244 |
+
"license": [
|
| 245 |
+
"GPL-2.0-or-later"
|
| 246 |
+
],
|
| 247 |
+
"description": "Used to retrieve information about the current status of Jetpack and the site overall."
|
| 248 |
}
|
| 249 |
]
|
woocommerce-payments.php
CHANGED
|
@@ -8,9 +8,9 @@
|
|
| 8 |
* Text Domain: woocommerce-payments
|
| 9 |
* Domain Path: /languages
|
| 10 |
* WC requires at least: 4.0
|
| 11 |
-
* WC tested up to: 4.
|
| 12 |
* Requires WP: 5.3
|
| 13 |
-
* Version: 1.
|
| 14 |
*
|
| 15 |
* @package WooCommerce\Payments
|
| 16 |
*/
|
|
@@ -29,6 +29,9 @@ require_once WCPAY_ABSPATH . 'vendor/autoload_packages.php';
|
|
| 29 |
* Initialize the Jetpack connection functionality.
|
| 30 |
*/
|
| 31 |
function wcpay_jetpack_init() {
|
|
|
|
|
|
|
|
|
|
| 32 |
$jetpack_config = new Automattic\Jetpack\Config();
|
| 33 |
$jetpack_config->ensure(
|
| 34 |
'connection',
|
|
@@ -52,4 +55,34 @@ function wcpay_init() {
|
|
| 52 |
}
|
| 53 |
|
| 54 |
// Make sure this is run *after* WooCommerce has a chance to initialize its packages (wc-admin, etc). That is run with priority 10.
|
|
|
|
| 55 |
add_action( 'plugins_loaded', 'wcpay_init', 11 );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
* Text Domain: woocommerce-payments
|
| 9 |
* Domain Path: /languages
|
| 10 |
* WC requires at least: 4.0
|
| 11 |
+
* WC tested up to: 4.4
|
| 12 |
* Requires WP: 5.3
|
| 13 |
+
* Version: 1.4.0
|
| 14 |
*
|
| 15 |
* @package WooCommerce\Payments
|
| 16 |
*/
|
| 29 |
* Initialize the Jetpack connection functionality.
|
| 30 |
*/
|
| 31 |
function wcpay_jetpack_init() {
|
| 32 |
+
if ( ! wcpay_check_old_jetpack_version() ) {
|
| 33 |
+
return;
|
| 34 |
+
}
|
| 35 |
$jetpack_config = new Automattic\Jetpack\Config();
|
| 36 |
$jetpack_config->ensure(
|
| 37 |
'connection',
|
| 55 |
}
|
| 56 |
|
| 57 |
// Make sure this is run *after* WooCommerce has a chance to initialize its packages (wc-admin, etc). That is run with priority 10.
|
| 58 |
+
// If you change the priority of this action, you'll need to change it in the wcpay_check_old_jetpack_version function too.
|
| 59 |
add_action( 'plugins_loaded', 'wcpay_init', 11 );
|
| 60 |
+
|
| 61 |
+
/**
|
| 62 |
+
* Check if WCPay is installed alongside an old version of Jetpack (8.1 or earlier). Due to the autoloader code in those old
|
| 63 |
+
* versions, the Jetpack Config initialization code would just crash the site.
|
| 64 |
+
* TODO: Remove this when Jetpack 8.1 (Released on January 2020) is so old we don't think anyone will run into this problem anymore.
|
| 65 |
+
*
|
| 66 |
+
* @return bool True if the plugin can keep initializing itself, false otherwise.
|
| 67 |
+
*/
|
| 68 |
+
function wcpay_check_old_jetpack_version() {
|
| 69 |
+
if ( defined( 'JETPACK__VERSION' ) && version_compare( JETPACK__VERSION, '8.2', '<' ) ) {
|
| 70 |
+
add_filter( 'admin_notices', 'wcpay_show_old_jetpack_notice' );
|
| 71 |
+
// Prevent the rest of the plugin from initializing.
|
| 72 |
+
remove_action( 'plugins_loaded', 'wcpay_init', 11 );
|
| 73 |
+
return false;
|
| 74 |
+
}
|
| 75 |
+
return true;
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
/**
|
| 79 |
+
* Display an error notice if the installed Jetpack version is too old to even start initializing the plugin.
|
| 80 |
+
*/
|
| 81 |
+
function wcpay_show_old_jetpack_notice() {
|
| 82 |
+
?>
|
| 83 |
+
<div class="notice wcpay-notice notice-error">
|
| 84 |
+
<p><b><?php echo esc_html( __( 'WooCommerce Payments', 'woocommerce-payments' ) ); ?></b></p>
|
| 85 |
+
<p><?php echo esc_html( __( 'The version of Jetpack installed is too old to be used with WooCommerce Payments. WooCommerce Payments has been disabled. Please deactivate or update Jetpack.', 'woocommerce-payments' ) ); ?></p>
|
| 86 |
+
</div>
|
| 87 |
+
<?php
|
| 88 |
+
}
|
