File manager - Edit - /home/verseaumee/maze/wp-content/plugins/woocommerce-paypal-payments/modules/ppcp-compat/src/CompatModule.php
Back
<?php /** * The compatibility module. * * @package WooCommerce\PayPalCommerce\Compat */ declare (strict_types=1); namespace WooCommerce\PayPalCommerce\Compat; use Exception; use WC_Order; use WC_Order_Item_Product; use WooCommerce\PayPalCommerce\Button\Session\CartData; use WooCommerce\PayPalCommerce\Settings\Data\PaymentSettings; use WooCommerce\PayPalCommerce\Settings\Data\SettingsModel; use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ExecutableModule; use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ModuleClassNameIdTrait; use WooCommerce\PayPalCommerce\Vendor\Inpsyde\Modularity\Module\ServiceModule; use WooCommerce\PayPalCommerce\Vendor\Psr\Container\ContainerInterface; use WooCommerce\PayPalCommerce\Button\Helper\Context; use WooCommerce\PayPalCommerce\Compat\Assets\CompatAssets; use WooCommerce\PayPalCommerce\WcGateway\Exception\NotFoundException; use WooCommerce\PayPalCommerce\WcGateway\Settings\Settings; /** * Class CompatModule */ class CompatModule implements ServiceModule, ExecutableModule { use ModuleClassNameIdTrait; /** * {@inheritDoc} */ public function services(): array { return require __DIR__ . '/../services.php'; } /** * {@inheritDoc} * * @throws NotFoundException */ public function run(ContainerInterface $c): bool { add_action('woocommerce_init', function () use ($c) { $this->initialize_ppec_compat_layer($c); $this->initialize_tracking_compat_layer($c); }); add_action('init', function () use ($c) { $asset_loader = $c->get('compat.assets'); assert($asset_loader instanceof CompatAssets); $asset_loader->register(); add_action('admin_enqueue_scripts', array($asset_loader, 'enqueue')); }); if (function_exists('WC_GC')) { $context = $c->get('button.helper.context'); assert($context instanceof Context); (new \WooCommerce\PayPalCommerce\Compat\WcGiftCardsCompat($context))->register(); } $this->migrate_pay_later_settings($c); $this->migrate_smart_button_settings($c); $this->migrate_three_d_secure_setting(); $this->migrate_capture_on_status_change(); $this->fix_page_builders(); $this->exclude_cache_plugins_js_minification($c); $is_nyp_active = $c->get('compat.nyp.is_supported_plugin_version_active'); if ($is_nyp_active) { $this->initialize_nyp_compat_layer(); } $is_wc_bookings_active = $c->get('compat.wc_bookings.is_supported_plugin_version_active'); if ($is_wc_bookings_active) { $this->initialize_wc_bookings_compat_layer($c); } $this->initialize_blueprint_compat_layer($c); add_action('woocommerce_paypal_payments_gateway_migrate', static fn() => delete_transient('ppcp_has_ppec_subscriptions')); add_action('woocommerce_paypal_payments_authenticated_merchant', function () { $this->disable_legacy_paypal_standard_on_connect(); }); add_action('admin_notices', function () { $this->maybe_show_wps_subscriptions_notice(); }); $this->legacy_ui_card_payment_mapping($c); /** * Automatically enable Pay Later messaging for Canadian stores during plugin update. * * This action runs during plugin updates to automatically enable Pay Later messaging for stores * that meet the following criteria: * - Store Country is set as Canada * - The "Stay updated" checkbox is enabled * * When all conditions are met, this will: * - Enable Pay Later messaging * - Enable Pay Later Payment Method * - Add default messaging locations (product, cart, checkout) to existing selections * * @hook woocommerce_paypal_payments_gateway_migrate */ add_action('woocommerce_paypal_payments_gateway_migrate', static function () use ($c) { // Check if the "Stay updated" checkbox is enabled (checked in either old or new UI). $settings_model = $c->get('settings.data.settings'); assert($settings_model instanceof SettingsModel); $settings = $c->get('wcgateway.settings'); assert($settings instanceof Settings); // Store Country is set as Canada. if ($c->get('api.shop.country') !== 'CA' || !$settings_model->get_stay_updated()) { return; } // Enable Pay Later messaging. $selected_locations = $settings->has('pay_later_messaging_locations') ? $settings->get('pay_later_messaging_locations') : array(); $settings->set('pay_later_messaging_enabled', \true); $settings->set('pay_later_messaging_locations', array_unique(array_merge($selected_locations, array('product', 'cart', 'checkout')))); $settings->persist(); // Enable Pay Later Payment Method. $payment_settings = $c->get('settings.data.payment'); assert($payment_settings instanceof PaymentSettings); $payment_settings->set_paylater_enabled(\true); $payment_settings->save(); }); return \true; } /** * Sets up the PayPal Express Checkout compatibility layer. * * @param ContainerInterface $container The Container. * @return void */ private function initialize_ppec_compat_layer(ContainerInterface $container): void { $handler = $container->get('compat.ppec.subscriptions-handler'); $handler->maybe_hook(); } /** * Sets up the 3rd party plugins compatibility layer for PayPal tracking. * * @param ContainerInterface $c The Container. * @return void */ protected function initialize_tracking_compat_layer(ContainerInterface $c): void { $order_tracking_integrations = $c->get('order-tracking.integrations'); foreach ($order_tracking_integrations as $integration) { assert($integration instanceof \WooCommerce\PayPalCommerce\Compat\Integration); $integration->integrate(); } } /** * Migrates the old Pay Later button and messaging settings for new Pay Later Tab. * * The migration will be done on plugin upgrade if it hasn't already done. * * @param ContainerInterface $c The Container. * @throws NotFoundException When setting was not found. */ protected function migrate_pay_later_settings(ContainerInterface $c): void { $is_pay_later_settings_migrated_option_name = 'woocommerce_ppcp-is_pay_later_settings_migrated'; $is_pay_later_settings_migrated = get_option($is_pay_later_settings_migrated_option_name); if ($is_pay_later_settings_migrated) { return; } add_action('woocommerce_paypal_payments_gateway_migrate_on_update', function () use ($c, $is_pay_later_settings_migrated_option_name) { $settings = $c->get('wcgateway.settings'); assert($settings instanceof Settings); $disable_funding = $settings->has('disable_funding') ? $settings->get('disable_funding') : array(); $available_messaging_locations = array_keys($c->get('wcgateway.settings.pay-later.messaging-locations')); $available_button_locations = array_keys($c->get('wcgateway.button.locations')); if (in_array('credit', $disable_funding, \true)) { $settings->set('pay_later_button_enabled', \false); } else { $settings->set('pay_later_button_enabled', \true); $selected_button_locations = $this->selected_locations($settings, $available_button_locations, 'button'); if (!empty($selected_button_locations)) { $settings->set('pay_later_button_locations', $selected_button_locations); } } $selected_messaging_locations = $this->selected_locations($settings, $available_messaging_locations, 'message'); if (!empty($selected_messaging_locations)) { $settings->set('pay_later_messaging_enabled', \true); $settings->set('pay_later_messaging_locations', $selected_messaging_locations); $settings->set('pay_later_enable_styling_per_messaging_location', \true); foreach ($selected_messaging_locations as $location) { $this->migrate_message_styling_settings_by_location($settings, $location); } } else { $settings->set('pay_later_messaging_enabled', \false); } $settings->persist(); update_option($is_pay_later_settings_migrated_option_name, \true); }); } /** * Migrates the messages styling setting by given location. * * @param Settings $settings The settings. * @param string $location The location. * @throws NotFoundException When setting was not found. */ protected function migrate_message_styling_settings_by_location(Settings $settings, string $location): void { $old_location = $location === 'checkout' ? '' : "_{$location}"; $layout = $settings->has("message{$old_location}_layout") ? $settings->get("message{$old_location}_layout") : 'text'; $logo_type = $settings->has("message{$old_location}_logo") ? $settings->get("message{$old_location}_logo") : 'primary'; $logo_position = $settings->has("message{$old_location}_position") ? $settings->get("message{$old_location}_position") : 'left'; $text_color = $settings->has("message{$old_location}_color") ? $settings->get("message{$old_location}_color") : 'black'; $style_color = $settings->has("message{$old_location}_flex_color") ? $settings->get("message{$old_location}_flex_color") : 'blue'; $ratio = $settings->has("message{$old_location}_flex_ratio") ? $settings->get("message{$old_location}_flex_ratio") : '1x1'; $settings->set("pay_later_{$location}_message_layout", $layout); $settings->set("pay_later_{$location}_message_logo", $logo_type); $settings->set("pay_later_{$location}_message_position", $logo_position); $settings->set("pay_later_{$location}_message_color", $text_color); $settings->set("pay_later_{$location}_message_flex_color", $style_color); $settings->set("pay_later_{$location}_message_flex_ratio", $ratio); } /** * Finds from old settings the selected locations for given type. * * @param Settings $settings The settings. * @param string[] $all_locations The list of all available locations. * @param string $type The setting type: 'button' or 'message'. * @return string[] The list of locations, which should be selected. */ protected function selected_locations(Settings $settings, array $all_locations, string $type): array { $button_locations = array(); foreach ($all_locations as $location) { $location_setting_name_part = $location === 'checkout' ? '' : "_{$location}"; $setting_name = "{$type}{$location_setting_name_part}_enabled"; if ($settings->has($setting_name) && $settings->get($setting_name)) { $button_locations[] = $location; } } return $button_locations; } /** * Migrates the old smart button settings. * * The migration will be done on plugin upgrade if it hasn't already done. * * @param ContainerInterface $c The Container. */ protected function migrate_smart_button_settings(ContainerInterface $c): void { $is_smart_button_settings_migrated_option_name = 'woocommerce_ppcp-is_smart_button_settings_migrated'; $is_smart_button_settings_migrated = get_option($is_smart_button_settings_migrated_option_name); if ($is_smart_button_settings_migrated) { return; } add_action('woocommerce_paypal_payments_gateway_migrate_on_update', function () use ($c, $is_smart_button_settings_migrated_option_name) { $settings = $c->get('wcgateway.settings'); assert($settings instanceof Settings); $available_button_locations = array_keys($c->get('wcgateway.button.locations')); $selected_button_locations = $this->selected_locations($settings, $available_button_locations, 'button'); if (!empty($selected_button_locations)) { $settings->set('smart_button_locations', $selected_button_locations); $settings->persist(); } update_option($is_smart_button_settings_migrated_option_name, \true); }); } /** * Migrates the old Three D Secure setting located in PaymentSettings to the new location in SettingsModel. * * The migration will be done on plugin update if it hasn't already done. */ protected function migrate_three_d_secure_setting(): void { add_action('woocommerce_paypal_payments_gateway_migrate_on_update', function () { $payment_settings = get_option('woocommerce-ppcp-data-payment') ?: array(); $data_settings = get_option('woocommerce-ppcp-data-settings') ?: array(); // Skip if payment settings don't have the setting but data settings do. if (!isset($payment_settings['three_d_secure']) || isset($data_settings['three_d_secure'])) { return; } // Move the setting. $data_settings['three_d_secure'] = $payment_settings['three_d_secure']; unset($payment_settings['three_d_secure']); // Save both. update_option('woocommerce-ppcp-data-settings', $data_settings); update_option('woocommerce-ppcp-data-payment', $payment_settings); }); } /** * Migrates the "capture on status change" setting from the legacy UI. * * The migration will be done on plugin update if it hasn't already done. */ protected function migrate_capture_on_status_change(): void { add_action('woocommerce_paypal_payments_gateway_migrate_on_update', static function () { $legacy_settings = (array) get_option('woocommerce-ppcp-settings') ?: array(); $payment_settings = (array) get_option('woocommerce-ppcp-data-payment') ?: array(); // Noop if the legacy setting does not exist, or the setting was already migrated. if (!isset($legacy_settings['capture_on_status_change']) || isset($payment_settings['capture_on_status_change'])) { return; } $payment_settings['capture_on_status_change'] = $legacy_settings['capture_on_status_change']; update_option('woocommerce-ppcp-data-payment', $payment_settings); }); } /** * Changes the button rendering place for page builders * that do not work well with our default places. * * @return void */ protected function fix_page_builders(): void { add_action('init', function () { if ($this->is_block_theme_active() || $this->is_elementor_pro_active() || $this->is_divi_theme_active() || $this->is_divi_child_theme_active()) { add_filter('woocommerce_paypal_payments_single_product_renderer_hook', function (): string { return 'woocommerce_after_add_to_cart_form'; }, 5); } }); } /** * Checks whether the current theme is a blocks theme. * * @return bool */ protected function is_block_theme_active(): bool { return function_exists('wp_is_block_theme') && wp_is_block_theme(); } /** * Checks whether the Elementor Pro plugins (allowing integrations with WC) is active. * * @return bool */ protected function is_elementor_pro_active(): bool { return is_plugin_active('elementor-pro/elementor-pro.php'); } /** * Checks whether the Divi theme is currently used. * * @return bool */ protected function is_divi_theme_active(): bool { $theme = wp_get_theme(); return $theme->get('Name') === 'Divi'; } /** * Checks whether a Divi child theme is currently used. * * @return bool */ protected function is_divi_child_theme_active(): bool { $theme = wp_get_theme(); $parent = $theme->parent(); return $parent && $parent->get('Name') === 'Divi'; } /** * Excludes PayPal scripts from being minified by cache plugins. * * @param ContainerInterface $c The Container. * @return void */ protected function exclude_cache_plugins_js_minification(ContainerInterface $c): void { $ppcp_script_names = $c->get('compat.plugin-script-names'); $ppcp_script_file_names = $c->get('compat.plugin-script-file-names'); // Siteground SG Optimize. add_filter('sgo_js_minify_exclude', function (array $scripts) use ($ppcp_script_names) { return array_merge($scripts, $ppcp_script_names); }); // LiteSpeed Cache. add_filter('litespeed_optimize_js_excludes', function (array $excluded_js) use ($ppcp_script_file_names) { return array_merge($excluded_js, $ppcp_script_file_names); }); // W3 Total Cache. add_filter( 'w3tc_minify_js_do_tag_minification', /** * Filter callback for 'w3tc_minify_js_do_tag_minification'. * * @param bool $do_tag_minification Whether to do tag minification. * @param string $script_tag The script tag. * @param string|null $file The file path. * @return bool Whether to do tag minification. * @psalm-suppress MissingClosureParamType */ function (bool $do_tag_minification, string $script_tag, $file) { if ($file && strpos($file, 'ppcp') !== \false) { return \false; } return $do_tag_minification; }, 10, 3 ); } /** * Sets up the compatibility layer for PayPal Shipping callback & WooCommerce Name Your Price plugin. * * @return void */ protected function initialize_nyp_compat_layer(): void { add_filter('woocommerce_paypal_payments_shipping_callback_cart_line_item_total', static function (string $total, array $cart_item) { if (!isset($cart_item['nyp'])) { return $total; } return $cart_item['nyp']; }, 10, 2); } /** * Sets up the compatibility layer for WooCommerce Bookings plugin. * * @param ContainerInterface $container The logger. * @return void */ protected function initialize_wc_bookings_compat_layer(ContainerInterface $container): void { add_action('woocommerce_paypal_payments_woocommerce_order_created_from_cart', static function (WC_Order $wc_order, CartData $cart_data) use ($container): void { try { foreach ($cart_data->items() as $cart_item) { if (empty($cart_item['booking'])) { continue; } foreach ($wc_order->get_items() as $wc_order_item) { if (!$wc_order_item instanceof WC_Order_Item_Product) { continue; } $product_id = $wc_order_item->get_variation_id() ?: $wc_order_item->get_product_id(); $product = wc_get_product($product_id); if (!is_wc_booking_product($product)) { continue; } $booking_data = array('cost' => $cart_item['booking']['_cost'] ?? 0, 'start_date' => $cart_item['booking']['_start_date'] ?? 0, 'end_date' => $cart_item['booking']['_end_date'] ?? 0, 'all_day' => $cart_item['booking']['_all_day'] ?? 0, 'local_timezone' => $cart_item['booking']['_local_timezone'] ?? 0, 'order_item_id' => $wc_order_item->get_id()); if (isset($cart_item['booking']['_resource_id'])) { $booking_data['resource_id'] = $cart_item['booking']['_resource_id']; } if (isset($cart_item['booking']['_persons'])) { $booking_data['persons'] = $cart_item['booking']['_persons']; } create_wc_booking($cart_item['product_id'], $booking_data, 'unpaid'); } } } catch (Exception $exception) { $container->get('woocommerce.logger.woocommerce')->warning('Failed to create booking for WooCommerce Bookings plugin: ' . $exception->getMessage()); } }, 10, 2); } /** * Sets up the WooCommerce Blueprint compatibility layer. * * @param ContainerInterface $container The Container. * @return void */ private function initialize_blueprint_compat_layer(ContainerInterface $container): void { $is_blueprint_available = $container->get('compat.blueprint.is_available'); if (!$is_blueprint_available) { return; } $blueprint_bootstrap = $container->get('compat.blueprint.bootstrap'); $blueprint_bootstrap->init(); } /** * Responsible to keep the credit card payment configuration backwards * compatible with the legacy UI. * * This method can be removed with the #legacy-ui code. * * @param ContainerInterface $container DI container instance. * @return void */ protected function legacy_ui_card_payment_mapping(ContainerInterface $container): void { $new_ui = $container->get('wcgateway.settings.admin-settings-enabled'); if ($new_ui) { return; } add_filter('woocommerce_paypal_payments_is_acdc_active', static function (bool $is_acdc) use ($container): bool { $settings = $container->get('wcgateway.settings'); assert($settings instanceof Settings); try { return (bool) $settings->get('dcc_enabled'); } catch (NotFoundException $exception) { return $is_acdc; } }); } /** * Returns the total count of active/pending-cancel PayPal Standard subscriptions via WCS. * * Checks both the native WPS gateway ID and the restoration plugin gateway ID. * Returns null when WooCommerce Subscriptions is not installed, so callers can * distinguish "WCS absent" from "WCS present but zero subscriptions". * * @return int|null null = WCS not installed; int = total active subscription count. */ protected function count_wps_active_subscriptions(): ?int { if (!function_exists('wcs_get_subscriptions')) { return null; } $total = 0; foreach (array('paypal', 'restore_paypal_standard') as $gateway_id) { $total += count(wcs_get_subscriptions(array('payment_method' => $gateway_id, 'subscription_status' => array('active', 'pending-cancel'), 'subscriptions_per_page' => -1))); } return $total; } /** * Disables the WC core PayPal Standard gateway when a merchant successfully connects PPCP. * * PayPal Standard has a '_should_load' persistence flag that survives the enabled toggle — * both keys must be set to 'no' for the gateway to fully stop loading. This method also * keeps the IPN handler dormant by clearing _should_load, which prevents residual * WOOTHEMES_CART BN code volume from appearing in PayPal partner reporting. * * When WooCommerce Subscriptions detects active subscriptions billed through PayPal Standard * or the restoration plugin, stores a transient instead of disabling — those renewals * depend on the IPN endpoint and cannot be silently migrated. The notice is rendered on the * next admin page load via maybe_show_wps_subscriptions_notice(). */ protected function disable_legacy_paypal_standard_on_connect(): void { $sub_count = $this->count_wps_active_subscriptions(); if ($sub_count !== null && $sub_count > 0) { // Persist count to a transient so the notice survives the AJAX connect request // and appears on the next admin page load. set_transient('ppcp_wps_standard_subs_notice', $sub_count, 30 * DAY_IN_SECONDS); return; } // Safe to disable — no active PayPal Standard subscriptions detected. $settings = get_option('woocommerce_paypal_settings', array()); $settings['enabled'] = 'no'; $settings['_should_load'] = 'no'; // Clears the permanent latch; enabled=no alone is insufficient. update_option('woocommerce_paypal_settings', $settings); // Also disable restore-paypal-standard-for-woocommerce if installed. // That plugin registers gateway ID `restore_paypal_standard` with option key // `woocommerce_restore_paypal_standard_settings` — a dark pool that sends no BN code. // enable-standard-paypal-for-woocommerce uses the native `woocommerce_paypal_settings` key // above, so it is already covered by the write above. $rpsfw = get_option('woocommerce_restore_paypal_standard_settings', array()); if (!empty($rpsfw)) { $rpsfw['enabled'] = 'no'; update_option('woocommerce_restore_paypal_standard_settings', $rpsfw); } } /** * Renders an admin notice when disable_legacy_paypal_standard_on_connect() detected active * PayPal Standard subscriptions and stored a transient instead of disabling the gateway. * * Fires on admin_notices. Uses a transient to bridge the AJAX merchant-connect request * and the next admin page load. */ protected function maybe_show_wps_subscriptions_notice(): void { $count = get_transient('ppcp_wps_standard_subs_notice'); if (\false === $count) { return; } delete_transient('ppcp_wps_standard_subs_notice'); $subscriptions_url = admin_url('edit.php?post_type=shop_subscription&payment_method=paypal'); printf('<div class="notice notice-warning"><p>%s</p></div>', wp_kses_post(sprintf( /* translators: 1: number of subscriptions, 2: URL to subscription list */ _n('PayPal Payments is now your active checkout gateway, but <a href="%2$s">%1$d subscription</a> is still billed through the legacy PayPal Standard gateway. Migrate or cancel these subscriptions before disabling PayPal Standard to avoid missed renewals.', 'PayPal Payments is now your active checkout gateway, but <a href="%2$s">%1$d subscriptions</a> are still billed through the legacy PayPal Standard gateway. Migrate or cancel these subscriptions before disabling PayPal Standard to avoid missed renewals.', (int) $count, 'woocommerce-paypal-payments'), (int) $count, esc_url($subscriptions_url) ))); } }
| ver. 1.4 |
Github
|
.
| PHP 8.5.7 | Generation time: 0 |
proxy
|
phpinfo
|
Settings