Merge branch 'trunk' into pcp-307-fee

This commit is contained in:
dinamiko 2022-02-23 10:06:11 +01:00
commit d86fdc35ff
87 changed files with 1550 additions and 542 deletions

View file

@ -1,8 +1,10 @@
*** Changelog ***
= 1.7.0 - TBD =
* Fix - DCC orders randomly failing #503
* Fix - Multi-currency broke #481
* Fix - Address information from PayPal shortcut flow not loaded #451
* Fix - WooCommerce as mu-plugin is not detected as active #461
* Enhancement - Improve onboarding flow, allow no card processing #443
* Enhancement - Add Germany to supported ACDC countries #459
* Enhancement - Add filters to allow ACDC for countries #437
@ -12,6 +14,8 @@
* Enhancement - Pass address details to credit card fields #479
* Enhancement - Improve onboarding notice #465
* Enhancement - Add transaction ID to WC order and order note when refund is received #473
* Enhancement - Asset caching may cause bugs on upgrades #501
* Enhancement - Allow partial capture #483
= 1.6.5 - 2022-01-31 =
* Fix - Allow guest users to purchase subscription products from checkout page #422

View file

@ -12,7 +12,10 @@
"dhii/containers": "^0.1.0-alpha1",
"psr/log": "^1.1",
"ralouphie/getallheaders": "^3.0",
"wikimedia/composer-merge-plugin": "^1.4"
"wikimedia/composer-merge-plugin": "^1.4",
"wp-oop/wordpress-interface": "^0.1.0-alpha1",
"dhii/versions": "^0.1.0-alpha1",
"symfony/polyfill-php80": "^1.19"
},
"require-dev": {
"woocommerce/woocommerce-sniffs": "^0.1.0",

869
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -25,6 +25,9 @@ class Repository implements RepositoryInterface {
*/
public function current_message(): array {
return array_filter(
/**
* Returns the list of admin messages.
*/
(array) apply_filters(
self::NOTICES_FILTER,
array()

View file

@ -422,6 +422,9 @@ return array(
* The matrix which countries and currency combinations can be used for DCC.
*/
'api.dcc-supported-country-currency-matrix' => static function ( ContainerInterface $container ) : array {
/**
* Returns which countries and currency combinations can be used for DCC.
*/
return apply_filters(
'woocommerce_paypal_payments_supported_country_currency_matrix',
array(
@ -567,6 +570,9 @@ return array(
* Which countries support which credit cards. Empty credit card arrays mean no restriction on currency.
*/
'api.dcc-supported-country-card-matrix' => static function ( ContainerInterface $container ) : array {
/**
* Returns which countries support which credit cards. Empty credit card arrays mean no restriction on currency.
*/
return apply_filters(
'woocommerce_paypal_payments_supported_country_card_matrix',
array(

View file

@ -12,6 +12,7 @@ namespace WooCommerce\PayPalCommerce\ApiClient\Endpoint;
use WooCommerce\PayPalCommerce\ApiClient\Authentication\Bearer;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Authorization;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Capture;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Refund;
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
@ -146,22 +147,32 @@ class PaymentsEndpoint {
/**
* Capture an authorization by a given ID.
*
* @param string $authorization_id The id.
* @param string $authorization_id The id.
* @param Money|null $amount The amount to capture. If not specified, the whole authorized amount is captured.
*
* @return Capture
* @throws RuntimeException If the request fails.
* @throws PayPalApiException If the request fails.
*/
public function capture( string $authorization_id ): Capture {
public function capture( string $authorization_id, ?Money $amount = null ): Capture {
$bearer = $this->bearer->bearer();
$url = trailingslashit( $this->host ) . 'v2/payments/authorizations/' . $authorization_id . '/capture';
$args = array(
$data = array(
'final_capture' => true,
);
if ( $amount ) {
$data['amount'] = $amount->to_array();
}
$args = array(
'method' => 'POST',
'headers' => array(
'Authorization' => 'Bearer ' . $bearer->token(),
'Content-Type' => 'application/json',
'Prefer' => 'return=representation',
),
'body' => wp_json_encode( $data, JSON_FORCE_OBJECT ),
);
$response = $this->request( $url, $args );

View file

@ -105,6 +105,9 @@ class PaymentToken {
* @return array
*/
public static function get_valid_types() {
/**
* Returns a list of valid payment token types.
*/
return apply_filters(
'woocommerce_paypal_payments_valid_payment_token_types',
array(

View file

@ -55,10 +55,12 @@ class PayerFactory {
$national_number = preg_replace( '/[^0-9]/', '', $national_number );
$national_number = substr( $national_number, 0, 14 );
$phone = new PhoneWithType(
'HOME',
new Phone( $national_number )
);
if ( $national_number ) {
$phone = new PhoneWithType(
'HOME',
new Phone( $national_number )
);
}
}
return new Payer(
new PayerName(
@ -91,10 +93,12 @@ class PayerFactory {
$national_number = preg_replace( '/[^0-9]/', '', $national_number );
$national_number = substr( $national_number, 0, 14 );
$phone = new PhoneWithType(
'HOME',
new Phone( $national_number )
);
if ( $national_number ) {
$phone = new PhoneWithType(
'HOME',
new Phone( $national_number )
);
}
}
return new Payer(
new PayerName(
@ -176,10 +180,12 @@ class PayerFactory {
if ( null !== $national_number ) {
$national_number = substr( $national_number, 0, 14 );
$phone = new PhoneWithType(
'HOME',
new Phone( $national_number )
);
if ( $national_number ) {
$phone = new PhoneWithType(
'HOME',
new Phone( $national_number )
);
}
}
}

View file

@ -134,6 +134,9 @@ class PurchaseUnitFactory {
$invoice_id,
$soft_descriptor
);
/**
* Returns PurchaseUnit for the WC order.
*/
return apply_filters(
'woocommerce_paypal_payments_purchase_unit_from_wc_order',
$purchase_unit,

View file

@ -74,7 +74,10 @@ class ApplicationContextRepository {
$parts = explode( '-', $locale );
if ( count( $parts ) === 3 ) {
return substr( $locale, 0, strrpos( $locale, '-' ) );
$ret = substr( $locale, 0, strrpos( $locale, '-' ) );
if ( false !== $ret ) {
return $ret;
}
}
return 'en';

View file

@ -45,6 +45,8 @@ class CustomerRepository {
}
$unique_id = substr( $this->prefix . strrev( uniqid() ), 0, self::CLIENT_ID_MAX_LENGTH );
assert( is_string( $unique_id ) );
WC()->session->set( 'ppcp_guest_customer_id', $unique_id );
return $unique_id;

View file

@ -75,10 +75,16 @@ class PartnerReferralsData {
return array(
'partner_config_override' => array(
'partner_logo_url' => 'https://connect.woocommerce.com/images/woocommerce_logo.png',
/**
* Returns the URL which will be opened at the end of onboarding.
*/
'return_url' => apply_filters(
'woocommerce_paypal_payments_partner_config_override_return_url',
admin_url( 'admin.php?page=wc-settings&tab=checkout&section=ppcp-gateway' )
),
/**
* Returns the description of the URL which will be opened at the end of onboarding.
*/
'return_url_description' => apply_filters(
'woocommerce_paypal_payments_partner_config_override_return_url_description',
__( 'Return to your shop.', 'woocommerce-paypal-payments' )

View file

@ -9,7 +9,6 @@ class CreditCardRenderer {
this.cardValid = false;
this.formValid = false;
this.currentHostedFieldsInstance = null;
this.formSubmissionSubscribed = false;
}
render(wrapper, contextConfig) {
@ -122,7 +121,7 @@ class CreditCardRenderer {
});
if (!this.formSubmissionSubscribed) {
if (document.querySelector(wrapper).getAttribute('data-ppcp-subscribed') !== true) {
document.querySelector(wrapper + ' button').addEventListener(
'click',
event => {
@ -130,7 +129,8 @@ class CreditCardRenderer {
this._submit(contextConfig);
}
);
this.formSubmissionSubscribed = true;
document.querySelector(wrapper).setAttribute('data-ppcp-subscribed', true);
}
});
@ -143,7 +143,7 @@ class CreditCardRenderer {
}
disableFields() {
if( this.currentHostedFieldsInstance) {
if (this.currentHostedFieldsInstance) {
this.currentHostedFieldsInstance.setAttribute({
field: 'number',
attribute: 'disabled'
@ -160,7 +160,7 @@ class CreditCardRenderer {
}
enableFields() {
if( this.currentHostedFieldsInstance) {
if (this.currentHostedFieldsInstance) {
this.currentHostedFieldsInstance.removeAttribute({
field: 'number',
attribute: 'disabled'

View file

@ -73,6 +73,7 @@ return array(
$currency = $container->get( 'api.shop.currency' );
return new SmartButton(
$container->get( 'button.url' ),
$container->get( 'ppcp.asset-version' ),
$container->get( 'session.handler' ),
$settings,
$payer_factory,

View file

@ -44,6 +44,13 @@ class SmartButton implements SmartButtonInterface {
*/
private $module_url;
/**
* The assets version.
*
* @var string
*/
private $version;
/**
* The Session Handler.
*
@ -125,6 +132,7 @@ class SmartButton implements SmartButtonInterface {
* SmartButton constructor.
*
* @param string $module_url The URL to the module.
* @param string $version The assets version.
* @param SessionHandler $session_handler The Session Handler.
* @param Settings $settings The Settings.
* @param PayerFactory $payer_factory The Payer factory.
@ -140,6 +148,7 @@ class SmartButton implements SmartButtonInterface {
*/
public function __construct(
string $module_url,
string $version,
SessionHandler $session_handler,
Settings $settings,
PayerFactory $payer_factory,
@ -155,6 +164,7 @@ class SmartButton implements SmartButtonInterface {
) {
$this->module_url = $module_url;
$this->version = $version;
$this->session_handler = $session_handler;
$this->settings = $settings;
$this->payer_factory = $payer_factory;
@ -406,7 +416,7 @@ class SmartButton implements SmartButtonInterface {
'ppcp-hosted-fields',
untrailingslashit( $this->module_url ) . '/assets/css/hosted-fields.css',
array(),
1
$this->version
);
}
if ( $load_script ) {
@ -414,7 +424,7 @@ class SmartButton implements SmartButtonInterface {
'ppcp-smart-button',
untrailingslashit( $this->module_url ) . '/assets/js/button.js',
array( 'jquery' ),
'1.3.2',
$this->version,
true
);
@ -1012,38 +1022,50 @@ class SmartButton implements SmartButtonInterface {
}
/**
* Return action name PayPal buttons will be rendered at on checkout page.
* Returns the action name that PayPal button will use for rendering on the checkout page.
*
* @return string Action name.
*/
private function checkout_button_renderer_hook(): string {
/**
* The filter returning the action name that PayPal button will use for rendering on the checkout page.
*/
return (string) apply_filters( 'woocommerce_paypal_payments_checkout_button_renderer_hook', 'woocommerce_review_order_after_payment' );
}
/**
* Return action name PayPal DCC button will be rendered at on checkout page.
* Returns the action name that PayPal DCC button will use for rendering on the checkout page.
*
* @return string
*/
private function checkout_dcc_button_renderer_hook(): string {
/**
* The filter returning the action name that PayPal DCC button will use for rendering on the checkout page.
*/
return (string) apply_filters( 'woocommerce_paypal_payments_checkout_dcc_renderer_hook', 'woocommerce_review_order_after_submit' );
}
/**
* Return action name PayPal button and Pay Later message will be rendered at on pay-order page.
* Returns the action name that PayPal button and Pay Later message will use for rendering on the pay-order page.
*
* @return string
*/
private function pay_order_renderer_hook(): string {
/**
* The filter returning the action name that PayPal button and Pay Later message will use for rendering on the pay-order page.
*/
return (string) apply_filters( 'woocommerce_paypal_payments_pay_order_dcc_renderer_hook', 'woocommerce_pay_order_after_submit' );
}
/**
* Return action name PayPal button will be rendered next to Proceed to checkout button (normally displayed in cart).
* Returns action name that PayPal button will use for rendering next to Proceed to checkout button (normally displayed in cart).
*
* @return string
*/
private function proceed_to_checkout_button_renderer_hook(): string {
/**
* The filter returning the action name that PayPal button will use for rendering next to Proceed to checkout button (normally displayed in cart).
*/
return (string) apply_filters(
'woocommerce_paypal_payments_proceed_to_checkout_button_renderer_hook',
'woocommerce_proceed_to_checkout'
@ -1051,11 +1073,14 @@ class SmartButton implements SmartButtonInterface {
}
/**
* Return action name PayPal button will be rendered in the WC mini cart.
* Returns the action name that PayPal button will use for rendering in the WC mini cart.
*
* @return string
*/
private function mini_cart_button_renderer_hook(): string {
/**
* The filter returning the action name that PayPal button will use for rendering in the WC mini cart.
*/
return (string) apply_filters(
'woocommerce_paypal_payments_mini_cart_button_renderer_hook',
'woocommerce_widget_shopping_cart_after_buttons'
@ -1063,11 +1088,14 @@ class SmartButton implements SmartButtonInterface {
}
/**
* Return action name PayPal button and Pay Later message will be rendered at on the single product page.
* Returns the action name that PayPal button and Pay Later message will use for rendering on the single product page.
*
* @return string
*/
private function single_product_renderer_hook(): string {
/**
* The filter returning the action name that PayPal button and Pay Later message will use for rendering on the single product page.
*/
return (string) apply_filters( 'woocommerce_paypal_payments_single_product_renderer_hook', 'woocommerce_single_product_summary' );
}
}

View file

@ -89,6 +89,9 @@ class PPECHelper {
* @return bool
*/
public static function use_ppec_compat_layer_for_subscriptions() {
/**
* The filter returning whether the compatibility layer for PPEC Subscriptions should be initialized.
*/
return ( ! self::is_gateway_available() ) && self::site_has_ppec_subscriptions() && apply_filters( 'woocommerce_paypal_payments_process_legacy_subscriptions', true );
}

View file

@ -59,29 +59,72 @@ ul.ppcp-onboarding-options-sublist {
.ppcp-muted-text {
opacity: 0.6;
font-size: 85%;
}
.ppcp-onboarding-header {
#field-ppcp_onboarading_header > td, #field-ppcp_onboarading_options > td {
padding: 0;
}
.ppcp-onboarding-header, .ppcp-onboarding-cards-options {
display: flex;
width: 1000px;
width: 1200px;
}
.ppcp-onboarding-header-left, .ppcp-onboarding-header-right {
flex: 50%;
}
.ppcp-onboarding-header-right {
text-align: right;
}
.ppcp-onboarding-header h2 {
margin-top: 0;
}
.ppcp-onboarding-header-left img {
height: 60px;
}
.ppcp-onboarding-header-cards img, .ppcp-onboarding-header-paypal-logos img {
margin: 5px;
}
.ppcp-onboarding-header-cards img {
height: 40px;
height: 37px;
}
.ppcp-onboarding-header-paypal-logos img {
height: 45px;
height: 32px;
}
.ppcp-onboarding-cards-options table {
margin-left: 35px;
margin-right: 15px;
}
.ppcp-onboarding-cards-options table td {
padding-top: 2px;
}
.ppcp-onboarding-cards-options table td:first-child {
vertical-align: top;
}
.ppcp-onboarding-cards-options table tr:not(:last-child) td {
padding-bottom: 0;
}
.ppcp-onboarding-cards-options table tr td:first-child {
width: 350px;
}
.ppcp-onboarding-cards-screen {
flex: 1;
align-self: center;
}
.ppcp-onboarding-cards-screen img {
width: 100%;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

View file

@ -85,7 +85,8 @@ const ppcp_onboarding = {
authCode: authCode,
sharedId: sharedId,
nonce: PayPalCommerceGatewayOnboarding.nonce,
env: env
env: env,
acceptCards: document.querySelector('#ppcp-onboarding-accept-cards').checked,
}
)
}
@ -144,6 +145,15 @@ function ppcp_onboarding_productionCallback(...args) {
document.querySelectorAll(ppcpButtonSelectors.join()).forEach(
element => element.style.display = !isExpress ? '' : 'none'
);
const screemImg = document.querySelector('#ppcp-onboarding-cards-screen-img');
if (screemImg) {
const currentRb = Array.from(document.querySelectorAll('#ppcp-onboarding-dcc-options input[type="radio"]'))
.filter(rb => rb.checked)[0] ?? null;
const imgUrl = currentRb.getAttribute('data-screen-url');
screemImg.src = imgUrl;
}
};
const updateManualInputControls = (shown, isSandbox, isAnyEnvOnboarded) => {

View file

@ -131,9 +131,11 @@ return array(
$login_seller_endpoint = $container->get( 'onboarding.endpoint.login-seller' );
return new OnboardingAssets(
$container->get( 'onboarding.url' ),
$container->get( 'ppcp.asset-version' ),
$state,
$container->get( 'onboarding.environment' ),
$login_seller_endpoint
$login_seller_endpoint,
$container->get( 'wcgateway.current-ppcp-settings-page-id' )
);
},
@ -214,7 +216,9 @@ return array(
);
},
'onboarding.render-options' => static function ( ContainerInterface $container ) : OnboardingOptionsRenderer {
return new OnboardingOptionsRenderer();
return new OnboardingOptionsRenderer(
$container->get( 'onboarding.url' )
);
},
'onboarding.rest' => static function( $container ) : OnboardingRESTController {
return new OnboardingRESTController( $container );

View file

@ -12,6 +12,7 @@ namespace WooCommerce\PayPalCommerce\Onboarding\Assets;
use WooCommerce\PayPalCommerce\Onboarding\Endpoint\LoginSellerEndpoint;
use WooCommerce\PayPalCommerce\Onboarding\Environment;
use WooCommerce\PayPalCommerce\Onboarding\State;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
/**
* Class OnboardingAssets
@ -25,6 +26,13 @@ class OnboardingAssets {
*/
private $module_url;
/**
* The assets version.
*
* @var string
*/
private $version;
/**
* The State.
*
@ -46,25 +54,38 @@ class OnboardingAssets {
*/
private $login_seller_endpoint;
/**
* ID of the current PPCP gateway settings page, or empty if it is not such page.
*
* @var string
*/
protected $page_id;
/**
* OnboardingAssets constructor.
*
* @param string $module_url The URL to the module.
* @param string $version The assets version.
* @param State $state The State object.
* @param Environment $environment The Environment.
* @param LoginSellerEndpoint $login_seller_endpoint The LoginSeller endpoint.
* @param string $page_id ID of the current PPCP gateway settings page, or empty if it is not such page.
*/
public function __construct(
string $module_url,
string $version,
State $state,
Environment $environment,
LoginSellerEndpoint $login_seller_endpoint
LoginSellerEndpoint $login_seller_endpoint,
string $page_id
) {
$this->module_url = untrailingslashit( $module_url );
$this->version = $version;
$this->state = $state;
$this->environment = $environment;
$this->login_seller_endpoint = $login_seller_endpoint;
$this->page_id = $page_id;
}
/**
@ -79,14 +100,14 @@ class OnboardingAssets {
'ppcp-onboarding',
$url,
array(),
1
$this->version
);
$url = untrailingslashit( $this->module_url ) . '/assets/js/settings.js';
wp_register_script(
'ppcp-settings',
$url,
array(),
1,
$this->version,
true
);
@ -95,7 +116,7 @@ class OnboardingAssets {
'ppcp-onboarding',
$url,
array( 'jquery' ),
1,
$this->version,
true
);
wp_localize_script(
@ -122,7 +143,7 @@ class OnboardingAssets {
'current_state' => State::get_state_name( $this->state->current_state() ),
'current_env' => $this->environment->current_environment(),
'error_messages' => array(
'no_credentials' => __( 'Enter the credentials.', 'woocommerce-paypal-payments' ),
'no_credentials' => __( 'API credentials must be entered to save the settings.', 'woocommerce-paypal-payments' ),
),
);
}
@ -149,7 +170,6 @@ class OnboardingAssets {
* @return bool
*/
private function should_render_onboarding_script(): bool {
global $current_section;
return 'ppcp-gateway' === $current_section;
return PayPalGateway::ID === $this->page_id;
}
}

View file

@ -128,6 +128,7 @@ class LoginSellerEndpoint implements EndpointInterface {
$this->settings->set( 'sandbox_on', $is_sandbox );
$this->settings->set( 'products_dcc_enabled', null );
$this->settings->persist();
$endpoint = $is_sandbox ? $this->login_seller_sandbox : $this->login_seller_production;
$credentials = $endpoint->credentials_for(
$data['sharedId'],
@ -143,10 +144,30 @@ class LoginSellerEndpoint implements EndpointInterface {
}
$this->settings->set( 'client_secret', $credentials->client_secret );
$this->settings->set( 'client_id', $credentials->client_id );
$accept_cards = (bool) ( $data['acceptCards'] ?? true );
$funding_sources = array();
if ( $this->settings->get( 'disable_funding' ) ) {
$funding_sources = $this->settings->get( 'disable_funding' );
if ( ! is_array( $funding_sources ) ) {
$funding_sources = array();
}
}
if ( $accept_cards ) {
$funding_sources = array_diff( $funding_sources, array( 'card' ) );
} else {
if ( ! in_array( 'card', $funding_sources, true ) ) {
$funding_sources[] = 'card';
}
}
$this->settings->set( 'disable_funding', $funding_sources );
$this->settings->persist();
if ( $this->cache->has( PayPalBearer::CACHE_KEY ) ) {
$this->cache->delete( PayPalBearer::CACHE_KEY );
}
wp_schedule_single_event(
time() + 5,
WebhookRegistrar::EVENT_HOOK

View file

@ -13,6 +13,22 @@ namespace WooCommerce\PayPalCommerce\Onboarding\Render;
* Class OnboardingRenderer
*/
class OnboardingOptionsRenderer {
/**
* The module url.
*
* @var string
*/
private $module_url;
/**
* OnboardingOptionsRenderer constructor.
*
* @param string $module_url The module url (for assets).
*/
public function __construct( string $module_url ) {
$this->module_url = $module_url;
}
/**
* Renders the onboarding options.
*
@ -23,7 +39,7 @@ class OnboardingOptionsRenderer {
<ul class="ppcp-onboarding-options">
<li>
<label><input type="checkbox" disabled checked> ' .
__( 'Accept PayPal, Venmo, Pay Later and local payment methods', 'woocommerce-paypal-payments' ) . '
__( 'Enable PayPal Payments — includes PayPal, Venmo, Pay Later — with fraud protection', 'woocommerce-paypal-payments' ) . '
</label>
</li>
<li>
@ -44,25 +60,140 @@ class OnboardingOptionsRenderer {
$items = array();
if ( $is_shop_supports_dcc ) {
$items[] = '
$dcc_table_rows = array(
$this->render_table_row(
__( 'Credit & Debit Card form fields', 'woocommerce-paypal-payments' ),
__( 'Customizable user experience', 'woocommerce-paypal-payments' )
),
$this->render_table_row(
__( 'Credit & Debit Card pricing', 'woocommerce-paypal-payments' ),
__( '2.59% + $0.49', 'woocommerce-paypal-payments' )
),
$this->render_table_row(
__( 'Seller Protection', 'woocommerce-paypal-payments' ),
__( 'Yes', 'woocommerce-paypal-payments' ),
__( 'No matter what you sell, Seller Protection can help you avoid chargebacks, reversals, and fees on eligible PayPal payment transactions — even when a customer has filed a dispute.', 'woocommerce-paypal-payments' ),
__( 'On eligible PayPal transactions', 'woocommerce-paypal-payments' )
),
$this->render_table_row(
__( 'Advanced Fraud Protection', 'woocommerce-paypal-payments' ),
__( 'Yes', 'woocommerce-paypal-payments' ),
__( 'Included with Advanced Checkout at no extra cost, Fraud Protection gives you the insight and control you need to better balance chargebacks and declines.', 'woocommerce-paypal-payments' )
),
$this->render_table_row(
__( 'Chargeback Protection', 'woocommerce-paypal-payments' ),
__( 'Yes', 'woocommerce-paypal-payments' ),
__( 'If you choose this optional, fee-based alternative to Fraud Protection, PayPal will manage chargebacks for eligible credit and debit card transactions — so you wont have to worry about unexpected costs.', 'woocommerce-paypal-payments' ),
__( 'Extra 0.4% per transaction', 'woocommerce-paypal-payments' )
),
$this->render_table_row(
__( 'Additional Vetting and Underwriting Required', 'woocommerce-paypal-payments' ),
__( 'Yes', 'woocommerce-paypal-payments' ),
__( 'Business Ownership and other business information will be required during the application for Advanced Card Processing.', 'woocommerce-paypal-payments' )
),
$this->render_table_row(
__( 'Seller Account Type', 'woocommerce-paypal-payments' ),
__( 'Business', 'woocommerce-paypal-payments' )
),
);
$items[] = '
<li>
<label><input type="radio" id="ppcp-onboarding-dcc-acdc" name="ppcp_onboarding_dcc" value="acdc" checked> ' .
__( 'Advanced credit and debit card processing', 'woocommerce-paypal-payments' ) . '*<br/> ' .
__( '(With advanced fraud protection and fully customizable card fields)', 'woocommerce-paypal-payments' ) . '
<span class="ppcp-muted-text">*' . __( 'Additional onboarding steps required', 'woocommerce-paypal-payments' ) . '</span>
<label' .
' title="' . __( 'PayPal acts as the payment processor for card transactions. You can add optional features like Chargeback Protection for more security.', 'woocommerce-paypal-payments' ) . '"'
. '>
<input type="radio" id="ppcp-onboarding-dcc-acdc" name="ppcp_onboarding_dcc" value="acdc" checked ' .
'data-screen-url="' . $this->get_screen_url( 'acdc' ) . '"> ' .
__( 'Advanced Card Processing', 'woocommerce-paypal-payments' ) . '
</label>
<table>
' . implode( '', $dcc_table_rows ) . '
</table>
</li>';
}
$items[] = '
<li>
<label><input type="radio" id="ppcp-onboarding-dcc-basic" name="ppcp_onboarding_dcc" value="basic" ' . ( ! $is_shop_supports_dcc ? 'checked' : '' ) . '> ' .
__( 'Basic credit and debit card processing', 'woocommerce-paypal-payments' ) . '
$basic_table_rows = array(
$this->render_table_row(
__( 'Credit & Debit Card form fields', 'woocommerce-paypal-payments' ),
__( 'Prebuilt user experience', 'woocommerce-paypal-payments' )
),
$this->render_table_row(
__( 'Credit & Debit Card pricing', 'woocommerce-paypal-payments' ),
__( '3.49% + $0.49', 'woocommerce-paypal-payments' )
),
$this->render_table_row(
__( 'Seller Protection', 'woocommerce-paypal-payments' ),
__( 'Yes', 'woocommerce-paypal-payments' ),
__( 'No matter what you sell, Seller Protection can help you avoid chargebacks, reversals, and fees on eligible PayPal payment transactions — even when a customer has filed a dispute.', 'woocommerce-paypal-payments' ),
__( 'On eligible PayPal transactions', 'woocommerce-paypal-payments' )
),
$this->render_table_row(
__( 'Seller Account Type', 'woocommerce-paypal-payments' ),
__( 'Business or Personal', 'woocommerce-paypal-payments' ),
__( 'For Standard payments, Casual sellers may connect their Personal PayPal account in eligible countries to sell on WooCommerce. For Advanced payments, a Business PayPal account is required.', 'woocommerce-paypal-payments' )
),
);
$items[] = '
<li ' . ( ! $is_shop_supports_dcc ? 'style="display: none;"' : '' ) . '>
<label ' .
' title="' . __( 'Card transactions are managed by PayPal, which simplifies compliance requirements for you.', 'woocommerce-paypal-payments' ) . '"'
. '>
<input type="radio" id="ppcp-onboarding-dcc-basic" name="ppcp_onboarding_dcc" value="basic" ' .
( ! $is_shop_supports_dcc ? 'checked' : '' ) .
' data-screen-url="' . $this->get_screen_url( 'basic' ) . '"' .
'> ' .
__( 'Standard Card Processing', 'woocommerce-paypal-payments' ) . '
</label>
<table>
' . implode( $basic_table_rows ) . '
</table>
</li>';
return '<ul id="ppcp-onboarding-dcc-options" class="ppcp-onboarding-options-sublist">' .
return '
<div class="ppcp-onboarding-cards-options">
<ul id="ppcp-onboarding-dcc-options" class="ppcp-onboarding-options-sublist">' .
implode( '', $items ) .
'</ul>';
'
</ul>
<div class="ppcp-onboarding-cards-screen">' .
( $is_shop_supports_dcc ? '<img id="ppcp-onboarding-cards-screen-img" />' : '' ) . '
</div>
</div>';
}
/**
* Returns HTML of a row for the cards options tables.
*
* @param string $header The text in the first cell.
* @param string $value The text in the second cell.
* @param string $tooltip The text shown on hover.
* @param string $note The additional description text, such as about conditions.
* @return string
*/
private function render_table_row( string $header, string $value, string $tooltip = '', string $note = '' ): string {
$value_html = $value;
if ( $note ) {
$value_html .= '<br/><span class="ppcp-muted-text">' . $note . '</span>';
}
$row_attributes_html = '';
if ( $tooltip ) {
$row_attributes_html .= 'title="' . $tooltip . '"';
}
return "
<tr $row_attributes_html>
<td>$header</td>
<td>$value_html</td>
</tr>";
}
/**
* Returns the screen image URL.
*
* @param string $key The image suffix, 'acdc' or 'basic'.
* @return string
*/
private function get_screen_url( string $key ): string {
return untrailingslashit( $this->module_url ) . "/assets/images/cards-screen-$key.png";
}
}

View file

@ -102,7 +102,7 @@ class OnboardingRenderer {
$this->render_button(
$this->get_signup_link( $is_production, $products ),
$id,
$is_production ? __( 'Connect with PayPal', 'woocommerce-paypal-payments' ) : __( 'Test payments with PayPal sandbox', 'woocommerce-paypal-payments' ),
$is_production ? __( 'Activate PayPal', 'woocommerce-paypal-payments' ) : __( 'Test payments with PayPal sandbox', 'woocommerce-paypal-payments' ),
$is_production ? 'primary' : 'secondary',
$is_production ? 'production' : 'sandbox'
);

View file

@ -174,6 +174,9 @@ class RenewalHandler {
* @return PaymentToken|null
*/
private function get_token_for_customer( \WC_Customer $customer, \WC_Order $wc_order ) {
/**
* Returns a payment token for a customer, or null.
*/
$token = apply_filters( 'woocommerce_paypal_payments_subscriptions_get_token_for_customer', null, $customer, $wc_order );
if ( null !== $token ) {
return $token;

View file

@ -22,7 +22,8 @@ return array(
},
'vaulting.assets.myaccount-payments' => function( ContainerInterface $container ) : MyAccountPaymentsAssets {
return new MyAccountPaymentsAssets(
$container->get( 'vaulting.module-url' )
$container->get( 'vaulting.module-url' ),
$container->get( 'ppcp.asset-version' )
);
},
'vaulting.payment-tokens-renderer' => static function (): PaymentTokensRenderer {

View file

@ -23,15 +23,25 @@ class MyAccountPaymentsAssets {
*/
private $module_url;
/**
* The assets version.
*
* @var string
*/
private $version;
/**
* MyAccountPaymentsAssets constructor.
*
* @param string $module_url The URL to the module.
* @param string $version The assets version.
*/
public function __construct(
string $module_url
string $module_url,
string $version
) {
$this->module_url = untrailingslashit( $module_url );
$this->version = $version;
}
/**
@ -44,7 +54,7 @@ class MyAccountPaymentsAssets {
'ppcp-vaulting-myaccount-payments',
untrailingslashit( $this->module_url ) . '/assets/js/myaccount-payments.js',
array( 'jquery' ),
'1',
$this->version,
true
);
}

View file

@ -1,10 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="50px" height="50px" viewBox="0 0 50 50" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Amex_acceptancemark_50x50</title>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="Amex_acceptancemark_50x50">
<polygon id="Shape" fill="#FFFFFF" fill-rule="nonzero" points="50 0 0 0 0 50 50 50"></polygon>
<path d="M25.0930414,18.1130368 L21.2948396,18.1130368 L23.1939405,13.5354022 L25.0930414,18.1130368 Z M27.5916246,24.0501324 L31.8892892,24.0501324 L25.7128236,10.0571358 L20.7951652,10.0571358 L14.6182767,24.0501324 L18.8161334,24.0501324 L19.9755555,21.2514908 L26.412114,21.2514908 L27.5916246,24.0501324 Z M46.2218867,24.0501324 L50,24.0501324 L50,10.0571358 L44.1229584,10.0571358 L40.9845044,18.7725731 L37.8661389,10.0571358 L31.8892892,10.0571358 L31.8892892,24.0501324 L35.6671911,24.0501324 L35.6671911,14.255204 L39.2655654,24.0501324 L42.6237239,24.0501324 L46.2218867,14.234904 L46.2218867,24.0501324 Z M23.7946916,36.8350715 L23.7946916,34.6562122 L31.6905191,34.6562122 L31.6905191,31.4978812 L23.7946916,31.4978812 L23.7946916,29.3190219 L31.8903465,29.3190219 L31.8903465,26.0807599 L19.9766128,26.0807599 L19.9766128,40.0733335 L31.8903465,40.0733335 L31.8903465,36.8350715 L23.7946916,36.8350715 Z M46.1576036,33.0427906 L50,37.1306893 L50,28.989148 L46.1576036,33.0427906 Z M44.9840138,40.0733335 L50,40.0733335 L43.3646714,33.0370812 L50,26.0807599 L45.0637333,26.0807599 L40.9661076,30.558375 L36.9078129,26.0807599 L31.8907695,26.0807599 L38.4871899,33.0770467 L31.8907695,40.0733335 L36.7682509,40.0733335 L40.8861766,35.5557529 L44.9840138,40.0733335 Z M50,50 L50,42.0773174 L43.9679599,42.0773174 L40.8622819,38.6432456 L37.7411674,42.0773174 L17.8527325,42.0773174 L17.8527325,26.072513 L11.4335135,26.072513 L19.3957387,8.05336344 L27.0746107,8.05336344 L29.8157358,14.2264457 L29.8157358,8.05336344 L39.3205444,8.05336344 L40.9709711,12.7052196 L42.6319707,8.05336344 L50,8.05336344 L50,0 L0,0 L0,50 L50,50 L50,50 Z" id="Fill-18" fill="#216EA9"></path>
<svg width="134px" height="85px" viewBox="0 0 134 85" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>AmEx Card Icon</title>
<g id="RD-4" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="LP---venmo---social---primary" transform="translate(-824.000000, -1587.000000)">
<g id="AmEx-Card-Icon" transform="translate(824.988647, 1587.578995)">
<rect id="Rectangle" fill="#216EA9" x="0" y="0" width="132.39159" height="83.7921454" rx="4.581738"></rect>
<g id="Amex" transform="translate(11.042625, 26.813487)" fill-rule="nonzero">
<polygon id="path3082" fill="#FFFFFF" points="58.1781633 28.829246 58.1781633 0.111970975 88.752584 0.111970975 92.0328881 4.36473322 95.4216632 0.111970975 111.627357 0.111970975 100.111543 14.3998649 111.627357 28.829246 95.1623158 28.829246 91.8866983 24.4852763 88.560787 28.829246"></polygon>
<polygon id="path3080" fill="#FFFFFF" points="12.9456251 0.111970975 24.8692065 0.111970975 28.7820013 9.06638213 28.7820013 0.111970975 43.6041122 0.111970975 45.933401 6.58395398 48.1915676 0.111970975 83.0100213 0.111970975 83.0100213 28.829228 23.1027999 28.829228 21.2713726 24.3023659 16.3877429 24.3023659 14.5692593 28.829228 0.216820214 28.829228"></polygon>
<path d="M15.3859151,3.6521988 L6.08653439,25.1547742 L12.140911,25.1547742 L13.8567623,20.8489817 L23.8318149,20.8489817 L25.5387763,25.1547742 L31.7265095,25.1547742 L22.436018,3.6521988 L15.3859151,3.6521988 Z M18.8265072,8.6564979 L21.8670326,16.1806509 L15.7770926,16.1806509 L18.8265072,8.6564979 L18.8265072,8.6564979 Z" id="path3046" fill="#216EA9"></path>
<polygon id="path3048" fill="#216EA9" points="32.3666185 25.1511618 32.3666185 3.64856809 40.9702248 3.68034593 45.9743744 17.543851 50.8586955 3.64856809 59.3934994 3.64856809 59.3934994 25.1511618 53.9881232 25.1511618 53.9881232 9.30714548 48.2583106 25.1511618 43.5177841 25.1511618 37.7719947 9.30714548 37.7719947 25.1511618"></polygon>
<polygon id="path3050" fill="#216EA9" points="63.091914 25.1511618 63.091914 3.64856809 80.7305103 3.64856809 80.7305103 8.45836792 68.5541888 8.45836792 68.5541888 12.1364341 80.4460167 12.1364341 80.4460167 16.6632958 68.5541888 16.6632958 68.5541888 20.482831 80.7305103 20.482831 80.7305103 25.1511618"></polygon>
<polygon id="path3066" fill="#216EA9" points="80.1997365 25.1511618 88.7878839 14.5324773 79.9952578 3.64856809 86.80532 3.64856809 92.0417773 10.3769555 97.2960166 3.64856809 103.839367 3.64856809 95.1623158 14.3998648 103.766272 25.1511618 96.9572869 25.1511618 91.8728606 18.5288349 86.9120057 25.1511618"></polygon>
</g>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Before After
Before After

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="88px" height="55px" viewBox="0 0 88 55" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>iDEAL_acceptancemark_80x50</title>
<g id="RD-4" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="LP---venmo---social---primary" transform="translate(-1290.000000, -1489.000000)">
<g id="iDEAL_acceptancemark_80x50" transform="translate(1290.674250, 1489.000000)">
<rect id="Rectangle" fill="#000000" x="0" y="0" width="86.55975" height="54.78165" rx="3.55725"></rect>
<g id="iDeal" transform="translate(19.722475, 8.569431)" fill-rule="nonzero">
<g id="Group-10">
<path d="M1.31483165,0.4147596 L1.31483165,38.542788 L23.6150559,38.542788 C38.3257411,38.542788 44.7042759,30.3306152 44.7042759,19.4407953 C44.7042759,8.59428425 38.3257411,0.4147596 23.6150559,0.4147596 L1.31483165,0.4147596 Z" id="Fill-6" fill="#FFFFFF"></path>
<path d="M24.4089797,0.0145181949 C43.6643857,0.0145181949 46.5394168,12.2271201 46.5394168,19.5055435 C46.5394168,32.133495 38.680567,39.0878016 24.4089797,39.0878016 L0.807144801,39.0878016 L0.807144801,0.0145181949 L24.4089797,0.0145181949 Z M2.66510307,1.8517804 L2.66510307,37.249739 L24.4089797,37.249739 C37.5392931,37.249739 44.6818631,31.2003587 44.6818631,19.5055435 C44.6818631,7.48721161 36.9395275,1.8517804 24.4089797,1.8517804 L2.66510307,1.8517804 Z" id="Fill-8" fill="#000000"></path>
</g>
<polygon id="Fill-11" fill="#000000" points="5.58237061 34.364139 12.5430893 34.364139 12.5430893 22.1081216 5.58237061 22.1081216"></polygon>
<g id="Group-16" transform="translate(4.652482, 4.673437)">
<path d="M8.73559986,11.2615791 C8.73559986,13.6248309 6.79935854,15.5409215 4.40980375,15.5409215 C2.02146263,15.5409215 0.0834007826,13.6248309 0.0834007826,11.2615791 C0.0834007826,8.89992785 2.02146263,6.98303694 4.40980375,6.98303694 C6.79935854,6.98303694 8.73559986,8.89992785 8.73559986,11.2615791" id="Fill-12" fill="#000000"></path>
<path d="M22.3930799,13.2641209 L22.3930799,15.2470356 L17.4327257,15.2470356 L17.4327257,7.28636627 L22.233075,7.28636627 L22.233075,9.26848068 L19.4381473,9.26848068 L19.4381473,10.1914133 L22.0813635,10.1914133 L22.0813635,12.1731276 L19.4381473,12.1731276 L19.4381473,13.2641209 L22.3930799,13.2641209 Z M23.3559412,15.2496365 L25.7841318,7.28296504 L28.6367095,7.28296504 L31.0640911,15.2496365 L28.9767452,15.2496365 L28.5218135,13.708481 L25.8990278,13.708481 L25.4426801,15.2496365 L23.3559412,15.2496365 Z M26.4850382,11.7269668 L27.9356009,11.7269668 L27.2723189,9.47555532 L27.1519613,9.47555532 L26.4850382,11.7269668 Z M32.0714544,7.2831651 L34.0764715,7.2831651 L34.0764715,13.2641209 L37.0477888,13.2641209 C36.2329978,2.4118093 27.6012291,0.0671642083 19.7581572,0.0671642083 L11.3960302,0.0671642083 L11.3960302,7.28736663 L12.6337925,7.28736663 C14.8904481,7.28736663 16.2924632,8.80091216 16.2924632,11.2355897 C16.2924632,13.7476951 14.9242292,15.2470356 12.6337925,15.2470356 L11.3960302,15.2470356 L11.3960302,29.6942429 L19.7581572,29.6942429 C32.5104059,29.6942429 36.9480638,23.8371318 37.1046299,15.2470356 L32.0714544,15.2470356 L32.0714544,7.2831651 Z M11.394412,9.26988119 L11.394412,13.2641209 L12.6337925,13.2641209 C13.492681,13.2641209 14.2858279,13.0186324 14.2858279,11.2355897 C14.2858279,9.49336174 13.4030701,9.26988119 12.6337925,9.26988119 L11.394412,9.26988119 Z" id="Fill-14" fill="#CC0066"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="134px" height="84px" viewBox="0 0 134 84" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Mastercard_acceptancemark_80x50</title>
<g id="RD-4" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="LP---venmo---social---primary" transform="translate(-967.000000, -1489.000000)">
<g id="Mastercard_acceptancemark_80x50" transform="translate(967.005261, 1489.000000)">
<rect id="Rectangle" fill="#000000" x="0" y="0" width="132.39159" height="83.7921454" rx="4.581738"></rect>
<g id="mc_symbol" transform="translate(16.758429, 11.730900)" fill-rule="nonzero">
<rect id="Rectangle" fill="#FF5F00" x="34.961091" y="6.91411461" width="29.2905829" height="48.0845243"></rect>
<path d="M37.978038,30.9606238 C37.9706835,21.5790039 42.2555184,12.7149877 49.5979316,6.92260862 C37.1243267,-2.93038543 19.2117299,-1.49521164 8.44863276,10.2195284 C-2.31446439,21.9342684 -2.31446439,39.9954731 8.44863276,51.7102132 C19.2117299,63.4249532 37.1243267,64.8601271 49.5979316,55.0071329 C42.2531818,49.2129145 37.9680851,40.3452244 37.978038,30.9606238 Z" id="Path" fill="#EB001B"></path>
<path d="M95.9169404,50.3974171 L95.9169404,49.0088616 L96.3394821,49.0088616 L96.3394821,48.7215742 L95.333833,48.7215742 L95.333833,49.0088616 L95.7310222,49.0088616 L95.7310222,50.3974171 L95.9169404,50.3974171 Z M97.8690825,50.3974171 L97.8690825,48.7215742 L97.5648527,48.7215742 L97.2099177,49.9186049 L96.8549827,48.7215742 L96.5507529,48.7215742 L96.5507529,50.3974171 L96.7704745,50.3974171 L96.7704745,49.1285648 L97.1000568,50.2178626 L97.3282294,50.2178626 L97.6578119,49.1285648 L97.6578119,50.3974171 L97.8690825,50.3974171 Z" id="Shape" fill="#F79E1B"></path>
<path d="M98.8240266,30.9606238 C98.8240266,42.6682247 92.1727326,53.3479581 81.695674,58.4641002 C71.2186153,63.5802422 58.7549062,62.2345869 49.5979316,54.9986391 C56.9371412,49.2013423 61.2222985,40.3385046 61.2222985,30.9563768 C61.2222985,21.5742491 56.9371412,12.7114113 49.5979316,6.91411461 C58.7549062,-0.321833201 71.2186153,-1.66748859 81.695674,3.44865344 C92.1727326,8.56479549 98.8240266,19.2445288 98.8240266,30.9521297 L98.8240266,30.9606238 Z" id="Path" fill="#F79E1B"></path>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 17 KiB

BIN
modules/ppcp-wc-gateway/assets/images/paypal.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Before After
Before After

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="133px" height="84px" viewBox="0 0 133 84" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Visa_acceptancemark_80x50</title>
<g id="RD-4" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="LP---venmo---social---primary" transform="translate(-824.000000, -1489.000000)">
<g id="Visa_acceptancemark_80x50" transform="translate(824.000000, 1489.000000)">
<rect id="Rectangle" fill="#1D1C45" x="0" y="0" width="132.39159" height="83.7921454" rx="4.581738"></rect>
<g id="Visa" transform="translate(15.082586, 25.137644)" fill="#FFFFFF" fill-rule="nonzero">
<path d="M51.4455687,0.590854329 L44.5028773,32.8958387 L36.1060355,32.8958387 L43.051613,0.590854329 L51.4455687,0.590854329 Z M86.768489,21.4493529 L91.1881833,9.31960182 L93.7323456,21.4493529 L86.768489,21.4493529 Z M96.1370094,32.8958387 L103.90226,32.8958387 L97.1240809,0.590854329 L89.9581922,0.590854329 C88.3462641,0.590854329 86.9873571,1.5231018 86.3841468,2.96001738 L73.7864787,32.8958387 L82.6003729,32.8958387 L84.3517993,28.0694111 L95.1225193,28.0694111 L96.1370094,32.8958387 Z M74.222772,22.3476047 C74.2602923,13.8223523 62.3788765,13.3516799 62.4606514,9.54224952 C62.486627,8.38400266 63.5949177,7.15249753 66.021709,6.83696026 C67.2228384,6.68086746 70.5404952,6.55972795 74.2987747,8.28201565 L75.7740906,1.43212747 C73.7523257,0.701938773 71.1542883,0 67.9188872,0 C59.6211374,0 53.7795214,4.39166605 53.7328615,10.6779922 C53.6775431,15.3310897 57.9014586,17.9238582 61.0839464,19.4709005 C64.3535004,21.0538539 65.4502465,22.0694147 65.4382207,23.4852625 C65.4136884,25.6538032 62.8291196,26.6095125 60.412911,26.6468598 C56.1918816,26.7124572 53.7420011,25.5111171 51.7899855,24.6056832 L50.2699339,31.6849224 C52.2296459,32.581259 55.8508322,33.3626806 59.6062254,33.4009855 C68.4268539,33.4009855 74.1953534,29.0658194 74.222772,22.3476047 L74.222772,22.3476047 Z M39.4487059,0.590854329 L25.8456873,32.8958387 L16.9711835,32.8958387 L10.2771842,7.11419256 C9.87071473,5.52692991 9.51812048,4.94421538 8.28235702,4.2767511 C6.26444044,3.18553796 2.93187165,2.16279498 0,1.52741111 L0.197702912,0.590854329 L14.4847447,0.590854329 C16.3044774,0.590854329 17.9428621,1.79602479 18.3560659,3.88412506 L21.8916291,22.578392 L30.6300016,0.590854329 L39.4487059,0.590854329 L39.4487059,0.590854329 Z" id="Fill-1"></path>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

View file

@ -285,16 +285,16 @@ return array(
</div>
<div class="ppcp-onboarding-header-right">
<div class="ppcp-onboarding-header-paypal-logos">
<img alt="PayPal" src="' . esc_url( $module_url ) . 'assets/images/paypal-button.png"/>
<img alt="Venmo" src="' . esc_url( $module_url ) . 'assets/images/venmo-button.png"/>
<img alt="Pay Later" src="' . esc_url( $module_url ) . 'assets/images/paylater-button.png"/>
<img alt="PayPal" src="' . esc_url( $module_url ) . 'assets/images/paypal-button.svg"/>
<img alt="Venmo" src="' . esc_url( $module_url ) . 'assets/images/venmo.svg"/>
<img alt="Pay Later" src="' . esc_url( $module_url ) . 'assets/images/paylater.svg"/>
</div>
<div class="ppcp-onboarding-header-cards">
<img alt="Visa" src="' . esc_url( $module_url ) . 'assets/images/visa.svg"/>
<img alt="Mastercard" src="' . esc_url( $module_url ) . 'assets/images/mastercard.svg"/>
<img alt="Visa" src="' . esc_url( $module_url ) . 'assets/images/visa-dark.svg"/>
<img alt="Mastercard" src="' . esc_url( $module_url ) . 'assets/images/mastercard-dark.svg"/>
<img alt="American Express" src="' . esc_url( $module_url ) . 'assets/images/amex.svg"/>
<img alt="Discover" src="' . esc_url( $module_url ) . 'assets/images/discover.svg"/>
<img alt="iDEAL" src="' . esc_url( $module_url ) . 'assets/images/ideal.svg"/>
<img alt="iDEAL" src="' . esc_url( $module_url ) . 'assets/images/ideal-dark.svg"/>
<img alt="Sofort" src="' . esc_url( $module_url ) . 'assets/images/sofort.svg"/>
</div>
</div>
@ -326,7 +326,7 @@ return array(
'state_from' => Environment::SANDBOX,
'requirements' => array(),
'gateway' => 'paypal',
'description' => __( 'Your account is connected to sandbox, no real charging takes place. To accept live payments, disconnect and connect your live PayPal account.', 'woocommerce-paypal-payments' ),
'description' => __( 'Your account is connected to sandbox, no real charging takes place. To accept live payments, turn off sandbox mode and connect your live PayPal account.', 'woocommerce-paypal-payments' ),
),
'ppcp_onboarading_options' => array(
@ -909,6 +909,9 @@ return array(
'type' => 'select',
'class' => array(),
'input_class' => array( 'wc-enhanced-select' ),
/**
* Returns default label ID of the PayPal button.
*/
'default' => apply_filters( 'woocommerce_paypal_payments_button_label_default', 'paypal' ),
'desc_tip' => true,
'description' => __(
@ -1211,6 +1214,9 @@ return array(
'type' => 'select',
'class' => array(),
'input_class' => array( 'wc-enhanced-select' ),
/**
* Returns default label ID of the PayPal button on product pages.
*/
'default' => apply_filters( 'woocommerce_paypal_payments_button_product_label_default', 'paypal' ),
'desc_tip' => true,
'description' => __(
@ -1514,6 +1520,9 @@ return array(
'type' => 'select',
'class' => array(),
'input_class' => array( 'wc-enhanced-select' ),
/**
* Returns default label ID of the PayPal button in cart.
*/
'default' => apply_filters( 'woocommerce_paypal_payments_button_cart_label_default', 'paypal' ),
'desc_tip' => true,
'description' => __(
@ -1817,6 +1826,9 @@ return array(
'type' => 'select',
'class' => array(),
'input_class' => array( 'wc-enhanced-select' ),
/**
* Returns default label ID of the PayPal button in mini cart.
*/
'default' => apply_filters( 'woocommerce_paypal_payments_button_mini_cart_label_default', 'paypal' ),
'desc_tip' => true,
'description' => __(

View file

@ -25,11 +25,11 @@ class SettingsPageAssets {
private $module_url;
/**
* The filesystem path to the module dir.
* The assets version.
*
* @var string
*/
private $module_path;
private $version;
/**
* The bearer.
@ -42,13 +42,13 @@ class SettingsPageAssets {
* Assets constructor.
*
* @param string $module_url The url of this module.
* @param string $module_path The filesystem path to this module.
* @param string $version The assets version.
* @param Bearer $bearer The bearer.
*/
public function __construct( string $module_url, string $module_path, Bearer $bearer ) {
$this->module_url = $module_url;
$this->module_path = $module_path;
$this->bearer = $bearer;
public function __construct( string $module_url, string $version, Bearer $bearer ) {
$this->module_url = $module_url;
$this->version = $version;
$this->bearer = $bearer;
}
/**
@ -102,13 +102,11 @@ class SettingsPageAssets {
* @param Bearer $bearer The bearer.
*/
private function register_admin_assets( Bearer $bearer ) {
$gateway_settings_script_path = trailingslashit( $this->module_path ) . 'assets/js/gateway-settings.js';
wp_enqueue_script(
'ppcp-gateway-settings',
trailingslashit( $this->module_url ) . 'assets/js/gateway-settings.js',
array(),
file_exists( $gateway_settings_script_path ) ? (string) filemtime( $gateway_settings_script_path ) : null,
$this->version,
true
);

View file

@ -11,12 +11,14 @@ namespace WooCommerce\PayPalCommerce\WcGateway\Processor;
use Exception;
use Psr\Log\LoggerInterface;
use WC_Order;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\OrderEndpoint;
use WooCommerce\PayPalCommerce\ApiClient\Endpoint\PaymentsEndpoint;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Authorization;
use WooCommerce\PayPalCommerce\ApiClient\Entity\AuthorizationStatus;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Capture;
use WooCommerce\PayPalCommerce\ApiClient\Entity\CaptureStatus;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
use WooCommerce\PayPalCommerce\WcGateway\Gateway\PayPalGateway;
use WooCommerce\PayPalCommerce\WcGateway\Notice\AuthorizeOrderActionNotice;
@ -96,11 +98,11 @@ class AuthorizedPaymentsProcessor {
/**
* Process a WooCommerce order.
*
* @param \WC_Order $wc_order The WooCommerce order.
* @param WC_Order $wc_order The WooCommerce order.
*
* @return string One of the AuthorizedPaymentsProcessor status constants.
*/
public function process( \WC_Order $wc_order ): string {
public function process( WC_Order $wc_order ): string {
$this->captures = array();
try {
@ -123,7 +125,7 @@ class AuthorizedPaymentsProcessor {
}
try {
$this->capture_authorizations( ...$authorizations );
$this->captures[] = $this->capture_authorization( $wc_order, ...$authorizations );
} catch ( Exception $exception ) {
$this->logger->error( 'Failed to capture authorization: ' . $exception->getMessage() );
return self::FAILED;
@ -144,11 +146,11 @@ class AuthorizedPaymentsProcessor {
/**
* Captures an authorized payment for an WooCommerce order.
*
* @param \WC_Order $wc_order The WooCommerce order.
* @param WC_Order $wc_order The WooCommerce order.
*
* @return bool
*/
public function capture_authorized_payment( \WC_Order $wc_order ): bool {
public function capture_authorized_payment( WC_Order $wc_order ): bool {
$result_status = $this->process( $wc_order );
$this->render_authorization_message_for_status( $result_status );
@ -211,11 +213,11 @@ class AuthorizedPaymentsProcessor {
/**
* Returns the PayPal order from a given WooCommerce order.
*
* @param \WC_Order $wc_order The WooCommerce order.
* @param WC_Order $wc_order The WooCommerce order.
*
* @return Order
*/
private function paypal_order_from_wc_order( \WC_Order $wc_order ): Order {
private function paypal_order_from_wc_order( WC_Order $wc_order ): Order {
$order_id = $wc_order->get_meta( PayPalGateway::ORDER_ID_META_KEY );
return $this->order_endpoint->order( $order_id );
}
@ -239,15 +241,21 @@ class AuthorizedPaymentsProcessor {
}
/**
* Captures the authorizations.
* Captures the authorization.
*
* @param WC_Order $order The order.
* @param Authorization ...$authorizations All authorizations.
* @throws Exception If capture failed.
*/
private function capture_authorizations( Authorization ...$authorizations ) {
private function capture_authorization( WC_Order $order, Authorization ...$authorizations ): Capture {
$uncaptured_authorizations = $this->authorizations_to_capture( ...$authorizations );
foreach ( $uncaptured_authorizations as $authorization ) {
$this->captures[] = $this->payments_endpoint->capture( $authorization->id() );
if ( ! $uncaptured_authorizations ) {
throw new Exception( 'No authorizations to capture.' );
}
$authorization = end( $uncaptured_authorizations );
return $this->payments_endpoint->capture( $authorization->id(), new Money( (float) $order->get_total(), $order->get_currency() ) );
}
/**

View file

@ -146,8 +146,14 @@ class SettingsListener {
}
$this->settings->persist();
/**
* The hook fired before performing the redirect at the end of onboarding after saving the merchant ID/email.
*/
do_action( 'woocommerce_paypal_payments_onboarding_before_redirect' );
/**
* The URL opened at the end of onboarding after saving the merchant ID/email.
*/
$redirect_url = apply_filters( 'woocommerce_paypal_payments_onboarding_redirect_url', admin_url( 'admin.php?page=wc-settings&tab=checkout&section=ppcp-gateway' ) );
if ( ! $this->settings->has( 'client_id' ) || ! $this->settings->get( 'client_id' ) ) {
$redirect_url = add_query_arg( 'ppcp-onboarding-error', '1', $redirect_url );

View file

@ -106,7 +106,7 @@ class WCGatewayModule implements ModuleInterface {
if ( $c->has( 'wcgateway.url' ) ) {
$assets = new SettingsPageAssets(
$c->get( 'wcgateway.url' ),
$c->get( 'wcgateway.absolute-path' ),
$c->get( 'ppcp.asset-version' ),
$c->get( 'api.bearer' )
);
$assets->register_assets();

View file

@ -156,7 +156,8 @@ return array(
'webhook.status.assets' => function( ContainerInterface $container ) : WebhooksStatusPageAssets {
return new WebhooksStatusPageAssets(
$container->get( 'webhook.module-url' )
$container->get( 'webhook.module-url' ),
$container->get( 'ppcp.asset-version' )
);
},

View file

@ -26,15 +26,25 @@ class WebhooksStatusPageAssets {
*/
private $module_url;
/**
* The assets version.
*
* @var string
*/
private $version;
/**
* WebhooksStatusPageAssets constructor.
*
* @param string $module_url The URL to the module.
* @param string $version The assets version.
*/
public function __construct(
string $module_url
string $module_url,
string $version
) {
$this->module_url = untrailingslashit( $module_url );
$this->version = $version;
}
/**
@ -47,14 +57,14 @@ class WebhooksStatusPageAssets {
'ppcp-webhooks-status-page-style',
untrailingslashit( $this->module_url ) . '/assets/css/status-page.css',
array(),
'1'
$this->version
);
wp_register_script(
'ppcp-webhooks-status-page',
untrailingslashit( $this->module_url ) . '/assets/js/status-page.js',
array(),
'1',
$this->version,
true
);

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<files psalm-version="4.11.2@6fba5eb554f9507b72932f9c75533d8af593688d">
<files psalm-version="4.20.0@f82a70e7edfc6cf2705e9374c8a0b6a974a779ed">
<file src="modules/ppcp-api-client/services.php">
<UndefinedConstant occurrences="2">
<code>PAYPAL_API_URL</code>
@ -12,9 +12,6 @@
</UndefinedMethod>
</file>
<file src="modules/ppcp-api-client/src/Endpoint/IdentityToken.php">
<InvalidOperand occurrences="1">
<code>$customer_id</code>
</InvalidOperand>
<UndefinedMethod occurrences="1">
<code>$response</code>
</UndefinedMethod>
@ -52,9 +49,6 @@
</UndefinedMethod>
</file>
<file src="modules/ppcp-api-client/src/Endpoint/PaymentTokenEndpoint.php">
<InvalidOperand occurrences="1">
<code>$id</code>
</InvalidOperand>
<UndefinedMethod occurrences="1">
<code>$response</code>
</UndefinedMethod>
@ -212,9 +206,7 @@
<RedundantCast occurrences="1">
<code>(float) $item_total</code>
</RedundantCast>
<RedundantCastGivenDocblockType occurrences="8">
<code>(float) $cart-&gt;get_cart_contents_tax()</code>
<code>(float) $cart-&gt;get_discount_tax()</code>
<RedundantCastGivenDocblockType occurrences="6">
<code>(float) $cart-&gt;get_discount_total()</code>
<code>(float) $cart-&gt;get_shipping_total()</code>
<code>(float) $cart-&gt;get_total( 'numeric' )</code>
@ -288,6 +280,9 @@
</UndefinedConstant>
</file>
<file src="modules/ppcp-button/services.php">
<PossiblyFalseArgument occurrences="1">
<code>realpath( __FILE__ )</code>
</PossiblyFalseArgument>
<UndefinedConstant occurrences="2">
<code>CONNECT_WOO_CLIENT_ID</code>
<code>CONNECT_WOO_SANDBOX_CLIENT_ID</code>
@ -297,13 +292,9 @@
<InvalidScalarArgument occurrences="1">
<code>1</code>
</InvalidScalarArgument>
<MissingClosureParamType occurrences="2">
<code>$default_fields</code>
<MissingClosureParamType occurrences="1">
<code>$id</code>
</MissingClosureParamType>
<MissingClosureReturnType occurrences="1">
<code>function ( $default_fields, $id ) {</code>
</MissingClosureReturnType>
<MissingReturnType occurrences="3">
<code>button_renderer</code>
<code>dcc_renderer</code>
@ -440,6 +431,9 @@
<MissingClosureParamType occurrences="1">
<code>$container</code>
</MissingClosureParamType>
<PossiblyFalseArgument occurrences="1">
<code>realpath( __FILE__ )</code>
</PossiblyFalseArgument>
<UndefinedConstant occurrences="10">
<code>CONNECT_WOO_MERCHANT_ID</code>
<code>CONNECT_WOO_SANDBOX_MERCHANT_ID</code>
@ -532,18 +526,13 @@
<FalsableReturnStatement occurrences="1">
<code>current( $tokens )</code>
</FalsableReturnStatement>
<MissingReturnType occurrences="3">
<code>capture_order</code>
<MissingReturnType occurrences="2">
<code>process_order</code>
<code>renew</code>
</MissingReturnType>
<RedundantCastGivenDocblockType occurrences="6">
<code>(int) $customer-&gt;get_id()</code>
<RedundantCastGivenDocblockType occurrences="2">
<code>(int) $customer-&gt;get_id()</code>
<code>(int) $wc_order-&gt;get_customer_id()</code>
<code>(int) $wc_order-&gt;get_id()</code>
<code>(int) $wc_order-&gt;get_id()</code>
<code>(int) $wc_order-&gt;get_id()</code>
</RedundantCastGivenDocblockType>
<TooManyArguments occurrences="1">
<code>apply_filters( 'woocommerce_paypal_payments_subscriptions_get_token_for_customer', null, $customer, $wc_order )</code>
@ -571,6 +560,11 @@
<code>\WC_Subscription</code>
</UndefinedClass>
</file>
<file src="modules/ppcp-vaulting/services.php">
<PossiblyFalseArgument occurrences="1">
<code>realpath( __FILE__ )</code>
</PossiblyFalseArgument>
</file>
<file src="modules/ppcp-vaulting/src/Assets/MyAccountPaymentsAssets.php">
<MissingReturnType occurrences="1">
<code>localize</code>
@ -603,6 +597,13 @@
</MissingReturnType>
</file>
<file src="modules/ppcp-wc-gateway/services.php">
<PossiblyFalseArgument occurrences="2">
<code>realpath( __FILE__ )</code>
<code>realpath( __FILE__ )</code>
</PossiblyFalseArgument>
<PossiblyFalseOperand occurrences="1">
<code>substr( $letters, 0, 6 )</code>
</PossiblyFalseOperand>
<PossiblyInvalidArgument occurrences="5">
<code>wp_unslash( $_GET[ SectionsRenderer::KEY ] )</code>
<code>wp_unslash( $_GET['page'] )</code>
@ -637,7 +638,6 @@
</file>
<file src="modules/ppcp-wc-gateway/src/Checkout/CheckoutPayPalAddressPreset.php">
<PossiblyNullReference occurrences="3">
<code>phone</code>
<code>phone</code>
<code>phone</code>
<code>purchase_units</code>
@ -764,7 +764,7 @@
</RedundantCast>
</file>
<file src="modules/ppcp-wc-gateway/src/WCGatewayModule.php">
<MissingClosureParamType occurrences="15">
<MissingClosureParamType occurrences="13">
<code>$args</code>
<code>$args</code>
<code>$column</code>
@ -774,9 +774,7 @@
<code>$methods</code>
<code>$methods</code>
<code>$notices</code>
<code>$order</code>
<code>$order_actions</code>
<code>$recipient</code>
<code>$value</code>
<code>$wc_order_id</code>
<code>$wc_order_id</code>
@ -793,6 +791,11 @@
<code>$container</code>
</MissingClosureParamType>
</file>
<file src="modules/ppcp-webhooks/services.php">
<PossiblyFalseArgument occurrences="1">
<code>realpath( __FILE__ )</code>
</PossiblyFalseArgument>
</file>
<file src="modules/ppcp-webhooks/src/Endpoint/ResubscribeEndpoint.php">
<MissingReturnType occurrences="1">
<code>handle_request</code>
@ -918,4 +921,9 @@
</PossiblyNullArgument>
<RedundantCastGivenDocblockType occurrences="1"/>
</file>
<file src="src/services.php">
<PossiblyFalseArgument occurrences="1">
<code>realpath( __FILE__ )</code>
</PossiblyFalseArgument>
</file>
</files>

View file

@ -4,12 +4,11 @@
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
xmlns:xi="http://www.w3.org/2001/XInclude"
totallyTyped="false"
reportMixedIssues="false"
useDocblockTypes="true"
usePhpDocMethodsWithoutMagicCall="false"
strictBinaryOperands="true"
rememberPropertyAssignmentsAfterCall="true"
allowPhpStormGenerics="true"
allowStringToStandInForClass="false"
memoizeMethodCallResults="false"
hoistConstants="false"
@ -150,5 +149,6 @@
<MixedReturnTypeCoercion errorLevel="info"/>
<MixedStringOffsetAssignment errorLevel="info"/>
<ParamNameMismatch errorLevel="info"/>
<RedundantCastGivenDocblockType errorLevel="info"/>
</issueHandlers>
</psalm>

View file

@ -82,8 +82,10 @@ Follow the steps below to connect the plugin to your PayPal account:
== Changelog ==
= 1.7.0 =
* Fix - DCC orders randomly failing #503
* Fix - Multi-currency broke #481
* Fix - Address information from PayPal shortcut flow not loaded #451
* Fix - WooCommerce as mu-plugin is not detected as active #461
* Enhancement - Improve onboarding flow, allow no card processing #443
* Enhancement - Add Germany to supported ACDC countries #459
* Enhancement - Add filters to allow ACDC for countries #437
@ -93,6 +95,8 @@ Follow the steps below to connect the plugin to your PayPal account:
* Enhancement - Pass address details to credit card fields #479
* Enhancement - Improve onboarding notice #465
* Enhancement - Add transaction ID to WC order and order note when refund is received #473
* Enhancement - Asset caching may cause bugs on upgrades #501
* Enhancement - Allow partial capture #483
= 1.6.5 =
* Fix - Allow guest users to purchase subscription products from checkout page #422

View file

@ -0,0 +1,134 @@
<?php
/**
* Extracts plugin info from plugin file path.
*
* @package WooCommerce\PayPalCommerce
*
* @phpcs:disable Squiz.Commenting.FunctionCommentThrowTag
* @phpcs:disable WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce;
use Dhii\Package\Version\StringVersionFactoryInterface;
use Dhii\Package\Version\VersionInterface;
use Exception;
use RuntimeException;
use UnexpectedValueException;
use WpOop\WordPress\Plugin\FilePathPluginFactoryInterface;
use WpOop\WordPress\Plugin\PluginInterface;
/**
* Extracts plugin info from plugin file path.
*/
class FilePathPluginFactory implements FilePathPluginFactoryInterface {
/**
* The version factory.
*
* @var StringVersionFactoryInterface
*/
protected $version_factory;
/**
* FilePathPluginFactory constructor.
*
* @param StringVersionFactoryInterface $version_factory The version factory.
*/
public function __construct( StringVersionFactoryInterface $version_factory ) {
$this->version_factory = $version_factory;
}
/**
* Extracts plugin info from plugin file path.
*
* @param string $filePath The plugin file path.
*/
public function createPluginFromFilePath( string $filePath ): PluginInterface {
if ( ! is_readable( $filePath ) ) {
throw new RuntimeException(
sprintf(
'Plugin file "%1$s" does not exist or is not readable',
$filePath
)
);
}
$plugin_data = get_plugin_data( $filePath );
if ( empty( $plugin_data ) ) {
throw new UnexpectedValueException(
sprintf(
'Plugin file "%1$s" does not have a valid plugin header',
$filePath
)
);
}
$plugin_data = array_merge(
array(
'Name' => '',
'Version' => '0.1.0-alpha1+default',
'Title' => '',
'Description' => '',
'TextDomain' => '',
'RequiresWP' => '5.0',
'RequiresPHP' => '7.1',
),
$plugin_data
);
$base_dir = dirname( $filePath );
$base_name = plugin_basename( $filePath );
$slug = $this->get_plugin_slug( $base_name );
$text_domain = ! empty( $plugin_data['TextDomain'] ) ? $plugin_data['TextDomain'] : $slug;
return new Plugin(
$plugin_data['Name'],
$this->create_version( $plugin_data['Version'] ),
$base_dir,
$base_name,
$plugin_data['Title'],
$plugin_data['Description'],
$text_domain,
$this->create_version( $plugin_data['RequiresPHP'] ),
$this->create_version( $plugin_data['RequiresWP'] )
);
}
/**
* Creates a new version from a version string.
*
* @param string $version_string The SemVer-compliant version string.
*
* @return VersionInterface The new version.
*
* @throws Exception If version string is malformed.
*/
protected function create_version( string $version_string ): VersionInterface {
return $this->version_factory->createVersionFromString( $version_string );
}
/**
* Retrieves a plugin slug from its basename.
*
* @param string $base_name The plugin's basename.
*
* @return string The plugin's slug.
*/
protected function get_plugin_slug( string $base_name ): string {
$directory_separator = '/';
// If plugin is in a directory, use directory name.
if ( strstr( $base_name, $directory_separator ) !== false ) {
$parts = explode( $directory_separator, $base_name );
if ( $parts ) {
return $parts[0];
}
}
// If plugin is not in a directory, return plugin file basename.
return basename( $base_name );
}
}

180
src/Plugin.php Normal file
View file

@ -0,0 +1,180 @@
<?php
/**
* Plugin properties.
*
* @package WooCommerce\PayPalCommerce
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce;
use Dhii\Package\Version\VersionInterface;
use WpOop\WordPress\Plugin\PluginInterface;
/**
* Plugin properties.
*/
class Plugin implements PluginInterface {
/**
* The plugin name.
*
* @var string
*/
protected $name;
/**
* The plugin version.
*
* @var VersionInterface
*/
protected $version;
/**
* The path to the plugin base directory.
*
* @var string
*/
protected $base_dir;
/**
* The plugin base name.
*
* @var string
*/
protected $base_name;
/**
* The plugin title.
*
* @var string
*/
protected $title;
/**
* The plugin description.
*
* @var string
*/
protected $description;
/**
* The text domain of this plugin
*
* @var string
*/
protected $text_domain;
/**
* The minimal version of PHP required by this plugin.
*
* @var VersionInterface
*/
protected $min_php_version;
/**
* The minimal version of WP required by this plugin.
*
* @var VersionInterface
*/
protected $min_wp_version;
/**
* Plugin constructor.
*
* @param string $name The plugin name.
* @param VersionInterface $version The plugin version.
* @param string $base_dir The path to the plugin base directory.
* @param string $base_name The plugin base name.
* @param string $title The plugin title.
* @param string $description The plugin description.
* @param string $text_domain The text domain of this plugin.
* @param VersionInterface $min_php_version The minimal version of PHP required by this plugin.
* @param VersionInterface $min_wp_version The minimal version of WP required by this plugin.
*/
public function __construct(
string $name,
VersionInterface $version,
string $base_dir,
string $base_name,
string $title,
string $description,
string $text_domain,
VersionInterface $min_php_version,
VersionInterface $min_wp_version
) {
$this->name = $name;
$this->description = $description;
$this->version = $version;
$this->base_dir = $base_dir;
$this->base_name = $base_name;
$this->title = $title;
$this->text_domain = $text_domain;
$this->min_php_version = $min_php_version;
$this->min_wp_version = $min_wp_version;
}
/**
* The plugin name.
*/
public function getName(): string {
return $this->name;
}
/**
* The plugin description.
*/
public function getDescription(): string {
return $this->description;
}
/**
* The plugin version.
*/
public function getVersion(): VersionInterface {
return $this->version;
}
/**
* The path to the plugin base directory.
*/
public function getBaseDir(): string {
return $this->base_dir;
}
/**
* The plugin base name.
*/
public function getBaseName(): string {
return $this->base_name;
}
/**
* The text domain of this plugin.
*/
public function getTextDomain(): string {
return $this->text_domain;
}
/**
* The plugin title.
*/
public function getTitle(): string {
return $this->title;
}
/**
* The minimal version of PHP required by this plugin.
*/
public function getMinPhpVersion(): VersionInterface {
return $this->min_php_version;
}
/**
* The minimal version of WP required by this plugin.
*/
public function getMinWpVersion(): VersionInterface {
return $this->min_wp_version;
}
}

View file

@ -23,7 +23,10 @@ class PluginModule implements ModuleInterface {
* {@inheritDoc}
*/
public function setup(): ServiceProviderInterface {
return new ServiceProvider( array(), array() );
return new ServiceProvider(
require __DIR__ . '/services.php',
require __DIR__ . '/extensions.php'
);
}
/**

12
src/extensions.php Normal file
View file

@ -0,0 +1,12 @@
<?php
/**
* The plugin module extensions.
*
* @package WooCommerce\PayPalCommerce
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce;
return array();

27
src/services.php Normal file
View file

@ -0,0 +1,27 @@
<?php
/**
* The plugin module services.
*
* @package WooCommerce\PayPalCommerce
*/
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce;
use Dhii\Versions\StringVersionFactory;
use Psr\Container\ContainerInterface;
use WpOop\WordPress\Plugin\PluginInterface;
return array(
'ppcp.plugin' => function( ContainerInterface $container ) : PluginInterface {
$factory = new FilePathPluginFactory( new StringVersionFactory() );
return $factory->createPluginFromFilePath( dirname( realpath( __FILE__ ), 2 ) . '/woocommerce-paypal-payments.php' );
},
'ppcp.asset-version' => function( ContainerInterface $container ) : string {
$plugin = $container->get( 'ppcp.plugin' );
assert( $plugin instanceof PluginInterface );
return (string) $plugin->getVersion();
},
);

View file

@ -6,9 +6,9 @@ namespace WooCommerce\PayPalCommerce\ApiClient\Authentication;
use Requests_Utility_CaseInsensitiveDictionary;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\ApiClient\Helper\Cache;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use Psr\Log\LoggerInterface;
use Mockery;
use WooCommerce\PayPalCommerce\TestCase;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
use function Brain\Monkey\Functions\expect;

View file

@ -10,8 +10,8 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\Token;
use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\ApiClient\Repository\CustomerRepository;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use Mockery;
use WooCommerce\PayPalCommerce\TestCase;
use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings;
use function Brain\Monkey\Functions\expect;
use function Brain\Monkey\Functions\when;
@ -89,7 +89,6 @@ class IdentityTokenTest extends TestCase
expect('is_wp_error')->with($rawResponse)->andReturn(false);
expect('wp_remote_retrieve_response_code')->with($rawResponse)->andReturn(200);
when('wc_print_r')->returnArg();
when('get_user_meta')->justReturn('');
$result = $this->sut->generate_for_user(1);
@ -108,7 +107,6 @@ class IdentityTokenTest extends TestCase
$headers->shouldReceive('getAll');
expect('wp_remote_get')->andReturn(['headers' => $headers,]);
expect('is_wp_error')->andReturn(true);
when('wc_print_r')->returnArg();
$this->logger->shouldReceive('log');
$this->logger->shouldReceive('debug');
$this->settings->shouldReceive('has')->andReturn(true);
@ -135,7 +133,6 @@ class IdentityTokenTest extends TestCase
]);
expect('is_wp_error')->andReturn(false);
expect('wp_remote_retrieve_response_code')->andReturn(500);
when('wc_print_r')->returnArg();
$this->logger->shouldReceive('log');
$this->logger->shouldReceive('debug');
$this->settings->shouldReceive('has')->andReturn(true);

View file

@ -24,10 +24,10 @@ use WooCommerce\PayPalCommerce\ApiClient\Factory\PatchCollectionFactory;
use WooCommerce\PayPalCommerce\ApiClient\Helper\ErrorResponse;
use WooCommerce\PayPalCommerce\ApiClient\Repository\ApplicationContextRepository;
use WooCommerce\PayPalCommerce\ApiClient\Repository\PayPalRequestIdRepository;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use Mockery;
use Psr\Log\LoggerInterface;
use WooCommerce\PayPalCommerce\Subscription\Helper\SubscriptionHelper;
use WooCommerce\PayPalCommerce\TestCase;
use function Brain\Monkey\Functions\expect;
use function Brain\Monkey\Functions\when;
@ -38,7 +38,6 @@ class OrderEndpointTest extends TestCase
public function setUp(): void
{
parent::setUp();
when('wc_print_r')->returnArg();
$this->shipping = new Shipping('shipping', new Address('US', 'street', '', 'CA', '', '12345'));
}

View file

@ -9,8 +9,8 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\OrderStatus;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payer;
use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSource;
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use Mockery;
use WooCommerce\PayPalCommerce\TestCase;
class OrderTest extends TestCase
{

View file

@ -12,9 +12,9 @@ use WooCommerce\PayPalCommerce\ApiClient\Exception\PayPalApiException;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\ApiClient\Factory\PaymentTokenFactory;
use WooCommerce\PayPalCommerce\ApiClient\Repository\CustomerRepository;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use Mockery;
use Mockery\Adapter\Phpunit\MockeryPHPUnitIntegration;
use WooCommerce\PayPalCommerce\TestCase;
use function Brain\Monkey\Functions\expect;
class PaymentTokenEndpointTest extends TestCase

View file

@ -13,10 +13,9 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\Token;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\ApiClient\Factory\AuthorizationFactory;
use WooCommerce\PayPalCommerce\ApiClient\Factory\CaptureFactory;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use Mockery;
use Psr\Log\LoggerInterface;
use WooCommerce\PayPalCommerce\TestCase;
use function Brain\Monkey\Functions\expect;
class PaymentsEndpointTest extends TestCase

View file

@ -3,7 +3,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use WooCommerce\PayPalCommerce\TestCase;
class AddressTest extends TestCase
{

View file

@ -3,7 +3,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use WooCommerce\PayPalCommerce\TestCase;
use Mockery;
class AmountBreakdownTest extends TestCase

View file

@ -3,7 +3,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use WooCommerce\PayPalCommerce\TestCase;
use Mockery;
class AmountTest extends TestCase

View file

@ -5,7 +5,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use WooCommerce\PayPalCommerce\TestCase;
class AuthorizationStatusTest extends TestCase
{

View file

@ -4,7 +4,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use WooCommerce\PayPalCommerce\TestCase;
class AuthorizationTest extends TestCase
{

View file

@ -3,7 +3,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use WooCommerce\PayPalCommerce\TestCase;
use Mockery;
class ItemTest extends TestCase

View file

@ -3,7 +3,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use WooCommerce\PayPalCommerce\TestCase;
class MoneyTest extends TestCase
{

View file

@ -3,7 +3,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use WooCommerce\PayPalCommerce\TestCase;
use Mockery;
class PayerTest extends TestCase

View file

@ -4,7 +4,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use WooCommerce\PayPalCommerce\TestCase;
class PaymentsTest extends TestCase
{

View file

@ -3,7 +3,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApiClient\Entity;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use WooCommerce\PayPalCommerce\TestCase;
use Mockery;
class PurchaseUnitTest extends TestCase

View file

@ -4,7 +4,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use WooCommerce\PayPalCommerce\TestCase;
use Mockery;
class AddressFactoryTest extends TestCase

View file

@ -6,7 +6,7 @@ namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Item;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use WooCommerce\PayPalCommerce\TestCase;
use Mockery;
use function Brain\Monkey\Functions\expect;
use function Brain\Monkey\Functions\when;

View file

@ -7,7 +7,7 @@ namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Authorization;
use WooCommerce\PayPalCommerce\ApiClient\Entity\AuthorizationStatus;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use WooCommerce\PayPalCommerce\TestCase;
class AuthorizationFactoryTest extends TestCase
{

View file

@ -5,7 +5,7 @@ namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Item;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use WooCommerce\PayPalCommerce\TestCase;
use function Brain\Monkey\Functions\expect;
use function Brain\Monkey\Functions\when;
use Mockery;

View file

@ -10,7 +10,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\PaymentSource;
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
use WooCommerce\PayPalCommerce\ApiClient\Exception\RuntimeException;
use WooCommerce\PayPalCommerce\ApiClient\Repository\ApplicationContextRepository;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use WooCommerce\PayPalCommerce\TestCase;
use Mockery;
class OrderFactoryTest extends TestCase

View file

@ -4,7 +4,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Address;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use WooCommerce\PayPalCommerce\TestCase;
use Mockery;
class PayerFactoryTest extends TestCase

View file

@ -7,7 +7,7 @@ namespace WooCommerce\PayPalCommerce\ApiClient\Factory;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Authorization;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Capture;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payments;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use WooCommerce\PayPalCommerce\TestCase;
use Mockery;
class PaymentsFactoryTest extends TestCase

View file

@ -11,7 +11,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\Payments;
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Shipping;
use WooCommerce\PayPalCommerce\ApiClient\Repository\PayeeRepository;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use WooCommerce\PayPalCommerce\TestCase;
use Mockery;
use function Brain\Monkey\Functions\expect;

View file

@ -3,8 +3,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApiClient\Repository;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use WooCommerce\PayPalCommerce\Button\Assets\SmartButton;
use WooCommerce\PayPalCommerce\TestCase;
use function Brain\Monkey\Functions\when;
class ApplicationContextRepositoryTest extends TestCase

View file

@ -3,9 +3,7 @@ declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApiClient\Repository;
use WooCommerce\PayPalCommerce\ApiClient\Config\Config;
use WooCommerce\PayPalCommerce\ApiClient\TestCase;
use Mockery;
use WooCommerce\PayPalCommerce\TestCase;
class PayeeRepositoryTest extends TestCase
{

View file

@ -1,28 +0,0 @@
<?php
declare(strict_types=1);
namespace WooCommerce\PayPalCommerce\ApiClient;
use function Brain\Monkey\setUp;
use function Brain\Monkey\tearDown;
use function Brain\Monkey\Functions\expect;
use Mockery;
class TestCase extends \PHPUnit\Framework\TestCase
{
public function setUp(): void
{
parent::setUp();
expect('__')->andReturnUsing(function (string $text) {
return $text;
});
setUp();
}
public function tearDown(): void
{
tearDown();
Mockery::close();
parent::tearDown();
}
}

View file

@ -36,7 +36,6 @@ class ThreeDSecureTest extends TestCase
$order->shouldReceive('payment_source')->andReturn($source);
$logger = \Mockery::mock(LoggerInterface::class);
$logger->shouldReceive('info');
when('wc_print_r')->justReturn();
$testee = new ThreeDSecure($logger);
$result = $testee->proceed_with_order($order);

View file

@ -25,6 +25,11 @@ class TestCase extends \PHPUnit\Framework\TestCase
when('sanitize_text_field')->returnArg();
when('wp_kses_post')->returnArg();
when('wp_unslash')->returnArg();
when('wc_print_r')->alias(function ($value, bool $return = false) {
return print_r($value, $return);
});
when('get_plugin_data')->justReturn(['Version' => '1.0']);
when('plugin_basename')->justReturn('woocommerce-paypal-payments/woocommerce-paypal-payments.php');
setUp();
}

View file

@ -12,6 +12,7 @@ use WooCommerce\PayPalCommerce\ApiClient\Entity\Authorization;
use WooCommerce\PayPalCommerce\ApiClient\Entity\AuthorizationStatus;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Capture;
use WooCommerce\PayPalCommerce\ApiClient\Entity\CaptureStatus;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Money;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Order;
use WooCommerce\PayPalCommerce\ApiClient\Entity\Payments;
use WooCommerce\PayPalCommerce\ApiClient\Entity\PurchaseUnit;
@ -26,6 +27,8 @@ class AuthorizedPaymentsProcessorTest extends TestCase
private $wcOrder;
private $paypalOrderId = 'abc';
private $authorizationId = 'qwe';
private $amount = 42.0;
private $currency = 'EUR';
private $paypalOrder;
private $orderEndpoint;
private $paymentsEndpoint;
@ -64,13 +67,13 @@ class AuthorizedPaymentsProcessorTest extends TestCase
public function testSuccess() {
$this->paymentsEndpoint
->expects('capture')
->with($this->authorizationId)
->with($this->authorizationId, equalTo(new Money($this->amount, $this->currency)))
->andReturn($this->createCapture(CaptureStatus::COMPLETED));
$this->assertEquals(AuthorizedPaymentsProcessor::SUCCESSFUL, $this->testee->process($this->wcOrder));
}
public function testCapturesAllCaptureable() {
public function testCapturesLastCaptureable() {
$authorizations = [
$this->createAuthorization('id1', AuthorizationStatus::CREATED),
$this->createAuthorization('id2', AuthorizationStatus::VOIDED),
@ -82,12 +85,10 @@ class AuthorizedPaymentsProcessorTest extends TestCase
];
$this->paypalOrder = $this->createPaypalOrder($authorizations);
foreach ([$authorizations[0], $authorizations[2]] as $authorization) {
$this->paymentsEndpoint
->expects('capture')
->with($authorization->id())
->andReturn($this->createCapture(CaptureStatus::COMPLETED));
}
$this->paymentsEndpoint
->expects('capture')
->with($authorizations[2]->id(), equalTo(new Money($this->amount, $this->currency)))
->andReturn($this->createCapture(CaptureStatus::COMPLETED));
$this->assertEquals(AuthorizedPaymentsProcessor::SUCCESSFUL, $this->testee->process($this->wcOrder));
}
@ -113,7 +114,7 @@ class AuthorizedPaymentsProcessorTest extends TestCase
public function testCaptureFails() {
$this->paymentsEndpoint
->expects('capture')
->with($this->authorizationId)
->with($this->authorizationId, equalTo(new Money($this->amount, $this->currency)))
->andThrow(RuntimeException::class);
$this->assertEquals(AuthorizedPaymentsProcessor::FAILED, $this->testee->process($this->wcOrder));
@ -137,7 +138,7 @@ class AuthorizedPaymentsProcessorTest extends TestCase
$this->paymentsEndpoint
->expects('capture')
->with($this->authorizationId)
->with($this->authorizationId, equalTo(new Money($this->amount, $this->currency)))
->andReturn($this->createCapture(CaptureStatus::COMPLETED));
$this->wcOrder->shouldReceive('payment_complete')->andReturn(true);
@ -172,6 +173,12 @@ class AuthorizedPaymentsProcessorTest extends TestCase
->shouldReceive('get_meta')
->with(PayPalGateway::ORDER_ID_META_KEY)
->andReturn($paypalOrderId);
$wcOrder
->shouldReceive('get_total')
->andReturn($this->amount);
$wcOrder
->shouldReceive('get_currency')
->andReturn($this->currency);
return $wcOrder;
}

View file

@ -8,3 +8,5 @@ require_once ROOT_DIR . '/vendor/autoload.php';
require_once TESTS_ROOT_DIR . '/stubs/WC_Payment_Gateway.php';
require_once TESTS_ROOT_DIR . '/stubs/WC_Payment_Gateway_CC.php';
require_once TESTS_ROOT_DIR . '/stubs/WC_Ajax.php';
Hamcrest\Util::registerGlobalFunctions();

View file

@ -41,10 +41,7 @@ define( 'PPCP_FLAG_SUBSCRIPTION', true );
function init() {
$root_dir = __DIR__;
if ( ! function_exists( 'is_plugin_active' ) ) {
require_once ABSPATH . '/wp-admin/includes/plugin.php';
}
if ( ! is_plugin_active( 'woocommerce/woocommerce.php' ) ) {
if ( ! is_woocommerce_activated() ) {
add_action(
'admin_notices',
function() {
@ -73,6 +70,9 @@ define( 'PPCP_FLAG_SUBSCRIPTION', true );
$app_container = $bootstrap( $root_dir );
$initialized = true;
/**
* The hook fired after the plugin bootstrap with the app services container as parameter.
*/
do_action( 'woocommerce_paypal_payments_built_container', $app_container );
}
}
@ -88,6 +88,9 @@ define( 'PPCP_FLAG_SUBSCRIPTION', true );
$plugin_data = get_plugin_data( __DIR__ . '/woocommerce-paypal-payments.php' );
$plugin_version = $plugin_data['Version'] ?? null;
if ( get_option( 'woocommerce-ppcp-version' ) !== $plugin_version ) {
/**
* The hook fired when the plugin is installed or updated.
*/
do_action( 'woocommerce_paypal_payments_gateway_migrate' );
update_option( 'woocommerce-ppcp-version', $plugin_version );
}
@ -97,6 +100,9 @@ define( 'PPCP_FLAG_SUBSCRIPTION', true );
__FILE__,
function () {
init();
/**
* The hook fired in register_activation_hook.
*/
do_action( 'woocommerce_paypal_payments_gateway_activate' );
}
);
@ -104,6 +110,9 @@ define( 'PPCP_FLAG_SUBSCRIPTION', true );
__FILE__,
function () {
init();
/**
* The hook fired in register_deactivation_hook.
*/
do_action( 'woocommerce_paypal_payments_gateway_deactivate' );
}
);
@ -112,10 +121,7 @@ define( 'PPCP_FLAG_SUBSCRIPTION', true );
add_filter(
'plugin_action_links_' . plugin_basename( __FILE__ ),
function( $links ) {
if ( ! function_exists( 'is_plugin_active' ) ) {
require_once ABSPATH . '/wp-admin/includes/plugin.php';
}
if ( ! is_plugin_active( 'woocommerce/woocommerce.php' ) ) {
if ( ! is_woocommerce_activated() ) {
return $links;
}
@ -132,4 +138,13 @@ define( 'PPCP_FLAG_SUBSCRIPTION', true );
}
);
/**
* Check if WooCommerce is active.
*
* @return bool true if WooCommerce is active, otherwise false.
*/
function is_woocommerce_activated(): bool {
return class_exists( 'woocommerce' );
}
} )();