'sanitize_text_field', ) ); register_setting( 'wbc_connection', 'wbc_client_id', array( 'sanitize_callback' => 'sanitize_text_field', ) ); register_setting( 'wbc_connection', 'wbc_client_secret', array( 'sanitize_callback' => array( $this, 'sanitize_client_secret' ), ) ); register_setting( 'wbc_connection', 'wbc_environment', array( 'sanitize_callback' => 'sanitize_text_field', ) ); register_setting( 'wbc_connection', 'wbc_company_id', array( 'sanitize_callback' => 'sanitize_text_field', ) ); register_setting( 'wbc_connection', 'wbc_company_name', array( 'sanitize_callback' => 'sanitize_text_field', ) ); // Sync settings (own group) register_setting( 'wbc_sync', 'wbc_sync_frequency', array( 'sanitize_callback' => array( $this, 'sanitize_frequency' ), ) ); register_setting( 'wbc_sync', 'wbc_enable_stock_sync', array( 'sanitize_callback' => array( $this, 'sanitize_checkbox' ), ) ); register_setting( 'wbc_sync', 'wbc_enable_price_sync', array( 'sanitize_callback' => array( $this, 'sanitize_checkbox' ), ) ); register_setting( 'wbc_sync', 'wbc_location_code', array( 'sanitize_callback' => 'sanitize_text_field', ) ); register_setting( 'wbc_sync', 'wbc_regular_price_list', array( 'sanitize_callback' => 'sanitize_text_field', ) ); register_setting( 'wbc_sync', 'wbc_sale_price_list', array( 'sanitize_callback' => 'sanitize_text_field', ) ); // Order settings (own group) register_setting( 'wbc_orders', 'wbc_enable_order_sync', array( 'sanitize_callback' => array( $this, 'sanitize_checkbox' ), ) ); register_setting( 'wbc_orders', 'wbc_default_payment_terms_id', array( 'sanitize_callback' => 'sanitize_text_field', ) ); register_setting( 'wbc_orders', 'wbc_default_shipment_method_id', array( 'sanitize_callback' => 'sanitize_text_field', ) ); register_setting( 'wbc_orders', 'wbc_shipping_item_number', array( 'sanitize_callback' => 'sanitize_text_field', ) ); register_setting( 'wbc_orders', 'wbc_default_customer_number', array( 'sanitize_callback' => 'sanitize_text_field', ) ); register_setting( 'wbc_orders', 'wbc_auto_release_order', array( 'sanitize_callback' => array( $this, 'sanitize_checkbox' ), ) ); } /** * Sanitize client secret * * Do NOT use sanitize_text_field() here - it strips characters like %XX * sequences, angle brackets, etc. that are common in Azure AD client secrets. * * @param string $value Input value. * @return string Sanitized value. */ public function sanitize_client_secret( $value ) { if ( empty( $value ) ) { // Keep existing value if empty (masked field) return get_option( 'wbc_client_secret', '' ); } // If it looks like a masked value, keep existing if ( strpos( $value, '***' ) !== false ) { return get_option( 'wbc_client_secret', '' ); } // Only trim whitespace, then encrypt - preserve all secret characters $value = trim( wp_unslash( $value ) ); // Clear cached OAuth token since secret changed WBC_OAuth::clear_token_cache(); return WBC_OAuth::encrypt( $value ); } /** * Sanitize frequency * * @param string $value Input value. * @return string Sanitized value. */ public function sanitize_frequency( $value ) { $allowed = array( 'hourly', 'twice_daily', 'daily' ); $value = sanitize_text_field( $value ); if ( ! in_array( $value, $allowed, true ) ) { return 'daily'; } // Reschedule cron if frequency changed $old_frequency = get_option( 'wbc_sync_frequency', 'daily' ); if ( $value !== $old_frequency ) { WBC_Cron::reschedule_sync( $value ); } return $value; } /** * Sanitize checkbox * * @param string $value Input value. * @return string Sanitized value. */ public function sanitize_checkbox( $value ) { return $value === 'yes' ? 'yes' : 'no'; } /** * Enqueue admin scripts * * @param string $hook Current admin page hook. */ public function enqueue_scripts( $hook ) { if ( strpos( $hook, self::PAGE_SLUG ) === false ) { return; } wp_enqueue_style( 'wbc-admin-style', WBC_PLUGIN_URL . 'admin/css/wbc-admin.css', array(), WBC_VERSION ); wp_enqueue_script( 'wbc-admin-script', WBC_PLUGIN_URL . 'admin/js/wbc-admin.js', array( 'jquery' ), WBC_VERSION, true ); wp_localize_script( 'wbc-admin-script', 'wbc_admin', array( 'ajax_url' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'wbc_admin_nonce' ), 'strings' => array( 'testing' => __( 'Testing connection...', 'woo-business-central' ), 'syncing' => __( 'Syncing products...', 'woo-business-central' ), 'clearing' => __( 'Clearing logs...', 'woo-business-central' ), 'loading' => __( 'Loading...', 'woo-business-central' ), 'confirm_clear' => __( 'Are you sure you want to clear all logs?', 'woo-business-central' ), ), ) ); } /** * Add settings link to plugin list * * @param array $links Existing links. * @return array Modified links. */ public function add_settings_link( $links ) { $settings_link = sprintf( '%s', admin_url( 'admin.php?page=' . self::PAGE_SLUG ), __( 'Settings', 'woo-business-central' ) ); array_unshift( $links, $settings_link ); return $links; } /** * Render settings page */ public function render_settings_page() { // Check user capabilities if ( ! current_user_can( 'manage_woocommerce' ) ) { wp_die( __( 'You do not have sufficient permissions to access this page.', 'woo-business-central' ) ); } // Handle tab $current_tab = isset( $_GET['tab'] ) ? sanitize_text_field( wp_unslash( $_GET['tab'] ) ) : 'connection'; include WBC_PLUGIN_DIR . 'admin/partials/wbc-admin-display.php'; } /** * AJAX: Test connection */ public function ajax_test_connection() { check_ajax_referer( 'wbc_admin_nonce', 'nonce' ); if ( ! current_user_can( 'manage_woocommerce' ) ) { wp_send_json_error( array( 'message' => __( 'Permission denied.', 'woo-business-central' ) ) ); } $result = WBC_OAuth::test_connection(); if ( is_wp_error( $result ) ) { wp_send_json_error( array( 'message' => $result->get_error_message() ) ); } wp_send_json_success( $result ); } /** * AJAX: Manual sync */ public function ajax_manual_sync() { check_ajax_referer( 'wbc_admin_nonce', 'nonce' ); if ( ! current_user_can( 'manage_woocommerce' ) ) { wp_send_json_error( array( 'message' => __( 'Permission denied.', 'woo-business-central' ) ) ); } $result = WBC_Cron::run_sync_now(); if ( isset( $result['success'] ) && $result['success'] ) { wp_send_json_success( $result ); } else { wp_send_json_error( $result ); } } /** * AJAX: Clear logs */ public function ajax_clear_logs() { check_ajax_referer( 'wbc_admin_nonce', 'nonce' ); if ( ! current_user_can( 'manage_woocommerce' ) ) { wp_send_json_error( array( 'message' => __( 'Permission denied.', 'woo-business-central' ) ) ); } WBC_Logger::clear_logs(); wp_send_json_success( array( 'message' => __( 'Logs cleared successfully.', 'woo-business-central' ) ) ); } /** * AJAX: Get companies */ public function ajax_get_companies() { check_ajax_referer( 'wbc_admin_nonce', 'nonce' ); if ( ! current_user_can( 'manage_woocommerce' ) ) { wp_send_json_error( array( 'message' => __( 'Permission denied.', 'woo-business-central' ) ) ); } $result = WBC_API_Client::get_companies(); if ( is_wp_error( $result ) ) { wp_send_json_error( array( 'message' => $result->get_error_message() ) ); } $companies = isset( $result['value'] ) ? $result['value'] : array(); wp_send_json_success( array( 'companies' => $companies ) ); } /** * Handle CSV export of logs */ public function handle_csv_export() { if ( ! isset( $_GET['wbc_export_logs'] ) || $_GET['wbc_export_logs'] !== '1' ) { return; } if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'wbc_export_logs' ) ) { wp_die( esc_html__( 'Security check failed.', 'woo-business-central' ) ); } if ( ! current_user_can( 'manage_woocommerce' ) ) { wp_die( esc_html__( 'Permission denied.', 'woo-business-central' ) ); } $csv = WBC_Logger::export_to_csv(); header( 'Content-Type: text/csv; charset=utf-8' ); header( 'Content-Disposition: attachment; filename=wbc-logs-' . gmdate( 'Y-m-d' ) . '.csv' ); header( 'Pragma: no-cache' ); header( 'Expires: 0' ); echo $csv; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- CSV output exit; } /** * Get logs for display * * @param array $args Query arguments. * @return array Logs data. */ public static function get_logs_for_display( $args = array() ) { $defaults = array( 'limit' => 50, 'offset' => 0, 'level' => '', ); $args = wp_parse_args( $args, $defaults ); return array( 'logs' => WBC_Logger::get_logs( $args ), 'total' => WBC_Logger::get_log_count( $args ), ); } }