ifnex/03_WordPress/wp-content/plugins/ifnex-bridge/includes/user-bridge.php
Kazem Alghasi c0a50acaef style(ui): modernize transaction list styling and update plugin version
Update the transaction interface with a modern design including improved
typography, card-based layouts, and color-coded status badges.

- Add comprehensive CSS for transaction items, types, and statuses
- Implement responsive styles for mobile transaction views
- Update transaction shortcode to include pagination limit
- Increment plugin asset version to 1.5.0
2026-08-24 04:04:29 +03:30

581 lines
21 KiB
PHP

<?php
/**
* IFNEX User Bridge
* مدیریت ارتباط کاربران وردپرس با لاراول
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class IFNEX_User_Bridge {
private $api_url;
private $api_key;
public function __construct() {
$this->api_url = rtrim(get_option('ifnex_api_url', 'http://localhost:8000/api/v1'), '/');
$this->api_key = get_option('ifnex_api_key', '');
}
/**
* دریافت توکن Sanctum از لاراول برای کاربر وردپرس
*/
public function get_user_token($user_id) {
$token = get_user_meta($user_id, 'ifnex_laravel_token', true);
$token_expiry = get_user_meta($user_id, 'ifnex_laravel_token_expiry', true);
// اگر توکن معتبر وجود دارد، از آن استفاده کن
if ($token && $token_expiry && strtotime($token_expiry) > time()) {
return $token;
}
// دریافت اطلاعات کاربر وردپرس
$wp_user = get_userdata($user_id);
if (!$wp_user) {
return false;
}
// درخواست توکن از Bridge endpoint (جدید)
$token = $this->request_bridge_token(
$user_id,
$wp_user->user_email,
$wp_user->display_name
);
if ($token) {
update_user_meta($user_id, 'ifnex_laravel_token', $token);
update_user_meta($user_id, 'ifnex_laravel_token_expiry', date('Y-m-d H:i:s', strtotime('+30 days')));
}
return $token;
}
/**
* درخواست توکن از Bridge endpoint جدید
* این روش نیازی به رمز عبور ندارد و از API Key مشترک استفاده می‌کند
*/
private function request_bridge_token($wp_user_id, $email, $name) {
$url = $this->api_url . '/bridge/login';
$bridge_key = get_option('ifnex_bridge_api_key', '');
if (empty($bridge_key)) {
error_log('IFNEX: Bridge API Key is not configured in WordPress settings');
return false;
}
$args = array(
'headers' => array(
'Content-Type' => 'application/json',
'Accept' => 'application/json',
),
'body' => json_encode(array(
'bridge_api_key' => $bridge_key,
'wp_user_id' => $wp_user_id,
'wp_user_email' => $email,
'wp_user_name' => $name,
'token_name' => 'wordpress-bridge-' . get_current_blog_id(),
)),
'timeout' => 30,
);
$response = wp_remote_post($url, $args);
if (is_wp_error($response)) {
error_log('IFNEX Bridge Error: ' . $response->get_error_message());
return false;
}
$body = wp_remote_retrieve_body($response);
$data = json_decode($body, true);
if (isset($data['token'])) {
return $data['token'];
}
error_log('IFNEX Bridge Token Error: ' . ($data['message'] ?? 'Unknown error'));
return false;
}
/**
* ارسال درخواست احراز هویت‌شده به API لاراول
*/
public function authenticated_request($user_id, $endpoint, $method = 'GET', $data = array()) {
$token = $this->get_user_token($user_id);
if (!$token) {
return new WP_Error('no_token', 'توکن احراز هویت یافت نشد.');
}
$url = $this->api_url . $endpoint;
$method = strtoupper($method);
$args = array(
'headers' => array(
'Authorization' => 'Bearer ' . $token,
'Accept' => 'application/json',
'Content-Type' => 'application/json',
),
'timeout' => 30,
'method' => $method, // ✅ همیشه متد درخواستی استفاده شود
);
// ✅ اصلاح: بر اساس متد، data را اضافه کن
if (in_array($method, ['POST', 'PUT', 'PATCH'])) {
// حتی اگر data خالی باشد، body را خالی بفرست
$args['body'] = json_encode($data ?: new \stdClass());
} elseif ($method === 'GET' && !empty($data)) {
// برای GET، data را به URL اضافه کن
$url = add_query_arg($data, $url);
}
$response = wp_remote_request($url, $args);
if (is_wp_error($response)) {
return $response;
}
$body = wp_remote_retrieve_body($response);
$code = wp_remote_retrieve_response_code($response);
$data = json_decode($body, true);
// لاگ برای دیباگ
error_log("IFNEX API [{$method}] {$endpoint} => Status: {$code}");
if ($code === 401) {
$this->invalidate_token(get_current_user_id());
return new WP_Error('token_expired', 'توکن منقضی شده است. لطفاً دوباره وارد شوید.');
}
// اگر پاسخ JSON نیست
if (!is_array($data)) {
return new WP_Error('invalid_response', 'پاسخ نامعتبر از سرور: ' . substr($body, 0, 200));
}
return $data;
}
/**
* باطل کردن توکن
*/
public function invalidate_token($user_id) {
delete_user_meta($user_id, 'ifnex_laravel_token');
delete_user_meta($user_id, 'ifnex_laravel_token_expiry');
}
/**
* دریافت موجودی کیف پول کاربر
*/
public function get_wallet_balance($user_id) {
$result = $this->authenticated_request($user_id, '/wallet/balance');
if (is_wp_error($result)) {
return $result;
}
return array(
'balance' => $result['balance'] ?? 0,
'total_deposited' => $result['total_deposited'] ?? 0,
'total_withdrawn' => $result['total_withdrawn'] ?? 0,
'is_frozen' => $result['is_frozen'] ?? false,
);
}
/**
* دریافت تراکنش‌های کاربر
*/
public function get_transactions($user_id, $per_page = 15) {
$result = $this->authenticated_request($user_id, '/wallet/transactions', 'GET', array(
'per_page' => $per_page,
));
if (is_wp_error($result)) {
return $result;
}
return $result;
}
/**
* رهگیری مرسوله
*/
public function track_shipment($awb_no) {
if (empty($this->api_key)) {
return new WP_Error('no_api_key', 'API Key تنظیم نشده است.');
}
$url = $this->api_url . '/track/' . urlencode($awb_no);
$args = array(
'headers' => array(
'Authorization' => 'Bearer ' . $this->api_key,
'Accept' => 'application/json',
),
'timeout' => 30,
);
$response = wp_remote_get($url, $args);
if (is_wp_error($response)) {
return $response;
}
$body = wp_remote_retrieve_body($response);
$data = json_decode($body, true);
if ($response['response']['code'] === 404) {
return new WP_Error('not_found', 'مرسوله‌ای با این کد پیدا نشد.');
}
if ($response['response']['code'] !== 200) {
return new WP_Error('api_error', 'خطا در ارتباط با API: ' . ($data['message'] ?? 'Unknown error'));
}
return $data;
}
// ══════════════════════════════════════════════════════════════
// Customer Orders API (جدید)
// ══════════════════════════════════════════════════════════════
/**
* دریافت پروفایل و آمار کاربر
*/
public function get_customer_profile($user_id) {
$result = $this->authenticated_request($user_id, '/customer/profile');
if (is_wp_error($result)) {
return $result;
}
return $result;
}
/**
* دریافت لیست کشورها
*/
public function get_countries($user_id) {
$result = $this->authenticated_request($user_id, '/customer/countries');
if (is_wp_error($result)) {
return $result;
}
return $result['data'] ?? [];
}
/**
* دریافت لیست سفارشات کاربر
*/
public function get_customer_orders($user_id, $per_page = 15, $status = null) {
$params = ['per_page' => $per_page];
if ($status) {
$params['status'] = $status;
}
$result = $this->authenticated_request($user_id, '/customer/orders', 'GET', $params);
if (is_wp_error($result)) {
return $result;
}
return $result;
}
/**
* دریافت جزئیات یک سفارش
*/
public function get_customer_order($user_id, $shipment_id) {
$result = $this->authenticated_request($user_id, "/customer/orders/{$shipment_id}");
if (is_wp_error($result)) {
return $result;
}
return $result;
}
/**
* ثبت سفارش جدید
*/
public function create_customer_order($user_id, $order_data) {
$result = $this->authenticated_request($user_id, '/customer/orders', 'POST', $order_data);
if (is_wp_error($result)) {
return $result;
}
return $result;
}
/**
* لغو سفارش
*/
public function cancel_customer_order($user_id, $shipment_id) {
$result = $this->authenticated_request($user_id, "/customer/orders/{$shipment_id}/cancel", 'POST');
if (is_wp_error($result)) {
return $result;
}
return $result;
}
}
// ══════════════════════════════════════════════════════════════
// AJAX Handler برای لغو سفارش
// ══════════════════════════════════════════════════════════════
add_action('wp_ajax_ifnex_cancel_order', 'ifnex_cancel_order_ajax');
function ifnex_cancel_order_ajax() {
check_ajax_referer('ifnex_ajax_nonce', 'nonce');
if (!is_user_logged_in()) {
wp_send_json_error('باید وارد شوید.');
}
$order_id = intval($_POST['order_id'] ?? 0);
if (!$order_id) {
wp_send_json_error('شناسه سفارش نامعتبر است.');
}
$bridge = new IFNEX_User_Bridge();
$result = $bridge->cancel_customer_order(get_current_user_id(), $order_id);
if (is_wp_error($result)) {
wp_send_json_error($result->get_error_message());
}
wp_send_json_success('سفارش لغو شد.');
}
// Enqueue AJAX script
add_action('wp_enqueue_scripts', 'ifnex_enqueue_ajax_script');
function ifnex_enqueue_ajax_script() {
global $post;
if (is_a($post, 'WP_Post') && has_shortcode($post->post_content, 'ifnex_orders_list')) {
wp_enqueue_script('jquery');
wp_localize_script('jquery', 'ifnex_ajax', array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('ifnex_ajax_nonce'),
));
}
}
// ══════════════════════════════════════════════════════════════
// AJAX Handlers برای فرم سفارش
// ══════════════════════════════════════════════════════════════
add_action('wp_ajax_ifnex_get_countries', 'ifnex_get_countries_ajax');
function ifnex_get_countries_ajax() {
check_ajax_referer('ifnex_ajax_nonce', 'nonce');
if (!is_user_logged_in()) wp_send_json_error('باید وارد شوید.');
$bridge = new IFNEX_User_Bridge();
$result = $bridge->get_countries(get_current_user_id());
if (is_wp_error($result)) wp_send_json_error($result->get_error_message());
wp_send_json_success($result);
}
add_action('wp_ajax_ifnex_calculate_price', 'ifnex_calculate_price_ajax');
function ifnex_calculate_price_ajax() {
check_ajax_referer('ifnex_ajax_nonce', 'nonce');
if (!is_user_logged_in()) wp_send_json_error('باید وارد شوید.');
$data = $_POST['data'] ?? [];
if (empty($data)) wp_send_json_error('داده‌ای ارسال نشده.');
// تبدیل direction برای PriceCalculator
$payload = array(
'direction' => ($data['direction'] === 'export') ? 'Outbound' : 'Inbound',
'type' => $data['type'],
'country_iso' => $data['country_iso'],
'weight' => floatval($data['weight']),
'volumetric_weight' => floatval($data['volumetric_weight'] ?? 0),
);
if (!empty($data['discount_code'])) $payload['discount_code'] = $data['discount_code'];
$api_url = rtrim(get_option('ifnex_api_url', 'http://localhost:8000/api/v1'), '/');
$response = wp_remote_post($api_url . '/calculate', array(
'headers' => array('Content-Type' => 'application/json', 'Accept' => 'application/json'),
'body' => json_encode($payload),
'timeout' => 30,
));
if (is_wp_error($response)) wp_send_json_error($response->get_error_message());
$body = json_decode(wp_remote_retrieve_body($response), true);
if ($response['response']['code'] !== 200) {
wp_send_json_error($body['message'] ?? 'خطا در محاسبه قیمت');
}
wp_send_json_success($body);
}
add_action('wp_ajax_ifnex_submit_order', 'ifnex_submit_order_ajax');
function ifnex_submit_order_ajax() {
check_ajax_referer('ifnex_ajax_nonce', 'nonce');
if (!is_user_logged_in()) wp_send_json_error('باید وارد شوید.');
$data = $_POST['data'] ?? [];
if (empty($data)) wp_send_json_error('داده‌ای ارسال نشده.');
$bridge = new IFNEX_User_Bridge();
$result = $bridge->create_customer_order(get_current_user_id(), $data);
if (is_wp_error($result)) wp_send_json_error($result->get_error_message());
if (isset($result['success']) && !$result['success']) {
wp_send_json_error($result['message'] ?? 'خطا در ثبت سفارش');
}
wp_send_json_success($result);
}
// Enqueue scripts & styles برای شورت‌کدهای جدید
add_action('wp_enqueue_scripts', 'ifnex_enqueue_order_assets');
function ifnex_enqueue_order_assets() {
global $post;
if (!is_a($post, 'WP_Post')) return;
$has_order_shortcodes =
has_shortcode($post->post_content, 'ifnex_orders_list') ||
has_shortcode($post->post_content, 'ifnex_order_form') ||
has_shortcode($post->post_content, 'ifnex_user_profile') ||
has_shortcode($post->post_content, 'ifnex_order_payment') ||
has_shortcode($post->post_content, 'ifnex_order_detail');
has_shortcode($post->post_content, 'ifnex_customer_dashboard');
if ($has_order_shortcodes) {
// ✅ اصلاح: dirname(__FILE__) یک سطح بالاتر می‌رود
$plugin_url = plugin_dir_url(dirname(__FILE__));
// Load CSS
wp_enqueue_style(
'ifnex-orders-css',
$plugin_url . 'assets/css/ifnex-orders.css',
array(),
'1.2.0' //版本号 changed برای شکستن cache
);
// Load jQuery & JS
wp_enqueue_script('jquery');
wp_enqueue_script(
'ifnex-order-form-js',
$plugin_url . 'assets/js/ifnex-order-form.js',
array('jquery'),
'1.2.0', //版本号 changed
true
);
// Pass data to JS
wp_localize_script('ifnex-order-form-js', 'ifnex_ajax', array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('ifnex_ajax_nonce'),
'orders_url' => home_url('/my-orders/'),
));
}
}
// ══════════════════════════════════════════════════════════════
// AJAX Handlers برای پرداخت سفارش
// ══════════════════════════════════════════════════════════════
add_action('wp_ajax_ifnex_pay_order_wallet', 'ifnex_pay_order_wallet_ajax');
function ifnex_pay_order_wallet_ajax() {
check_ajax_referer('ifnex_ajax_nonce', 'nonce');
if (!is_user_logged_in()) wp_send_json_error('باید وارد شوید.');
$order_id = intval($_POST['order_id'] ?? 0);
if (!$order_id) wp_send_json_error('شناسه سفارش نامعتبر است.');
$bridge = new IFNEX_User_Bridge();
$result = $bridge->authenticated_request(
get_current_user_id(),
"/customer/orders/{$order_id}/pay-wallet",
'POST'
);
if (is_wp_error($result)) wp_send_json_error($result->get_error_message());
if (isset($result['success']) && !$result['success']) {
wp_send_json_error($result['message'] ?? 'خطا در پرداخت');
}
wp_send_json_success($result);
}
add_action('wp_ajax_ifnex_pay_order_gateway', 'ifnex_pay_order_gateway_ajax');
function ifnex_pay_order_gateway_ajax() {
check_ajax_referer('ifnex_ajax_nonce', 'nonce');
if (!is_user_logged_in()) wp_send_json_error('باید وارد شوید.');
$order_id = intval($_POST['order_id'] ?? 0);
$callback_url = sanitize_url($_POST['callback_url'] ?? '');
if (!$order_id) wp_send_json_error('شناسه سفارش نامعتبر است.');
if (!$callback_url) wp_send_json_error('آدرس بازگشت نامعتبر است.');
$bridge = new IFNEX_User_Bridge();
$result = $bridge->authenticated_request(
get_current_user_id(),
"/customer/orders/{$order_id}/pay-gateway",
'POST',
['frontend_callback' => $callback_url]
);
if (is_wp_error($result)) wp_send_json_error($result->get_error_message());
if (isset($result['success']) && !$result['success']) {
wp_send_json_error($result['message'] ?? 'خطا در اتصال به درگاه');
}
wp_send_json_success($result);
}
// Enqueue برای صفحه پرداخت
add_action('wp_enqueue_scripts', 'ifnex_enqueue_payment_assets');
function ifnex_enqueue_payment_assets() {
global $post;
if (!is_a($post, 'WP_Post')) return;
if (has_shortcode($post->post_content, 'ifnex_order_payment')) {
$plugin_url = plugin_dir_url(dirname(__FILE__));
wp_enqueue_style('ifnex-orders-css', $plugin_url . 'assets/css/ifnex-orders.css', array(), '1.3.0');
wp_enqueue_script('jquery');
wp_localize_script('jquery', 'ifnex_ajax', array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('ifnex_ajax_nonce'),
'orders_url' => home_url('/my-orders/'),
));
}
}
// ══════════════════════════════════════════════════════════════
// لود سراسری CSS و متغیرهای AJAX برای همه صفحات IFNEX
// این تابع همیشه اجرا می‌شود تا هیچ شورت‌کدی بدون استایل نماند
// ══════════════════════════════════════════════════════════════
add_action('wp_enqueue_scripts', 'ifnex_enqueue_global_assets', 20);
function ifnex_enqueue_global_assets() {
$plugin_url = plugin_dir_url(dirname(__FILE__));
// لود CSS اصلی (نسخه را بالا بردیم تا cache مرورگر بشکند)
wp_enqueue_style(
'ifnex-orders-css',
$plugin_url . 'assets/css/ifnex-orders.css',
array(),
'1.5.0'
);
// لود jQuery
wp_enqueue_script('jquery');
// متغیرهای AJAX برای همه صفحات
wp_localize_script('jquery', 'ifnex_ajax', array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('ifnex_ajax_nonce'),
'orders_url' => home_url('/my-account/?tab=orders'),
'home_url' => home_url('/'),
));
}