Merge branch 'trunk' into pcp-541-onboarding

This commit is contained in:
Alex P 2022-02-22 16:49:34 +02:00
commit a6689eb371
35 changed files with 1045 additions and 318 deletions

View file

@ -12,6 +12,7 @@
* 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
= 1.6.5 - 2022-01-31 =
* Fix - Allow guest users to purchase subscription products from checkout page #422

View file

@ -12,7 +12,9 @@
"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"
},
"require-dev": {
"woocommerce/woocommerce-sniffs": "^0.1.0",

705
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

@ -395,6 +395,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(
@ -540,6 +543,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

@ -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

@ -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

@ -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' )
);
},

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(
@ -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

@ -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

@ -905,6 +905,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' => __(
@ -1207,6 +1210,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' => __(
@ -1510,6 +1516,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' => __(
@ -1813,6 +1822,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

@ -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

@ -74,7 +74,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

@ -9,7 +9,6 @@
usePhpDocMethodsWithoutMagicCall="false"
strictBinaryOperands="true"
rememberPropertyAssignmentsAfterCall="true"
allowPhpStormGenerics="true"
allowStringToStandInForClass="false"
memoizeMethodCallResults="false"
hoistConstants="false"

View file

@ -93,6 +93,7 @@ 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
= 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

@ -25,6 +25,8 @@ class TestCase extends \PHPUnit\Framework\TestCase
when('sanitize_text_field')->returnArg();
when('wp_kses_post')->returnArg();
when('wp_unslash')->returnArg();
when('get_plugin_data')->justReturn(['Version' => '1.0']);
when('plugin_basename')->justReturn('woocommerce-paypal-payments/woocommerce-paypal-payments.php');
setUp();
}

View file

@ -73,6 +73,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 +91,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 +103,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 +113,9 @@ define( 'PPCP_FLAG_SUBSCRIPTION', true );
__FILE__,
function () {
init();
/**
* The hook fired in register_deactivation_hook.
*/
do_action( 'woocommerce_paypal_payments_gateway_deactivate' );
}
);