1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
|
<?php declare( strict_types=1 );
namespace Automattic\WooCommerce\Internal\Admin\Settings;
use Automattic\WooCommerce\Admin\Features\Features; use Automattic\WooCommerce\Internal\Admin\Suggestions\PaymentExtensionSuggestions; use Exception; use WooCommerce\Admin\Experimental_Abtest;
defined( 'ABSPATH' ) || exit; /** * Payments settings controller class. * * Use this class for hooks and actions related to the Payments settings page. */ class PaymentsController {
/** * The payment service. * * @var Payments */ private Payments $payments;
/** * Register hooks. */ public function register() { // Filter the feature config to allow the experiment to have effect. // Use a priority of 9 to ensure that the filter runs before the user-set feature values // are applied by the WC Beta Tester plugin. // This way we allow users to control the feature flag via the WC Beta Tester plugin and disregard the experiment. // @see plugins/woocommerce-beta-tester/plugin.php. add_filter( 'woocommerce_admin_get_feature_config', array( $this, 'filter_feature_config_experiment' ), 9 );
// Because we gate the hooking based on a feature flag, // we need to delay the registration until the 'woocommerce_init' hook. // Otherwise, we end up in an infinite loop. add_action( 'woocommerce_init', array( $this, 'delayed_register' ) ); }
/** * Filter the feature flags list to modify the new Payments Settings page feature based on the experiment. * * @param array $features The feature flags list. * * @return array The updated feature flags list. */ public function filter_feature_config_experiment( $features ) { // If the feature flag is not present or has been disabled, don't do anything. if ( empty( $features['reactify-classic-payments-settings'] ) ) { return $features; }
// If the feature flag is enabled, but the user is NOT in the experiment treatment group, disable the feature. if ( ! Experimental_Abtest::in_treatment_handled_exception( 'woocommerce_payment_settings_2025_v1' ) ) { return array_merge( $features, array( 'reactify-classic-payments-settings' => false, ) ); }
return $features; }
/** * Delayed hook registration. */ public function delayed_register() { // Don't do anything if the feature is not enabled. if ( ! Features::is_enabled( 'reactify-classic-payments-settings' ) ) { return; }
add_action( 'admin_menu', array( $this, 'add_menu' ) ); add_filter( 'woocommerce_admin_shared_settings', array( $this, 'preload_settings' ) ); add_filter( 'woocommerce_admin_allowed_promo_notes', array( $this, 'add_allowed_promo_notes' ) ); }
/** * Initialize the class instance. * * @param Payments $payments The payments service. * * @internal */ final public function init( Payments $payments ): void { $this->payments = $payments; }
/** * Adds the Payments top-level menu item. */ public function add_menu() { global $menu;
// The WooPayments plugin must not be active. // When active, WooPayments will own the Payments menu item since it is the native Woo payments solution. if ( $this->is_woopayments_active() ) { return; }
$menu_title = esc_html__( 'Payments', 'woocommerce' ); $menu_icon = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI4NTIiIGhlaWdodD0iNjg0Ij48cGF0aCBmaWxsPSIjYTJhYWIyIiBkPSJNODIgODZ2NTEyaDY4NFY4NlptMCA1OThjLTQ4IDAtODQtMzgtODQtODZWODZDLTIgMzggMzQgMCA4MiAwaDY4NGM0OCAwIDg0IDM4IDg0IDg2djUxMmMwIDQ4LTM2IDg2LTg0IDg2em0zODQtNTU2djQ0aDg2djg0SDM4MnY0NGgxMjhjMjQgMCA0MiAxOCA0MiA0MnYxMjhjMCAyNC0xOCA0Mi00MiA0MmgtNDR2NDRoLTg0di00NGgtODZ2LTg0aDE3MHYtNDRIMzM4Yy0yNCAwLTQyLTE4LTQyLTQyVjIxNGMwLTI0IDE4LTQyIDQyLTQyaDQ0di00NHoiLz48L3N2Zz4='; // Link to the Payments settings page. $menu_path = 'admin.php?page=wc-settings&tab=checkout';
add_menu_page( $menu_title, $menu_title, 'manage_woocommerce', // Capability required to see the menu item. $menu_path, null, $menu_icon, 56, // Position after WooCommerce Product menu item. );
// If there are providers with active incentive, add a notice badge to the Payments menu item. if ( $this->store_has_providers_with_incentive() ) { $badge = ' <span class="wcpay-menu-badge awaiting-mod count-1"><span class="plugin-count">1</span></span>'; foreach ( $menu as $index => $menu_item ) { // Only add the badge markup if not already present and the menu item is the Payments menu item. if ( 0 === strpos( $menu_item[0], $menu_title ) && $menu_path === $menu_item[2] && false === strpos( $menu_item[0], $badge ) ) {
$menu[ $index ][0] .= $badge; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
// One menu item with a badge is more than enough. break; } } } }
/** * Preload settings to make them available to the Payments settings page frontend logic. * * Added keys will be available in the window.wcSettings.admin object. * * @param array $settings The settings array. * * @return array Settings array with additional settings added. */ public function preload_settings( array $settings ): array { // We only preload settings in the WP admin. if ( ! is_admin() ) { return $settings; }
// Add the business location country to the settings. if ( ! isset( $settings[ Payments::USER_PAYMENTS_NOX_PROFILE_KEY ] ) ) { $settings[ Payments::USER_PAYMENTS_NOX_PROFILE_KEY ] = array(); } $settings[ Payments::USER_PAYMENTS_NOX_PROFILE_KEY ]['business_country_code'] = $this->payments->get_country();
return $settings; }
/** * Adds promo note IDs to the list of allowed ones. * * @param array $promo_notes Allowed promo note IDs. * * @return array The updated list of allowed promo note IDs. */ public function add_allowed_promo_notes( array $promo_notes = array() ): array { try { $providers = $this->payments->get_payment_providers( $this->payments->get_country() ); } catch ( Exception $e ) { // In case of an error, bail. return $promo_notes; }
// Add all incentive promo IDs to the allowed promo notes list. foreach ( $providers as $provider ) { if ( ! empty( $provider['_incentive']['promo_id'] ) ) { $promo_notes[] = $provider['_incentive']['promo_id']; } }
return $promo_notes; }
/** * Check if the store has any enabled gateways (including offline payment methods). * * @return bool True if the store has any enabled gateways, false otherwise. */ private function store_has_enabled_gateways(): bool { $gateways = WC()->payment_gateways->get_available_payment_gateways(); $enabled_gateways = array_filter( $gateways, function ( $gateway ) { return 'yes' === $gateway->enabled; } );
return ! empty( $enabled_gateways ); }
/** * Check if the store has any payment providers that have an active incentive. * * @return bool True if the store has providers with an active incentive. */ private function store_has_providers_with_incentive(): bool { try { $providers = $this->payments->get_payment_providers( $this->payments->get_country() ); } catch ( Exception $e ) { // In case of an error, just return false. return false; }
// Go through the providers and check if any of them have a "prominently" visible incentive (i.e., modal or banner). foreach ( $providers as $provider ) { // We check to see if the incentive was dismissed in the banner context. // In case an incentive uses the modal surface also (like the WooPayments Switch incentive), // we rely on the fact that the modal falls back to the banner, once dismissed. if ( ! empty( $provider['_incentive'] ) && ( empty( $provider['_incentive']['_dismissals'] ) || ! in_array( 'wc_settings_payments__banner', $provider['_incentive']['_dismissals'], true ) ) ) { return true; } }
return false; }
/** * Check if the WooPayments plugin is active. * * @return boolean */ private function is_woopayments_active(): bool { return class_exists( '\WC_Payments' ); } }
|