| @@ -34,9 +34,9 @@ | ||
| 34 | 34 | public function payment_gateways( array $gateways ) { |
| 35 | 35 | global $plugin_page; |
| 36 | 36 | |
| 37 | 37 | // Early exit for WooCommerce settings, ie: don't show POS gateways. |
| 38 | - if ( is_admin() && 'wc-settings' == $plugin_page ) { | |
| 38 | + if ( self::should_suppress_pos_gateways( is_admin(), $plugin_page ) ) { | |
| 39 | 39 | return $gateways; |
| 40 | 40 | } |
| 41 | 41 | |
| 42 | 42 | // All other cases, the default POS gateways are added. |
| @@ -49,8 +49,29 @@ | ||
| 49 | 49 | ); |
| 50 | 50 | } |
| 51 | 51 | |
| 52 | 52 | /** |
| 53 | + * Decide whether the POS gateways should be withheld from registration. | |
| 54 | + * | |
| 55 | + * Pure policy function: all ambient state is passed in, so it makes no | |
| 56 | + * WordPress calls and reads no globals. | |
| 57 | + * | |
| 58 | + * NOTE: the loose `==` comparison is carried over verbatim from the inline | |
| 59 | + * implementation this was extracted from. `$plugin_page` is a WordPress | |
| 60 | + * global that is commonly `null`, and on PHP 7.4 a loose comparison against | |
| 61 | + * a non-empty string behaves differently from PHP 8 for some falsy values, | |
| 62 | + * so the comparison operator is preserved rather than tightened. | |
| 63 | + * | |
| 64 | + * @param bool $is_admin Result of is_admin() for the current request. | |
| 65 | + * @param mixed $plugin_page The WordPress `$plugin_page` global. | |
| 66 | + * | |
| 67 | + * @return bool True when the POS gateways must not be registered. | |
| 68 | + */ | |
| 69 | + public static function should_suppress_pos_gateways( bool $is_admin, $plugin_page ): bool { | |
| 70 | + return $is_admin && 'wc-settings' == $plugin_page; | |
| 71 | + } | |
| 72 | + | |
| 73 | + /** | |
| 53 | 74 | * Get available payment POS gateways, |
| 54 | 75 | * - Order and set default order |
| 55 | 76 | * - Also going to remove icons from the gateways. |
| 56 | 77 | * |
| @@ -68,14 +89,50 @@ | ||
| 68 | 89 | |
| 69 | 90 | // use POS settings. |
| 70 | 91 | $settings = woocommerce_pos_get_settings( 'payment_gateways' ); |
| 71 | 92 | |
| 72 | - // Get all payment gateways. | |
| 93 | + /* | |
| 94 | + * Get all payment gateways. | |
| 95 | + * | |
| 96 | + * NOTE: this reads the public `payment_gateways` property directly rather | |
| 97 | + * than calling the `payment_gateways()` accessor. Preserved verbatim - the | |
| 98 | + * two are not interchangeable in every WooCommerce version. | |
| 99 | + */ | |
| 73 | 100 | $all_gateways = WC()->payment_gateways->payment_gateways; |
| 74 | 101 | |
| 102 | + return self::order_gateways( $all_gateways, $settings ); | |
| 103 | + } | |
| 104 | + | |
| 105 | + /** | |
| 106 | + * Apply the POS gateway availability, presentation and ordering policy. | |
| 107 | + * | |
| 108 | + * Selects the gateways enabled in the POS `payment_gateways` settings, | |
| 109 | + * overrides each one's title, blanks its icon, forces it enabled and marks the | |
| 110 | + * configured `default_gateway` as chosen, then sorts the result by the | |
| 111 | + * per-gateway `order` setting. | |
| 112 | + * | |
| 113 | + * Free of ambient state - it makes no WordPress calls and reads no globals, so | |
| 114 | + * it can be exercised directly in unit tests. It is NOT side-effect free: the | |
| 115 | + * gateway objects are mutated in place, which in production means the live | |
| 116 | + * `WC()->payment_gateways->payment_gateways` singletons. That is the existing | |
| 117 | + * mechanism (Admin\Orders\Single_Order::add_available_gateways() relies on the | |
| 118 | + * same singleton mutation) and is preserved deliberately. | |
| 119 | + * | |
| 120 | + * NOTE: neither parameter carries a native typehint. Lots of plugins/themes | |
| 121 | + * call the `woocommerce_available_payment_gateways` filter and neither the | |
| 122 | + * gateway list nor the settings shape is guaranteed; a native `array` here | |
| 123 | + * would turn today's warning into an uncatchable TypeError on the payment | |
| 124 | + * path. Behaviour for unexpected shapes is preserved exactly as it was inline. | |
| 125 | + * | |
| 126 | + * @param array $gateways All registered payment gateway objects. | |
| 127 | + * @param array $settings The POS `payment_gateways` settings blob. | |
| 128 | + * | |
| 129 | + * @return array The enabled gateways, keyed by gateway id, in settings order. | |
| 130 | + */ | |
| 131 | + public static function order_gateways( $gateways, $settings ): array { | |
| 75 | 132 | $_available_gateways = array(); |
| 76 | 133 | |
| 77 | - foreach ( $all_gateways as $gateway ) { | |
| 134 | + foreach ( $gateways as $gateway ) { | |
| 78 | 135 | if ( isset( $settings['gateways'][ $gateway->id ] ) && $settings['gateways'][ $gateway->id ]['enabled'] ) { |
| 79 | 136 | if ( isset( $settings['gateways'][ $gateway->id ]['title'] ) ) { |
| 80 | 137 | $gateway->title = $settings['gateways'][ $gateway->id ]['title']; |
| 81 | 138 | } |
| @@ -95,13 +152,17 @@ | ||
| 95 | 152 | $_available_gateways[ $gateway->id ] = $gateway; |
| 96 | 153 | } |
| 97 | 154 | } |
| 98 | 155 | |
| 99 | - // Order the available gateways according to the settings. | |
| 156 | + /* | |
| 157 | + * Order the available gateways according to the settings. | |
| 158 | + * | |
| 159 | + * Gateways without an explicit order sort after configured gateways. | |
| 160 | + */ | |
| 100 | 161 | uksort( |
| 101 | 162 | $_available_gateways, |
| 102 | 163 | function ( $a, $b ) use ( $settings ) { |
| 103 | - return $settings['gateways'][ $a ]['order'] <=> $settings['gateways'][ $b ]['order']; | |
| 164 | + return ( $settings['gateways'][ $a ]['order'] ?? PHP_INT_MAX ) <=> ( $settings['gateways'][ $b ]['order'] ?? PHP_INT_MAX ); | |
| 104 | 165 | } |
| 105 | 166 | ); |
| 106 | 167 | |
| 107 | 168 | return $_available_gateways; |