payment_gateways()->payment_gateways(); $gateways = []; foreach ($wc_gateways as $gateway) { // Only support gateways that extend WC_Payment_Gateway (respect the bone) if (!$gateway instanceof WC_Payment_Gateway) { continue; } // Force gateway to reload settings from database $gateway->init_settings(); $gateways[] = self::transform_gateway($gateway); } return $gateways; } /** * Get single gateway by ID * * @param string $gateway_id Gateway ID * @return array|null Gateway data or null if not found */ public static function get_gateway(string $gateway_id): ?array { if (!function_exists('WC')) { return null; } $wc_gateways = WC()->payment_gateways()->payment_gateways(); if (!isset($wc_gateways[$gateway_id])) { return null; } $gateway = $wc_gateways[$gateway_id]; if (!$gateway instanceof WC_Payment_Gateway) { return null; } // Force gateway to reload settings from database $gateway->init_settings(); return self::transform_gateway($gateway); } /** * Transform WooCommerce gateway to clean format * * @param WC_Payment_Gateway $gateway WooCommerce gateway instance * @return array Clean gateway data */ private static function transform_gateway(WC_Payment_Gateway $gateway): array { $type = self::categorize_gateway($gateway->id); $requirements = self::check_requirements($gateway); $settings = self::get_gateway_settings($gateway); return [ 'id' => $gateway->id, 'title' => $gateway->get_title(), 'description' => $gateway->get_description(), 'enabled' => $gateway->enabled === 'yes', 'type' => $type, 'icon' => self::get_gateway_icon($gateway->id), 'method_title' => $gateway->get_method_title(), 'method_description' => $gateway->get_method_description(), 'supports' => $gateway->supports, 'requirements' => $requirements, 'settings' => $settings, 'has_fields' => $gateway->has_fields(), 'countries' => $gateway->countries ?? null, 'availability' => $gateway->availability ?? 'all', 'order_button_text' => $gateway->order_button_text ?? null, 'webhook_url' => self::get_webhook_url($gateway->id), 'has_custom_ui' => self::has_custom_ui($gateway->id), 'wc_settings_url' => admin_url('admin.php?page=wc-settings&tab=checkout§ion=' . $gateway->id), ]; } /** * Categorize gateway into type * * @param string $gateway_id Gateway ID * @return string Type: manual, provider, or other */ private static function categorize_gateway(string $gateway_id): string { // Manual payment methods $manual = ['bacs', 'cheque', 'cod']; if (in_array($gateway_id, $manual, true)) { return 'manual'; } // Recognized payment providers $providers = ['stripe', 'paypal', 'stripe_cc', 'ppec_paypal', 'square', 'authorize_net']; if (in_array($gateway_id, $providers, true)) { return 'provider'; } // Other WC-compliant gateways return 'other'; } /** * Get gateway icon name for UI * * @param string $gateway_id Gateway ID * @return string Icon name (Lucide icon) */ private static function get_gateway_icon(string $gateway_id): string { $icons = [ 'bacs' => 'banknote', 'cheque' => 'banknote', 'cod' => 'banknote', 'stripe' => 'credit-card', 'stripe_cc' => 'credit-card', 'paypal' => 'credit-card', 'ppec_paypal' => 'credit-card', 'square' => 'credit-card', 'authorize_net' => 'credit-card', ]; return $icons[$gateway_id] ?? 'credit-card'; } /** * Check gateway requirements * * @param WC_Payment_Gateway $gateway Gateway instance * @return array Requirements status */ private static function check_requirements(WC_Payment_Gateway $gateway): array { $requirements = [ 'met' => true, 'missing' => [], ]; // Check if gateway has custom requirements method if (method_exists($gateway, 'get_requirements')) { $reqs = $gateway->get_requirements(); if (is_array($reqs)) { foreach ($reqs as $req => $met) { if (!$met) { $requirements['met'] = false; $requirements['missing'][] = $req; } } } } // Common requirements checks // Check SSL for gateways that need it if (in_array('tokenization', $gateway->supports ?? [], true)) { if (!is_ssl() && get_option('woocommerce_force_ssl_checkout') !== 'yes') { $requirements['met'] = false; $requirements['missing'][] = 'SSL certificate required'; } } return $requirements; } /** * Get gateway settings fields * * @param WC_Payment_Gateway $gateway Gateway instance * @return array Categorized settings fields */ private static function get_gateway_settings(WC_Payment_Gateway $gateway): array { $form_fields = $gateway->get_form_fields(); $current_settings = $gateway->settings; // Get current saved values return [ 'basic' => self::extract_basic_fields($form_fields, $current_settings), 'api' => self::extract_api_fields($form_fields, $current_settings), 'advanced' => self::extract_advanced_fields($form_fields, $current_settings), ]; } /** * Extract basic settings fields * * @param array $form_fields All form fields * @return array Basic fields */ private static function extract_basic_fields(array $form_fields, array $current_settings): array { $basic_keys = ['enabled', 'title', 'description', 'instructions']; return self::filter_fields($form_fields, $basic_keys, $current_settings); } /** * Extract API-related fields * * @param array $form_fields All form fields * @return array API fields */ private static function extract_api_fields(array $form_fields, array $current_settings): array { $api_patterns = ['key', 'secret', 'token', 'api', 'client', 'merchant', 'account']; $api_fields = []; foreach ($form_fields as $key => $field) { // Skip account_details - it's a special BACS field, not an API field if ($key === 'account_details') { continue; } foreach ($api_patterns as $pattern) { if (stripos($key, $pattern) !== false) { $api_fields[$key] = self::normalize_field($key, $field, $current_settings); break; } } } return $api_fields; } /** * Extract advanced settings fields * * @param array $form_fields All form fields * @return array Advanced fields */ private static function extract_advanced_fields(array $form_fields, array $current_settings): array { $basic_keys = ['enabled', 'title', 'description', 'instructions']; $advanced_fields = []; foreach ($form_fields as $key => $field) { // Skip basic fields if (in_array($key, $basic_keys, true)) { continue; } // Skip API fields (already extracted) $api_patterns = ['key', 'secret', 'token', 'api', 'client', 'merchant', 'account']; $is_api = false; foreach ($api_patterns as $pattern) { if (stripos($key, $pattern) !== false) { $is_api = true; break; } } if (!$is_api) { $advanced_fields[$key] = self::normalize_field($key, $field, $current_settings); } } return $advanced_fields; } /** * Filter fields by keys * * @param array $form_fields All fields * @param array $keys Keys to extract * @return array Filtered fields */ private static function filter_fields(array $form_fields, array $keys, array $current_settings): array { $filtered = []; foreach ($keys as $key) { if (isset($form_fields[$key])) { $filtered[$key] = self::normalize_field($key, $form_fields[$key], $current_settings); } } return $filtered; } /** * Normalize field to clean format * * @param string $key Field key * @param array $field Field data * @return array Normalized field */ private static function normalize_field(string $key, array $field, array $current_settings): array { // Special handling for BACS account_details if ($key === 'account_details') { $accounts = get_option('woocommerce_bacs_accounts', []); $current_value = $accounts; } else { // Use current value if available, otherwise use default $current_value = $current_settings[$key] ?? $field['default'] ?? ''; } return [ 'id' => $key, 'type' => $field['type'] ?? 'text', 'title' => $field['title'] ?? 'Account Details', 'description' => $field['description'] ?? 'Bank account details that will be displayed on the thank you page and in emails.', 'default' => $field['default'] ?? '', 'value' => $current_value, // Add current value! 'placeholder' => $field['placeholder'] ?? '', 'required' => !empty($field['required']), 'options' => $field['options'] ?? null, 'custom_attributes' => $field['custom_attributes'] ?? [], 'class' => $field['class'] ?? '', ]; } /** * Get webhook URL for gateway * * @param string $gateway_id Gateway ID * @return string|null Webhook URL or null */ private static function get_webhook_url(string $gateway_id): ?string { // Common webhook URL pattern for WooCommerce return home_url('/wc-api/' . $gateway_id); } /** * Check if gateway has custom UI component * * @param string $gateway_id Gateway ID * @return bool True if has custom UI */ private static function has_custom_ui(string $gateway_id): bool { // For now, only Stripe and PayPal will have custom UI (Phase 2) $custom_ui_gateways = ['stripe', 'paypal', 'stripe_cc', 'ppec_paypal']; return in_array($gateway_id, $custom_ui_gateways, true); } /** * Save gateway settings * * @param string $gateway_id Gateway ID * @param array $settings Settings to save * @return bool|WP_Error True on success, WP_Error on failure */ public static function save_gateway_settings(string $gateway_id, array $settings) { if (!function_exists('WC')) { return new \WP_Error('wc_not_available', 'WooCommerce is not available'); } $wc_gateways = WC()->payment_gateways()->payment_gateways(); if (!isset($wc_gateways[$gateway_id])) { return new \WP_Error('gateway_not_found', 'Gateway not found'); } $gateway = $wc_gateways[$gateway_id]; if (!$gateway instanceof WC_Payment_Gateway) { return new \WP_Error('invalid_gateway', 'Gateway does not extend WC_Payment_Gateway'); } // Block external HTTP requests (analytics, tracking, etc.) add_filter('pre_http_request', '__return_true', 999); // Get current settings and merge with new ones $gateway->init_settings(); $current_settings = $gateway->settings; // Special handling for BACS account_details if ($gateway_id === 'bacs' && isset($settings['account_details'])) { $accounts = $settings['account_details']; // Save to separate option like WooCommerce does update_option('woocommerce_bacs_accounts', $accounts); // Remove from settings array as it's not stored there unset($settings['account_details']); } $new_settings = array_merge($current_settings, $settings); // Debug logging error_log(sprintf('[WooNooW] Saving gateway %s settings: %s', $gateway_id, json_encode($settings))); error_log(sprintf('[WooNooW] Current enabled: %s, New enabled: %s', isset($current_settings['enabled']) ? $current_settings['enabled'] : 'not set', isset($new_settings['enabled']) ? $new_settings['enabled'] : 'not set' )); // Update gateway settings directly $gateway->settings = $new_settings; // Save to database using WooCommerce's method $saved = update_option($gateway->get_option_key(), $gateway->settings, 'yes'); error_log(sprintf('[WooNooW] update_option returned: %s', $saved ? 'true' : 'false')); // Update the enabled property specifically (WooCommerce does this) if (isset($new_settings['enabled'])) { $gateway->enabled = $new_settings['enabled']; error_log(sprintf('[WooNooW] Set gateway->enabled to: %s', $gateway->enabled)); } // Re-enable HTTP requests remove_filter('pre_http_request', '__return_true', 999); // Clear all WooCommerce caches wp_cache_delete('woocommerce_payment_gateways', 'options'); wp_cache_flush(); // Force WooCommerce to reload payment gateways if (function_exists('WC') && WC()->payment_gateways()) { WC()->payment_gateways()->init(); } return true; } /** * Toggle gateway enabled status * * @param string $gateway_id Gateway ID * @param bool $enabled Enable or disable * @return bool|WP_Error True on success, WP_Error on failure */ public static function toggle_gateway(string $gateway_id, bool $enabled) { return self::save_gateway_settings($gateway_id, [ 'enabled' => $enabled ? 'yes' : 'no', ]); } }