Compare commits

...

2 Commits

Author SHA1 Message Date
Kazem Alghasi
a549ce8d8e chore(wp): allow ifnex-bridge plugin in gitignore
Exclude the ifnex-bridge plugin directory from being ignored by
adding an exception rule to the .gitignore file.
2026-08-04 11:38:48 +03:30
Kazem Alghasi
97e641de42 feat(wp): add ifnex-bridge plugin for Laravel API integration
Implement a new WordPress plugin to bridge the frontend with the Laravel
logistics API. This includes:

- API client for secure shipment tracking via Bearer token
- Admin settings page for configuring API URL and Key
- Shortcodes for embedding tracking forms and status displays
- AJAX-based tracking form with real-time results and timeline view
2026-08-04 11:38:36 +03:30
5 changed files with 403 additions and 0 deletions

3
.gitignore vendored
View File

@ -11,6 +11,9 @@ Thumbs.db
03_WordPress/wp-content/upgrade/*
03_WordPress/wp-content/db.php
# exception: custom plugin for this project
!03_WordPress/wp-content/plugins/ifnex-bridge/
# هسته لاراول (پکیج‌های دانلودی و تنظیمات)
04_Laravel/vendor/
04_Laravel/node_modules/

View File

@ -0,0 +1,52 @@
<?php
/**
* Plugin Name: IFNEX Logistics Bridge
* Description: اتصال فرانت‌اند سایت ایف‌نکس به API لاراول
* Version: 1.0
* Author: VernaSoft group (Kazem Alghasi)
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// لود کردن فایل‌های پلاگین
require_once plugin_dir_path( __FILE__ ) . 'includes/api-client.php';
require_once plugin_dir_path( __FILE__ ) . 'includes/shortcodes.php';
require_once plugin_dir_path( __FILE__ ) . 'includes/tracking-form.php';
// اضافه کردن لینک به منوی پیشخوان وردپرس
add_action( 'admin_menu', 'ifnex_plugin_setup_menu' );
function ifnex_plugin_setup_menu() {
add_menu_page( 'تنظیمات IFNEX', 'IFNEX', 'manage_options', 'ifnex-settings', 'ifnex_settings_page_html', 'dashicons-location-alt', 30 );
}
function ifnex_settings_page_html() {
if (isset($_POST['ifnex_api_url']) && check_admin_referer('ifnex_settings_save')) {
update_option('ifnex_api_url', sanitize_url($_POST['ifnex_api_url']));
update_option('ifnex_api_key', sanitize_text_field($_POST['ifnex_api_key']));
echo '<div class="notice notice-success"><p>تنظیمات ذخیره شد.</p></div>';
}
$api_url = get_option('ifnex_api_url', 'http://localhost:8000/api/v1');
$api_key = get_option('ifnex_api_key', '');
?>
<div class="wrap">
<h1>تنظیمات IFNEX Logistics Bridge</h1>
<form method="post">
<?php wp_nonce_field('ifnex_settings_save'); ?>
<table class="form-table">
<tr>
<th scope="row"><label for="ifnex_api_url">API URL</label></th>
<td><input type="text" id="ifnex_api_url" name="ifnex_api_url" value="<?php echo esc_attr($api_url); ?>" class="regular-text" placeholder="http://localhost:8000/api/v1"></td>
</tr>
<tr>
<th scope="row"><label for="ifnex_api_key">API Key</label></th>
<td><input type="text" id="ifnex_api_key" name="ifnex_api_key" value="<?php echo esc_attr($api_key); ?>" class="regular-text"></td>
</tr>
</table>
<?php submit_button('ذخیره تنظیمات'); ?>
</form>
</div>
<?php
}

View File

@ -0,0 +1,54 @@
<?php
/**
* IFNEX API Client
* اتصال به API لاراول برای استعلام ترکینگ
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class IFNEX_API_Client {
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', '');
}
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;
}
}

View File

@ -0,0 +1,88 @@
<?php
/**
* IFNEX Shortcodes
* شورت‌کدهای پلاگین IFNEX Bridge
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// شورت‌کد فرم ترکینگ
add_shortcode('ifnex_tracking_form', 'ifnex_tracking_form_shortcode');
function ifnex_tracking_form_shortcode($atts) {
$atts = shortcode_atts(array(
'title' => 'رهگیری مرسوله',
'placeholder' => 'شماره بارنامه را وارد کنید',
'button_text' => 'رهگیری',
), $atts);
ob_start();
?>
<div class="ifnex-tracking-container">
<h2><?php echo esc_html($atts['title']); ?></h2>
<form id="ifnex-tracking-form" class="ifnex-tracking-form">
<div class="ifnex-form-group">
<input type="text" id="ifnex-awb-input" placeholder="<?php echo esc_attr($atts['placeholder']); ?>" required>
<button type="submit" id="ifnex-track-btn"><?php echo esc_html($atts['button_text']); ?></button>
</div>
</form>
<div id="ifnex-tracking-result" class="ifnex-tracking-result" style="display: none;"></div>
</div>
<?php
return ob_get_clean();
}
// شورت‌کد نمایش وضعیت مستقیم
add_shortcode('ifnex_tracking_status', 'ifnex_tracking_status_shortcode');
function ifnex_tracking_status_shortcode($atts) {
$atts = shortcode_atts(array(
'awb' => '',
), $atts);
if (empty($atts['awb'])) {
return '<p>شماره بارنامه وارد نشده است.</p>';
}
$client = new IFNEX_API_Client();
$result = $client->track_shipment($atts['awb']);
if (is_wp_error($result)) {
return '<p class="ifnex-error">' . esc_html($result->get_error_message()) . '</p>';
}
ob_start();
?>
<div class="ifnex-tracking-status">
<h3>وضعیت مرسوله <?php echo esc_html($result['awb_no'] ?? ''); ?></h3>
<div class="ifnex-status-badge">
<?php echo esc_html($result['status'] ?? 'نامشخص'); ?>
</div>
<div class="ifnex-details">
<p><strong>نوع:</strong> <?php echo esc_html($result['type'] ?? ''); ?></p>
<p><strong>جهت:</strong> <?php echo esc_html($result['direction'] ?? ''); ?></p>
<p><strong>فرستنده:</strong> <?php echo esc_html($result['sender']['name'] ?? ''); ?></p>
<p><strong>گیرنده:</strong> <?php echo esc_html($result['receiver']['name'] ?? ''); ?></p>
</div>
<?php if (!empty($result['timeline']) && is_array($result['timeline'])): ?>
<div class="ifnex-timeline">
<h4>تاریخچه رهگیری</h4>
<ul>
<?php foreach ($result['timeline'] as $event): ?>
<li>
<strong><?php echo esc_html($event['event_date'] ?? ''); ?></strong>
<span><?php echo esc_html($event['event_description'] ?? ''); ?></span>
<?php if (!empty($event['location'])): ?>
<small><?php echo esc_html($event['location']); ?></small>
<?php endif; ?>
</li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
</div>
<?php
return ob_get_clean();
}

View File

@ -0,0 +1,206 @@
<?php
/**
* IFNEX Tracking Form Handler
* JavaScript و منطق فرم رهگیری
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
add_action('wp_footer', 'ifnex_tracking_form_scripts');
function ifnex_tracking_form_scripts() {
// فقط اگر شورت‌کد در صفحه وجود دارد، اسکریپت را لود کن
global $post;
if (is_a($post, 'WP_Post') && has_shortcode($post->post_content, 'ifnex_tracking_form')) {
?>
<script>
document.addEventListener('DOMContentLoaded', function() {
var form = document.getElementById('ifnex-tracking-form');
if (!form) return;
form.addEventListener('submit', function(e) {
e.preventDefault();
var input = document.getElementById('ifnex-awb-input');
var resultDiv = document.getElementById('ifnex-tracking-result');
var btn = document.getElementById('ifnex-track-btn');
var awb = input.value.trim();
if (!awb) {
resultDiv.innerHTML = '<p class="ifnex-error">لطفاً شماره بارنامه را وارد کنید.</p>';
resultDiv.style.display = 'block';
return;
}
btn.disabled = true;
btn.textContent = 'در حال جستجو...';
resultDiv.style.display = 'block';
resultDiv.innerHTML = '<p>در حال جستجو...</p>';
var xhr = new XMLHttpRequest();
xhr.open('POST', '<?php echo esc_url(admin_url('admin-ajax.php')); ?>', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onload = function() {
btn.disabled = false;
btn.textContent = '<?php echo esc_js(__('رهگیری', 'ifnex-bridge')); ?>';
if (xhr.status === 200) {
var data = JSON.parse(xhr.responseText);
if (data.success) {
resultDiv.innerHTML = data.html;
} else {
resultDiv.innerHTML = '<p class="ifnex-error">' + data.message + '</p>';
}
} else {
resultDiv.innerHTML = '<p class="ifnex-error">خطا در ارتباط با سرور.</p>';
}
};
xhr.onerror = function() {
btn.disabled = false;
btn.textContent = '<?php echo esc_js(__('رهگیری', 'ifnex-bridge')); ?>';
resultDiv.innerHTML = '<p class="ifnex-error">خطا در ارتباط با سرور.</p>';
};
xhr.send('action=ifnex_track_shipment&awb=' + encodeURIComponent(awb));
});
});
</script>
<style>
.ifnex-tracking-container {
max-width: 600px;
margin: 20px auto;
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
font-family: inherit;
}
.ifnex-tracking-form {
margin-bottom: 20px;
}
.ifnex-form-group {
display: flex;
gap: 10px;
}
.ifnex-form-group input {
flex: 1;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 16px;
}
.ifnex-form-group button {
padding: 10px 20px;
background: #0073aa;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
.ifnex-form-group button:hover {
background: #005a87;
}
.ifnex-form-group button:disabled {
background: #ccc;
cursor: not-allowed;
}
.ifnex-tracking-result {
margin-top: 20px;
padding: 15px;
background: #f9f9f9;
border-radius: 4px;
}
.ifnex-error {
color: #dc3232;
}
.ifnex-tracking-status h3 {
margin-top: 0;
}
.ifnex-status-badge {
display: inline-block;
padding: 5px 10px;
background: #0073aa;
color: white;
border-radius: 4px;
margin-bottom: 10px;
}
.ifnex-timeline {
margin-top: 20px;
}
.ifnex-timeline ul {
list-style: none;
padding: 0;
}
.ifnex-timeline li {
padding: 10px;
border-bottom: 1px solid #eee;
}
.ifnex-timeline li:last-child {
border-bottom: none;
}
</style>
<?php
}
}
// AJAX Handler
add_action('wp_ajax_ifnex_track_shipment', 'ifnex_track_shipment_ajax');
add_action('wp_ajax_nopriv_ifnex_track_shipment', 'ifnex_track_shipment_ajax');
function ifnex_track_shipment_ajax() {
$awb = isset($_POST['awb']) ? sanitize_text_field($_POST['awb']) : '';
if (empty($awb)) {
wp_send_json(array('success' => false, 'message' => 'شماره بارنامه وارد نشده است.'));
return;
}
$client = new IFNEX_API_Client();
$result = $client->track_shipment($awb);
if (is_wp_error($result)) {
wp_send_json(array('success' => false, 'message' => $result->get_error_message()));
return;
}
// ساخت HTML نتیجه
ob_start();
?>
<div class="ifnex-tracking-status">
<h3>وضعیت مرسوله <?php echo esc_html($result['awb_no'] ?? ''); ?></h3>
<div class="ifnex-status-badge">
<?php echo esc_html($result['status'] ?? 'نامشخص'); ?>
</div>
<div class="ifnex-details">
<p><strong>نوع:</strong> <?php echo esc_html($result['type'] ?? ''); ?></p>
<p><strong>جهت:</strong> <?php echo esc_html($result['direction'] ?? ''); ?></p>
<?php if (!empty($result['sender']['name'])): ?>
<p><strong>فرستنده:</strong> <?php echo esc_html($result['sender']['name']); ?></p>
<?php endif; ?>
<?php if (!empty($result['receiver']['name'])): ?>
<p><strong>گیرنده:</strong> <?php echo esc_html($result['receiver']['name']); ?></p>
<?php endif; ?>
</div>
<?php if (!empty($result['timeline']) && is_array($result['timeline'])): ?>
<div class="ifnex-timeline">
<h4>تاریخچه رهگیری</h4>
<ul>
<?php foreach (array_reverse($result['timeline']) as $event): ?>
<li>
<strong><?php echo esc_html($event['event_date'] ?? ''); ?></strong>
<span><?php echo esc_html($event['event_description'] ?? ''); ?></span>
<?php if (!empty($event['location'])): ?>
<small><?php echo esc_html($event['location']); ?></small>
<?php endif; ?>
</li>
<?php endforeach; ?>
</ul>
</div>
<?php endif; ?>
</div>
<?php
$html = ob_get_clean();
wp_send_json(array('success' => true, 'html' => $html));
}