';
},
30
);
}
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
if ( isset( $available_gateways['ppcp-gateway'] ) ) {
add_action(
$this->pay_order_renderer_hook(),
function (): void {
$this->button_renderer( PayPalGateway::ID, 'woocommerce_paypal_payments_payorder_button_render' );
$this->button_renderer( CardButtonGateway::ID );
},
20
);
add_action(
$this->checkout_button_renderer_hook(),
function (): void {
$this->button_renderer( PayPalGateway::ID, 'woocommerce_paypal_payments_checkout_button_render' );
$this->button_renderer( CardButtonGateway::ID );
}
);
$enabled_on_cart = $this->settings_status->is_smart_button_enabled_for_location( 'cart' );
add_action(
$this->proceed_to_checkout_button_renderer_hook(),
function() use ( $enabled_on_cart ) {
if ( ! is_cart() || ! $enabled_on_cart || $this->is_free_trial_cart() || $this->is_cart_price_total_zero() || isset( reset( WC()->cart->cart_contents )['subscription_switch'] ) ) {
return;
}
$this->button_renderer( PayPalGateway::ID, 'woocommerce_paypal_payments_cart_button_render' );
},
20
);
}
return true;
}
/**
* Whether any of our scripts (for DCC or product, mini-cart, non-block cart/checkout) should be loaded.
*/
public function should_load_ppcp_script(): bool {
$pcp_gateway_enabled = $this->settings->has( 'enabled' ) && $this->settings->get( 'enabled' );
if ( ! $pcp_gateway_enabled ) {
return false;
}
return $this->should_load_buttons() || $this->should_load_messages() || $this->can_render_dcc();
}
/**
* Determines whether the button component should be loaded.
*/
public function should_load_buttons() : bool {
$pcp_gateway_enabled = $this->settings->has( 'enabled' ) && $this->settings->get( 'enabled' );
if ( ! $pcp_gateway_enabled ) {
return false;
}
$smart_button_enabled_for_current_location = $this->settings_status->is_smart_button_enabled_for_location( $this->context() );
$smart_button_enabled_for_mini_cart = $this->settings_status->is_smart_button_enabled_for_location( 'mini-cart' );
switch ( $this->context() ) {
case 'checkout':
case 'cart':
case 'pay-now':
case 'checkout-block':
case 'cart-block':
return $smart_button_enabled_for_current_location;
case 'product':
return $smart_button_enabled_for_current_location || $smart_button_enabled_for_mini_cart;
default:
return $smart_button_enabled_for_mini_cart || $this->is_block_editor();
}
}
/**
* Determines whether the Pay Later messages component should be loaded.
*/
public function should_load_messages() : bool {
$pcp_gateway_enabled = $this->settings->has( 'enabled' ) && $this->settings->get( 'enabled' );
if ( ! $pcp_gateway_enabled ) {
return false;
}
if ( ! $this->settings_status->is_pay_later_messaging_enabled() ) {
return false;
}
if ( ! $this->messages_apply->for_country() || $this->is_free_trial_cart() ) {
return false;
}
$location = $this->location();
$messaging_enabled_for_current_location = $this->settings_status->is_pay_later_messaging_enabled_for_location( $location );
$has_paylater_block = PayLaterBlockModule::is_block_enabled( $this->settings_status ) && has_block( 'woocommerce-paypal-payments/paylater-messages' );
if ( 'cart-block' === $location || 'checkout-block' === $location ) {
return true;
}
switch ( $location ) {
case 'checkout':
case 'cart':
case 'pay-now':
case 'product':
case 'shop':
case 'home':
return $messaging_enabled_for_current_location;
case 'block-editor':
return true;
default:
return $has_paylater_block;
}
}
/**
* Whether DCC fields can be rendered.
*/
public function can_render_dcc() : bool {
return $this->dcc_configuration->is_acdc_enabled()
&& in_array(
$this->context(),
apply_filters( 'woocommerce_paypal_payments_can_render_dcc_contexts', array( 'checkout', 'pay-now', 'add-payment-method' ) ),
true
);
}
/**
* Enqueues our scripts/styles (for DCC and product, mini-cart and non-block cart/checkout)
*/
public function enqueue(): void {
if ( $this->can_render_dcc() ) {
wp_enqueue_style(
'ppcp-hosted-fields',
untrailingslashit( $this->module_url ) . '/assets/css/hosted-fields.css',
array(),
$this->version
);
}
wp_enqueue_style(
'gateway',
untrailingslashit( $this->module_url ) . '/assets/css/gateway.css',
array(),
$this->version
);
wp_enqueue_script(
'ppcp-smart-button',
untrailingslashit( $this->module_url ) . '/assets/js/button.js',
array( 'jquery' ),
$this->version,
true
);
wp_localize_script(
'ppcp-smart-button',
'PayPalCommerceGateway',
$this->script_data()
);
}
/**
* Renders the HTML for the buttons.
*
* @param string $gateway_id The gateway ID, like 'ppcp-gateway'.
* @param string|null $action_name The action name to be called.
*/
public function button_renderer( string $gateway_id, string $action_name = null ) {
$available_gateways = WC()->payment_gateways->get_available_payment_gateways();
if ( ! isset( $available_gateways[ $gateway_id ] ) ) {
return;
}
// The wrapper is needed for the loading spinner,
// otherwise jQuery block() prevents buttons rendering.
echo '
';
$hook_gateway_id = str_replace( '-', '_', $gateway_id );
/**
* A hook executed after rendering of the opening tag for the PCP wrapper (before the inner wrapper for the buttons).
*
* For the PayPal gateway the hook name is ppcp_start_button_wrapper_ppcp_gateway.
*/
do_action( 'ppcp_start_button_wrapper_' . $hook_gateway_id );
echo '';
/**
* A hook executed before rendering of the closing tag for the PCP wrapper (before the inner wrapper for the buttons).
*
* For the PayPal gateway the hook name is ppcp_end_button_wrapper_ppcp_gateway.
*/
do_action( 'ppcp_end_button_wrapper_' . $hook_gateway_id );
if ( null !== $action_name ) {
do_action( $action_name );
}
echo '
';
}
/**
* Renders the HTML for the credit messaging.
*
* @param array|null $block_params If it's to be rendered after a block, contains the block params.
* @return void
*/
public function message_renderer( $block_params = array() ): void {
$product = wc_get_product();
$location = $this->location();
$location_hook = $this->location_to_hook( $location );
if (
$location === 'product' && is_a( $product, WC_Product::class )
/**
* The filter returning true if PayPal buttons can be rendered, or false otherwise.
*/
&& ! $this->product_supports_payment( $product )
) {
return;
}
/**
* A hook executed before rendering of the PCP Pay Later messages wrapper.
*/
do_action( "ppcp_before_{$location_hook}_message_wrapper" );
$messages_placeholder = '';
if ( is_array( $block_params ) && ( $block_params['blockName'] ?? false ) ) {
$this->render_after_block(
$block_params['blockName'],
'
' . $messages_placeholder . '
',
$block_params['priority'] ?? 10
);
} else {
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo $messages_placeholder;
}
/**
* A hook executed after rendering of the PCP Pay Later messages wrapper.
*/
do_action( "ppcp_after_{$location_hook}_message_wrapper" );
}
/**
* Renders content after a given block.
*
* @param string $name The name of the block to render after.
* @param string $content The content to be rendered.
* @param int $priority The 'render_block' hook priority.
* @return void
*/
private function render_after_block( string $name, string $content, int $priority = 10 ): void {
add_filter(
'render_block',
/**
* Adds content after a given block.
*
* @param string $block_content The block content.
* @param array|mixed $block_params The block params.
* @return string
*
* @psalm-suppress MissingClosureParamType
*/
function ( $block_content, $block_params ) use ( $name, $content, $priority ) {
if (
is_array( $block_params )
&& ( $block_params['blockName'] ?? null ) === $name
) {
$block_content .= $content;
}
return $block_content;
},
$priority,
2
);
}
/**
* The values for the credit messaging.
*
* @return array
*/
private function message_values(): array {
if ( ! $this->settings_status->is_pay_later_messaging_enabled() ) {
return array();
}
$location = $this->location();
switch ( $location ) {
case 'checkout':
case 'checkout-block':
case 'pay-now':
$placement = 'payment';
break;
case 'cart':
case 'cart-block':
$placement = 'cart';
break;
case 'product':
$placement = 'product';
break;
case 'shop':
$placement = 'product-list';
break;
case 'home':
$placement = 'home';
break;
default:
$placement = 'payment';
break;
}
$product = wc_get_product();
$amount = 0;
if ( is_a( $product, WC_Product::class ) ) {
$amount = wc_get_price_including_tax( $product );
} elseif ( isset( WC()->cart ) ) {
$amount = WC()->cart->get_total( 'raw' );
}
$styling_per_location = $this->settings->has( 'pay_later_enable_styling_per_messaging_location' ) && $this->settings->get( 'pay_later_enable_styling_per_messaging_location' );
$location = $styling_per_location ? $location : 'general';
// Map checkout-block and cart-block message options to checkout and cart options.
switch ( $location ) {
case 'checkout-block':
$location = 'checkout';
break;
case 'cart-block':
$location = 'cart';
break;
default:
break;
}
$setting_name_prefix = "pay_later_{$location}_message";
$layout = $this->settings->has( "{$setting_name_prefix}_layout" ) ? $this->settings->get( "{$setting_name_prefix}_layout" ) : 'text';
$logo_type = $this->settings->has( "{$setting_name_prefix}_logo" ) ? $this->settings->get( "{$setting_name_prefix}_logo" ) : 'primary';
$logo_position = $this->settings->has( "{$setting_name_prefix}_position" ) ? $this->settings->get( "{$setting_name_prefix}_position" ) : 'left';
$text_color = $this->settings->has( "{$setting_name_prefix}_color" ) ? $this->settings->get( "{$setting_name_prefix}_color" ) : 'black';
$style_color = $this->settings->has( "{$setting_name_prefix}_flex_color" ) ? $this->settings->get( "{$setting_name_prefix}_flex_color" ) : 'blue';
$ratio = $this->settings->has( "{$setting_name_prefix}_flex_ratio" ) ? $this->settings->get( "{$setting_name_prefix}_flex_ratio" ) : '1x1';
$text_size = $this->settings->has( "{$setting_name_prefix}_text_size" ) ? $this->settings->get( "{$setting_name_prefix}_text_size" ) : '12';
return array(
'wrapper' => '.ppcp-messages',
'is_hidden' => ! $this->is_pay_later_filter_enabled_for_location( $this->context() ),
'block' => array(
'enabled' => PayLaterBlockModule::is_block_enabled( $this->settings_status ),
),
'amount' => $amount,
'placement' => $placement,
'style' => array(
'layout' => $layout,
'logo' => array(
'type' => $logo_type,
'position' => $logo_position,
),
'text' => array(
'color' => $text_color,
'size' => $text_size,
),
'color' => $style_color,
'ratio' => $ratio,
),
);
}
/**
* Renders the HTML for the DCC fields.
*/
public function dcc_renderer() {
if ( ! $this->can_render_dcc() ) {
return;
}
/**
* The WC filter returning the WC order button text.
* phpcs:disable WordPress.WP.I18n.TextDomainMismatch
*/
$label = 'checkout' === $this->context() ? apply_filters( 'woocommerce_order_button_text', __( 'Place order', 'woocommerce' ) ) : __( 'Pay for order', 'woocommerce' );
// phpcs:enable WordPress.WP.I18n.TextDomainMismatch
printf(
'