cardBrandHelper = $cardBrandHelper; $this->id = MONEI_GATEWAY_ID; $this->method_title = __( 'MONEI - Credit Card', 'monei' ); $this->method_description = __( 'Accept credit card payments.', 'monei' ); $this->enabled = ( ! empty( $this->get_option( 'enabled' ) ) && 'yes' === $this->get_option( 'enabled' ) && $this->is_valid_for_use() ) ? 'yes' : 'no'; // Load the form fields. $this->init_form_fields(); // Load the settings. $this->init_settings(); $description = ! empty( $this->get_option( 'description' ) ) ? $this->get_option( 'description' ) : ''; // Non-breaking space if description is empty // Hosted payment with redirect. $this->has_fields = false; $iconUrl = apply_filters( 'woocommerce_monei_icon', WC_Monei()->image_url( 'monei-cards.svg' ) ); $iconMarkup = 'MONEI'; // Settings variable $this->hide_logo = ( ! empty( $this->get_option( 'hide_logo' ) ) && 'yes' === $this->get_option( 'hide_logo' ) ) ? true : false; // Hide logo if card brands are available $cardBrands = $this->cardBrandHelper->getCardBrandsConfig(); $hasCardBrands = ! empty( $cardBrands ) && count( array_filter( array_keys( $cardBrands ), fn( $key ) => $key !== 'default' ) ) > 0; $this->icon = ( $this->hide_logo || $hasCardBrands ) ? '' : $iconMarkup; $this->redirect_flow = ( ! empty( $this->get_option( 'mode' ) ) && 'yes' === $this->get_option( 'mode' ) ) ? true : false; $this->testmode = $this->getTestmode(); $hide_title = ( ! empty( $this->get_option( 'hide_title' ) ) && 'yes' === $this->get_option( 'hide_title' ) ) ? true : false; $this->title = ( ! $hide_title && ! empty( $this->get_option( 'title' ) ) ) ? $this->get_option( 'title' ) : ''; if ( $this->testmode && ! empty( $this->title ) ) { $this->title .= ' (' . __( 'Test Mode', 'monei' ) . ')'; } $this->description = ( ! empty( $this->get_option( 'description' ) ) ) ? $this->get_option( 'description' ) : ''; // Backward compatible: try local setting first, then global setting $local_orderdo = $this->get_option( 'orderdo' ); $this->status_after_payment = ! empty( $local_orderdo ) ? $local_orderdo : get_option( 'monei_orderdo', 'processing' ); $this->account_id = $this->getAccountId(); $this->api_key = $this->getApiKey(); $this->shop_name = get_bloginfo( 'name' ); $this->password = ( ! empty( $this->get_option( 'password' ) ) ) ? $this->get_option( 'password' ) : ''; $this->tokenization = ( ! empty( $this->get_option( 'tokenization' ) ) && 'yes' === $this->get_option( 'tokenization' ) ) ? true : false; // Backward compatible: try local setting first, then global setting $local_preauth = $this->get_option( 'pre-authorize' ); $global_preauth = get_option( 'monei_pre_authorize', 'no' ); $this->pre_auth = ( ! empty( $local_preauth ) && 'yes' === $local_preauth ) || ( empty( $local_preauth ) && 'yes' === $global_preauth ); $this->logging = ( ! empty( get_option( 'monei_debug' ) ) && 'yes' === get_option( 'monei_debug' ) ) ? true : false; // IPN callbacks $this->notify_url = WC_Monei()->get_ipn_url(); new WC_Monei_IPN( $this->logging ); $this->supports = array( 'products', 'refunds', ); if ( $this->tokenization ) { $this->supports[] = 'tokenization'; } $this->subscriptions_service = $subscriptionService; $this->handler = $this->subscriptions_service->getHandler(); if ( $this->handler ) { $this->supports = $this->handler->init_subscriptions( $this->supports, $this->id ); } add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options', ) ); add_filter( 'woocommerce_save_settings_checkout_' . $this->id, function ( $is_post ) { return $this->checks_before_save( $is_post, 'woocommerce_monei_enabled' ); } ); add_action( 'wp_enqueue_scripts', array( $this, 'monei_scripts' ) ); // Add new total on checkout updates (ex, selecting different shipping methods) add_filter( 'woocommerce_update_order_review_fragments', function ( $fragments ) { return self::add_cart_total_fragments( $fragments ); } ); } /** * Return whether or not this gateway still requires setup to function. * * When this gateway is toggled on via AJAX, if this returns true a * redirect will occur to the settings page instead. * * @return bool * @since 3.4.0 */ public function needs_setup() { if ( ! $this->account_id || ! $this->api_key ) { return true; } return false; } /** * Initialise Gateway Settings Form Fields * * @access public * @return void * @since 5.0 */ public function init_form_fields() { $this->form_fields = require WC_Monei()->plugin_path() . '/includes/admin/monei-cc-settings.php'; } /** * Validate card_input_style field * * @param string $key * @param string $value * @return string */ public function validate_card_input_style_field( $key, $value ) { if ( empty( $value ) ) { return $value; } // WordPress adds slashes to $_POST data, we need to remove them before validating JSON $value = stripslashes( $value ); // Try to decode JSON $decoded = json_decode( $value, true ); // Check for JSON errors if ( json_last_error() !== JSON_ERROR_NONE ) { WC_Admin_Settings::add_error( sprintf( /* translators: %s: JSON error message */ __( 'Card Input Style field contains invalid JSON: %s', 'monei' ), json_last_error_msg() ) ); return $this->get_option( 'card_input_style', self::DEFAULT_CARD_INPUT_STYLE ); } // Re-encode with pretty print for better readability in admin return wp_json_encode( $decoded, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ); } /** * Process the payment and return the result * * @access public * * @param int $order_id * @param null $allowed_payment_method * * @return array */ public function process_payment( $order_id, $allowed_payment_method = null ) { return parent::process_payment( $order_id, self::PAYMENT_METHOD ); } /** * Add payment method in Account add_payment_method_page. * * @return array */ public function add_payment_method() { $nonce = isset( $_POST['woocommerce-add-payment-method-nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['woocommerce-add-payment-method-nonce'] ) ) : ''; if ( ! $nonce || ! wp_verify_nonce( $nonce, 'woocommerce-add-payment-method' ) ) { return array( 'result' => 'failure', 'redirect' => wc_get_endpoint_url( 'payment-methods' ), ); } // Since it is a hosted version, we need to create a 0 EUR payment and send customer to MONEI. try { $zero_payload = $this->create_zero_eur_payload(); $payment = $this->moneiPaymentServices->create_payment( $zero_payload ); $this->log( 'WC_Monei_API::add_payment_method', 'debug' ); $this->log( $zero_payload, 'debug' ); $this->log( $payment, 'debug' ); do_action( 'wc_gateway_monei_add_payment_method_success', $zero_payload, $payment ); return array( 'result' => 'success', 'redirect' => $payment->getNextAction()->getRedirectUrl(), ); } catch ( Exception $e ) { $this->log( $e, 'error' ); wc_add_notice( $e->getMessage(), 'error' ); return array( 'result' => 'failure', 'redirect' => wc_get_endpoint_url( 'payment-methods' ), ); } } /** * @return array */ protected function create_zero_eur_payload() { $current_user_id = (string) get_current_user_id(); /** Create 0 EUR Payment Payload */ $payload = array( 'amount' => 0, 'currency' => get_woocommerce_currency(), 'orderId' => $current_user_id . 'generatetoken' . wp_rand( 0, 1000000 ), 'description' => "User $current_user_id creating empty transaction to generate token", 'callbackUrl' => esc_url_raw( $this->notify_url ), 'completeUrl' => esc_url_raw( wc_get_account_endpoint_url( 'payment-methods' ) ), 'cancelUrl' => esc_url_raw( wc_get_account_endpoint_url( 'payment-methods' ) ), 'failUrl' => esc_url_raw( wc_get_account_endpoint_url( 'payment-methods' ) ), 'transactionType' => self::VERIFY_TRANSACTION_TYPE, 'sessionDetails' => array( 'ip' => WC_Geolocation::get_ip_address(), 'userAgent' => wc_get_user_agent(), ), 'generatePaymentToken' => true, 'allowedPaymentMethods' => array( self::PAYMENT_METHOD ), ); // All Zero payloads ( add payment method ) will use component CC. $monei_token = $this->get_frontend_generated_monei_token(); if ( MONEI_GATEWAY_ID === $this->id && $monei_token ) { $payload['paymentToken'] = $monei_token; $payload['sessionId'] = (string) ( WC()->session !== null ? WC()->session->get_customer_id() : '' ); } return $payload; } /** * Check if gateway has fields. * @return bool */ public function has_fields() { // Always show fields for component mode or when tokenization is enabled return ! $this->redirect_flow || $this->tokenization; } /** * Payments fields, shown on checkout or payment method page (add payment method). */ public function payment_fields() { ob_start(); if ( is_add_payment_method_page() ) { esc_html_e( 'Pay via MONEI: you can add your payment method for future payments.', 'monei' ); // Always use component form in Add Payment method page. $this->render_monei_form(); } elseif ( is_checkout_pay_page() ) { // Order-pay page: Don't show saved cards (matches Stripe behavior) // Always require new payment method for failed payment retries // Show description in redirect mode if ( $this->redirect_flow && $this->description ) { echo '
'; echo wp_kses_post( wpautop( wptexturize( $this->description ) ) ); echo '
'; } if ( ! $this->redirect_flow ) { $this->render_monei_form(); } if ( $this->tokenization ) { $this->save_payment_method_checkbox(); } } elseif ( $this->handler !== null && $this->handler->is_subscription_change_payment_page() ) { // On subscription change payment page, we always use component CC. // Description not shown in component mode (non-redirect) if ( $this->tokenization ) { $this->saved_payment_methods(); } $this->render_monei_form(); if ( $this->tokenization ) { $this->tokenization_script(); } } else { // Checkout screen. // Show description only in redirect mode if ( $this->redirect_flow && $this->description ) { echo '
'; echo wp_kses_post( wpautop( wptexturize( $this->description ) ) ); echo '
'; } if ( $this->tokenization ) { $this->saved_payment_methods(); // If Component CC if ( ! $this->redirect_flow ) { $this->render_monei_form(); } else { $this->tokenization_script(); } $this->save_payment_method_checkbox(); } elseif ( ! $this->redirect_flow ) { // If Component CC $this->render_monei_form(); } } ob_end_flush(); } /** * Form where MONEI JS will render CC Component. */ protected function render_monei_form() { ?>
get_option( 'card_field_layout', 'single' ) ) : ?>
should_load_scripts() ) { return; } // Return early if redirect flow (doesn't need component scripts) if ( $this->redirect_flow ) { return; } // Return early if not on a page that needs scripts $is_required_page = is_checkout() || is_checkout_pay_page() || is_add_payment_method_page(); if ( ! $is_required_page ) { return; } if ( 'no' === $this->enabled ) { return; } // Don't load classic CSS on blocks checkout if ( $this->is_block_checkout_page() ) { return; } // Register and enqueue classic checkout CSS wp_register_style( 'monei-classic-checkout', plugins_url( 'public/css/monei-classic-checkout.css', MONEI_MAIN_FILE ), array(), MONEI_VERSION, 'all' ); wp_enqueue_style( 'monei-classic-checkout' ); if ( ! wp_script_is( 'monei', 'registered' ) ) { wp_register_script( 'monei', 'https://js.monei.com/v3/monei.js', '', '3.0', true ); } wp_register_script( 'woocommerce_monei', plugins_url( 'public/js/monei-cc-classic.min.js', MONEI_MAIN_FILE ), array( 'jquery', 'monei', ), MONEI_VERSION, true ); wp_enqueue_script( 'monei' ); // Determine the total amount to be passed $total = $this->determineTheTotalAmountToBePassed(); $card_input_style = $this->get_option( 'card_input_style', self::DEFAULT_CARD_INPUT_STYLE ); wp_localize_script( 'woocommerce_monei', 'wc_monei_params', array( 'accountId' => $this->getAccountId(), 'sessionId' => WC()->session !== null ? WC()->session->get_customer_id() : '', 'total' => monei_price_format( $total ), 'currency' => get_woocommerce_currency(), 'appleLogo' => WC_Monei()->image_url( 'apple-logo.svg' ), 'cardInputStyle' => json_decode( $card_input_style ), 'cardFieldLayout' => $this->get_option( 'card_field_layout', 'single' ), 'cardBrands' => $this->cardBrandHelper->getCardBrandsConfig(), 'nameErrorString' => esc_html__( 'Please enter a valid name. Special characters are not allowed.', 'monei' ), ) ); wp_enqueue_script( 'woocommerce_monei' ); $this->tokenization_script(); self::$scripts_enqueued = true; } protected function should_load_scripts() { return is_checkout() || is_checkout_pay_page() || is_add_payment_method_page(); } }