Settings
1 week ago
BlockHooks.php
1 week ago
BlockHooksFactory.php
1 week ago
Factory.php
1 year ago
Hooks.php
1 week ago
Strings.php
1 week ago
Hooks.php
289 lines
| 1 | <?php |
| 2 | |
| 3 | namespace WCML\PaymentGateways; |
| 4 | |
| 5 | use IWPML_Backend_Action; |
| 6 | use IWPML_Frontend_Action; |
| 7 | use IWPML_DIC_Action; |
| 8 | use WCML\MultiCurrency\Geolocation; |
| 9 | use WCML\StandAlone\IStandAloneAction; |
| 10 | use WCML\Utilities\Resources; |
| 11 | use WCML\Utilities\AdminUrl; |
| 12 | use WPML\API\Sanitize; |
| 13 | use WPML\FP\Fns; |
| 14 | use WPML\FP\Logic; |
| 15 | use WPML\FP\Maybe; |
| 16 | use WPML\FP\Obj; |
| 17 | use WPML\FP\Relation; |
| 18 | use WPML\FP\Str; |
| 19 | use WPML\FP\Type; |
| 20 | |
| 21 | class Hooks implements IWPML_Backend_Action, IWPML_Frontend_Action, IWPML_DIC_Action, IStandAloneAction { |
| 22 | |
| 23 | const OPTION_KEY = 'wcml_payment_gateways'; |
| 24 | const PRIORITY = 1000; |
| 25 | |
| 26 | public function add_hooks() { |
| 27 | |
| 28 | if ( is_admin() ) { |
| 29 | if ( $this->isWCGatewaysSettingsScreen() ) { |
| 30 | add_action( 'woocommerce_update_options_checkout', [ $this, 'updateSettingsOnSave' ], self::PRIORITY ); |
| 31 | add_action( 'woocommerce_settings_checkout', [ $this, 'outputInSettings' ], self::PRIORITY ); |
| 32 | add_action( 'woocommerce_after_settings_checkout', [ $this, 'outputAfterSettings' ], self::PRIORITY ); |
| 33 | if( $this->isWooC10_1_Spa() ) { |
| 34 | add_action( 'admin_enqueue_scripts', [ $this, 'loadSPAAssets' ] ); |
| 35 | } else { |
| 36 | add_action( 'admin_enqueue_scripts', [ $this, 'loadClassicAssets' ] ); |
| 37 | } |
| 38 | } |
| 39 | add_action( 'admin_notices', [ $this, 'maybeAddNotice' ] ); |
| 40 | add_action( 'wp_ajax_wcml_save_payment_gateways', [ $this, 'updateSettingsOnAjaxSave' ] ); |
| 41 | } else { |
| 42 | add_filter( 'woocommerce_available_payment_gateways', [ $this, 'filterByCountry' ], self::PRIORITY ); |
| 43 | } |
| 44 | } |
| 45 | |
| 46 | public function updateSettingsOnSave() { |
| 47 | |
| 48 | if ( isset( $_POST[ self::OPTION_KEY ] ) ) { |
| 49 | |
| 50 | $gatewaySettings = $_POST[ self::OPTION_KEY ]; |
| 51 | $gatewayId = Sanitize::stringProp( 'ID', $gatewaySettings ); |
| 52 | |
| 53 | $this->updateGatewaySettings( $gatewayId, $gatewaySettings ); |
| 54 | } |
| 55 | } |
| 56 | |
| 57 | public function updateSettingsOnAjaxSave() { |
| 58 | $nonce = array_key_exists( 'nonce', $_POST ) ? sanitize_text_field( $_POST['nonce'] ) : false; |
| 59 | if ( ! $nonce || ! wp_verify_nonce( $nonce, self::OPTION_KEY ) ) { |
| 60 | wp_send_json_error(); |
| 61 | } |
| 62 | |
| 63 | $data = json_decode( stripslashes( Obj::propOr( '{}', 'data', $_POST ) ), true ); |
| 64 | $gatewayId = Obj::prop( 'gatewayId', $data ); |
| 65 | $gatewaySettings = Obj::prop( 'settings', $data ); |
| 66 | |
| 67 | $updated = $this->updateGatewaySettings( $gatewayId, $gatewaySettings ); |
| 68 | |
| 69 | if ( $updated ) { |
| 70 | wp_send_json_success(); |
| 71 | } else { |
| 72 | wp_send_json_error(); |
| 73 | } |
| 74 | |
| 75 | } |
| 76 | |
| 77 | private function updateGatewaySettings( $gatewayId, $gatewaySettings ) { |
| 78 | $settings = $this->getSettings(); |
| 79 | $settingsSignature = maybe_serialize( $settings ); |
| 80 | |
| 81 | $settings[ $gatewayId ]['mode'] = isset( $gatewaySettings['mode'] ) && in_array( $gatewaySettings['mode'], [ |
| 82 | 'all', |
| 83 | 'exclude', |
| 84 | 'include' |
| 85 | ], true ) ? $gatewaySettings['mode'] : 'all'; |
| 86 | |
| 87 | $countries = Logic::ifElse( |
| 88 | Type::isString(), |
| 89 | Str::split( ',' ), |
| 90 | Fns::identity(), |
| 91 | Obj::propOr( [], 'countries', $gatewaySettings ) |
| 92 | ); |
| 93 | |
| 94 | $validCountries = wpml_collect( WC()->countries->get_countries() )->keys()->toArray(); |
| 95 | |
| 96 | $isValidCountry = function( $country ) use ( $validCountries ) { |
| 97 | return in_array( $country, $validCountries, true ); |
| 98 | }; |
| 99 | |
| 100 | $settings[ $gatewayId ]['countries'] = wpml_collect( $countries ) |
| 101 | ->filter( $isValidCountry ) |
| 102 | ->values() |
| 103 | ->toArray(); |
| 104 | |
| 105 | $updatedSettingsSignature = maybe_serialize( $settings ); |
| 106 | |
| 107 | if ( $settingsSignature === $updatedSettingsSignature ) { |
| 108 | return true; |
| 109 | } |
| 110 | |
| 111 | return $this->updateSettings( $settings ); |
| 112 | } |
| 113 | |
| 114 | public function loadClassicAssets() { |
| 115 | $enqueue = Resources::enqueueApp( 'paymentGatewaysAdmin' ); |
| 116 | $gatewayId = sanitize_title( $_GET['section'] ); |
| 117 | |
| 118 | $enqueue( [ |
| 119 | 'name' => 'wcmlPaymentGateways', |
| 120 | 'data' => [ |
| 121 | 'endpoint' => self::OPTION_KEY, |
| 122 | 'gatewayId' => $gatewayId, |
| 123 | 'allCountries' => $this->getAllCountries(), |
| 124 | 'strings' => $this->getStrings(), |
| 125 | 'settings' => $this->getGatewaySettings( $gatewayId ), |
| 126 | ], |
| 127 | ] ); |
| 128 | |
| 129 | wp_register_style( 'wcml-payment-gateways', WCML_PLUGIN_URL . '/res/css/wcml-payment-gateways.css', [], WCML_VERSION ); |
| 130 | wp_enqueue_style( 'wcml-payment-gateways' ); |
| 131 | } |
| 132 | |
| 133 | public function loadSpaAssets() { |
| 134 | $enqueue = Resources::enqueueApp( 'paymentGatewaysAdminSPA' ); |
| 135 | |
| 136 | $allGatewaySettings = get_option( self::OPTION_KEY, [] ); |
| 137 | $allGatewaySettings['_default'] = [ 'mode' => 'all', 'countries' => [] ]; |
| 138 | |
| 139 | $enqueue( [ |
| 140 | 'name' => 'wcmlPaymentGateways', |
| 141 | 'data' => [ |
| 142 | 'endpoint' => self::OPTION_KEY, |
| 143 | 'gatewayId' => null, |
| 144 | 'allCountries' => $this->getAllCountries(), |
| 145 | 'strings' => $this->getStrings(), |
| 146 | 'settings' => $allGatewaySettings, |
| 147 | ], |
| 148 | ] ); |
| 149 | |
| 150 | wp_register_style( 'wcml-payment-gateways', WCML_PLUGIN_URL . '/res/css/wcml-payment-gateways.css', [], WCML_VERSION ); |
| 151 | wp_enqueue_style( 'wcml-payment-gateways' ); |
| 152 | } |
| 153 | |
| 154 | private function getStrings() { |
| 155 | return [ |
| 156 | 'translationInstructions' => Strings::getTranslationInstructions(), |
| 157 | 'labelAvailability' => __( 'Country availability', 'woocommerce-multilingual' ), |
| 158 | 'labelAllCountries' => __( 'All countries', 'woocommerce-multilingual' ), |
| 159 | 'labelAllCountriesExcept' => __( 'All countries except', 'woocommerce-multilingual' ), |
| 160 | 'labelAllCountriesExceptDots' => __( 'All countries except...', 'woocommerce-multilingual' ), |
| 161 | 'labelSpecificCountries' => __( 'Specific countries', 'woocommerce-multilingual' ), |
| 162 | 'tooltip' => __( 'Configure per country availability for this payment gateway', 'woocommerce-multilingual' ), |
| 163 | 'submitButton' => [ |
| 164 | 'label' => __( 'Save changes', 'woocommerce-multilingual' ), |
| 165 | 'success' => __( 'Settings saved.', 'woocommerce-multilingual' ), |
| 166 | 'error' => __( 'Error saving settings.', 'woocommerce-multilingual' ), |
| 167 | ], |
| 168 | ]; |
| 169 | } |
| 170 | |
| 171 | private function getAllCountries() { |
| 172 | |
| 173 | $buildCountry = function ( $label, $code ) { |
| 174 | return (object) [ |
| 175 | 'code' => $code, |
| 176 | 'label' => html_entity_decode( $label ), |
| 177 | ]; |
| 178 | }; |
| 179 | |
| 180 | return wpml_collect( WC()->countries->get_countries() )->map( $buildCountry )->values()->toArray(); |
| 181 | } |
| 182 | |
| 183 | private function isSubmitButtonHidden() { |
| 184 | return ! empty( $GLOBALS['hide_save_button'] ); |
| 185 | } |
| 186 | |
| 187 | public function outputInSettings() { |
| 188 | if ( ! $this->isSubmitButtonHidden() ) { |
| 189 | $this->output(); |
| 190 | } |
| 191 | } |
| 192 | |
| 193 | public function outputAfterSettings() { |
| 194 | if ( $this->isSubmitButtonHidden() ) { |
| 195 | ?> |
| 196 | <div id="wcml-after-mainform"> |
| 197 | <?php |
| 198 | $this->output(); |
| 199 | ?> |
| 200 | </div> |
| 201 | <?php |
| 202 | } |
| 203 | } |
| 204 | |
| 205 | public function output() { |
| 206 | ?><h2>WPML Multilingual & Multicurrency for WooCommerce</h2><div id="wcml-payment-gateways"></div><?php |
| 207 | } |
| 208 | |
| 209 | public function filterByCountry( $payment_gateways ) { |
| 210 | |
| 211 | $customer_country = Geolocation::getUserCountry(); |
| 212 | |
| 213 | if ( $customer_country ) { |
| 214 | |
| 215 | $ifExceptCountries = function ( $gateway ) use ( $customer_country ) { |
| 216 | $gatewaySettings = $this->getGatewaySettings( $gateway->id ); |
| 217 | |
| 218 | return $gatewaySettings['mode'] == 'exclude' && in_array( $customer_country, $gatewaySettings['countries'] ); |
| 219 | }; |
| 220 | |
| 221 | $ifNotIncluded = function ( $gateway ) use ( $customer_country ) { |
| 222 | $gatewaySettings = $this->getGatewaySettings( $gateway->id ); |
| 223 | |
| 224 | return $gatewaySettings['mode'] == 'include' && ! in_array( $customer_country, $gatewaySettings['countries'] ); |
| 225 | }; |
| 226 | |
| 227 | return wpml_collect( $payment_gateways ) |
| 228 | ->reject( $ifExceptCountries ) |
| 229 | ->reject( $ifNotIncluded ) |
| 230 | ->toArray(); |
| 231 | } |
| 232 | |
| 233 | return $payment_gateways; |
| 234 | } |
| 235 | |
| 236 | public function maybeAddNotice(){ |
| 237 | if( class_exists( 'WooCommerce_Gateways_Country_Limiter' ) ) { |
| 238 | echo $this->getNoticeText(); |
| 239 | } |
| 240 | } |
| 241 | |
| 242 | private function getNoticeText(){ |
| 243 | |
| 244 | $text = '<div id="message" class="updated error">'; |
| 245 | $text .= '<p>'; |
| 246 | $text .= __( 'We noticed that you\'re using WooCommerce Gateways Country Limiter plugin which is now integrated into WPML Multilingual & Multicurrency for WooCommerce. Please remove it!', 'woocommerce-multilingual' ); |
| 247 | $text .= '</p>'; |
| 248 | $text .= '</div>'; |
| 249 | |
| 250 | return $text; |
| 251 | } |
| 252 | |
| 253 | private function getGatewaySettings( $gatewayId ) { |
| 254 | return Maybe::fromNullable( get_option( self::OPTION_KEY, false ) ) |
| 255 | ->map( Obj::prop( $gatewayId ) ) |
| 256 | ->getOrElse( [ 'mode' => 'all', 'countries' => [] ] ); |
| 257 | } |
| 258 | |
| 259 | private function getSettings() { |
| 260 | return get_option( self::OPTION_KEY, [] ); |
| 261 | } |
| 262 | |
| 263 | private function updateSettings( $settings ) { |
| 264 | return update_option( self::OPTION_KEY, $settings ); |
| 265 | } |
| 266 | |
| 267 | private function isWCGatewaysSettingsScreen() { |
| 268 | if ( $this->isWooC10_1_Spa() ) { |
| 269 | return $this->isWCGatewaysSettingsScreenSPA(); |
| 270 | } |
| 271 | |
| 272 | return Obj::prop( 'section', $_GET ) |
| 273 | && Relation::equals( AdminUrl::PAGE_WOO_SETTINGS, Obj::prop( 'page', $_GET ) ) |
| 274 | && Relation::equals( 'checkout', Obj::prop( 'tab', $_GET ) ) |
| 275 | && ! Relation::propEq( 'section', 'offline', $_GET ); |
| 276 | } |
| 277 | |
| 278 | private function isWooC10_1_Spa(): bool { |
| 279 | return (bool) Obj::prop( 'path', $_GET ); |
| 280 | } |
| 281 | |
| 282 | private function isWCGatewaysSettingsScreenSPA(): bool { |
| 283 | return Obj::prop( 'path', $_GET ) |
| 284 | && Relation::equals( AdminUrl::PAGE_WOO_SETTINGS, Obj::prop( 'page', $_GET ) ) |
| 285 | && Relation::equals( 'checkout', Obj::prop( 'tab', $_GET ) ); |
| 286 | } |
| 287 | |
| 288 | } |
| 289 |