Implement critical security hardening and resolve a P0 bug in the discount code consumption flow. This update transitions the system from a development-heavy configuration to a production-ready state. Key changes: - Fix P0 bug where `consumeDiscountCode()` was missing, breaking order registration; replaced with a robust `DiscountCodeService` using `discount_code_usages` for audit trails and idempotency. - Implement strict production guards for the Zarinpal payment gateway to prevent accidental mock processing in live environments. - Refactor WordPress bridge asset management to use `filemtime` based versioning instead of `time()` to prevent unnecessary cache busting. - Remove debug-only hacks (`opcache_reset`, `header` cache control) from the WordPress plugin. - Enhance file upload security by enforcing strict `mimetypes` validation. - Update `.gitignore` to exclude sensitive WordPress configuration files and local PHPUnit caches. - Add comprehensive documentation for production deployment, including security checklists and key rotation procedures. - Update test suite to reflect new architecture and ensure 100% coverage of the discount service.
118 lines
6.4 KiB
PHP
118 lines
6.4 KiB
PHP
<?php
|
||
/**
|
||
* Plugin Name: IFNEX Logistics Bridge
|
||
* Description: اتصال فرانتاند سایت ایفنکس به API لاراول
|
||
* Version: 1.0
|
||
* Author: VernaSoft group (Kazem Alghasi)
|
||
*/
|
||
|
||
if ( ! defined( 'ABSPATH' ) ) {
|
||
exit;
|
||
}
|
||
|
||
// ─── نسخهٔ پلاگین + cache-busting سالم assetها (سختسازی Production) ───
|
||
// قبلاً اینجا opcache_reset() و header('Cache-Control: no-store') بود که فقط برای دیباگ
|
||
// لوکال مناسب است و در Production باعث header error و شکستن کش CDN/مرورگر میشد — حذف شد.
|
||
if ( ! defined( 'IFNEX_BRIDGE_VERSION' ) ) {
|
||
define( 'IFNEX_BRIDGE_VERSION', '2.1.0' );
|
||
}
|
||
|
||
/**
|
||
* نسخهٔ asset بر اساس آخرین زمان تغییر فایل.
|
||
* کش مرورگر فقط وقتی فایل واقعاً عوض شود باطل میشود — جایگزین استاندارد time().
|
||
*/
|
||
if ( ! function_exists( 'ifnex_asset_version' ) ) {
|
||
function ifnex_asset_version( string $relative_path ): string {
|
||
$file = plugin_dir_path( __FILE__ ) . ltrim( $relative_path, '/' );
|
||
$mtime = file_exists( $file ) ? (string) filemtime( $file ) : '0';
|
||
|
||
return IFNEX_BRIDGE_VERSION . '.' . $mtime;
|
||
}
|
||
}
|
||
|
||
// لود کردن فایلهای پلاگین
|
||
require_once plugin_dir_path( __FILE__ ) . 'includes/api-client.php';
|
||
require_once plugin_dir_path( __FILE__ ) . 'includes/user-bridge.php';
|
||
require_once plugin_dir_path( __FILE__ ) . 'includes/shortcodes.php';
|
||
require_once plugin_dir_path( __FILE__ ) . 'includes/tracking-form.php';
|
||
|
||
// لود کردن استایلهای و اسکریپتهای پلاگین
|
||
add_action('wp_enqueue_scripts', 'ifnex_enqueue_scripts');
|
||
function ifnex_enqueue_scripts() {
|
||
global $post;
|
||
if (is_a($post, 'WP_Post') &&
|
||
(has_shortcode($post->post_content, 'ifnex_tracking_form') ||
|
||
has_shortcode($post->post_content, 'ifnex_wallet_balance') ||
|
||
has_shortcode($post->post_content, 'ifnex_transactions') ||
|
||
has_shortcode($post->post_content, 'ifnex_tracking_status') ||
|
||
has_shortcode($post->post_content, 'ifnex_order_form') ||
|
||
has_shortcode($post->post_content, 'ifnex_user_profile') ||
|
||
has_shortcode($post->post_content, 'ifnex_orders_list') ||
|
||
has_shortcode($post->post_content, 'ifnex_order_detail') ||
|
||
has_shortcode($post->post_content, 'ifnex_order_payment') ||
|
||
has_shortcode($post->post_content, 'ifnex_customer_dashboard'))) {
|
||
wp_enqueue_style('ifnex-bridge-css', plugin_dir_url(__FILE__) . 'assets/css/ifnex-bridge.css', array('ifnex-main'), ifnex_asset_version('assets/css/ifnex-bridge.css'));
|
||
// SweetAlert2 — پاپآپ خطاها (فاز ۳.۸) — باندل محلی، بدون وابستگی به CDN
|
||
wp_enqueue_script('sweetalert2', plugin_dir_url(__FILE__) . 'assets/js/sweetalert2.all.min.js', array(), '11.14.5', true);
|
||
wp_enqueue_script('ifnex-order-form-js', plugin_dir_url(__FILE__) . 'assets/js/ifnex-order-form.js', array('jquery', 'sweetalert2'), ifnex_asset_version('assets/js/ifnex-order-form.js'), true);
|
||
}
|
||
}
|
||
|
||
// اضافه کردن لینک به منوی پیشخوان وردپرس
|
||
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']));
|
||
update_option('ifnex_bridge_api_key', sanitize_text_field($_POST['ifnex_bridge_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', '');
|
||
$bridge_api_key = get_option('ifnex_bridge_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">
|
||
<p class="description">آدرس پایه API لاراول</p>
|
||
</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">
|
||
<p class="description">برای APIهای عمومی مثل Tracking</p>
|
||
</td>
|
||
</tr>
|
||
<tr style="background: #fff3cd;">
|
||
<th scope="row"><label for="ifnex_bridge_api_key">🔐 Bridge API Key</label></th>
|
||
<td>
|
||
<input type="text" id="ifnex_bridge_api_key" name="ifnex_bridge_api_key" value="<?php echo esc_attr($bridge_api_key); ?>" class="regular-text">
|
||
<p class="description"><strong>مهم:</strong> باید با مقدار <code>IFNEX_BRIDGE_API_KEY</code> در فایل <code>.env</code> لاراول یکسان باشد.</p>
|
||
</td>
|
||
</tr>
|
||
</table>
|
||
<?php submit_button('ذخیره تنظیمات'); ?>
|
||
</form>
|
||
|
||
<hr>
|
||
<h2>راهنمای راهاندازی</h2>
|
||
<ol>
|
||
<li>در فایل <code>.env</code> لاراول، خط <code>IFNEX_BRIDGE_API_KEY=your-secret-key</code> را تنظیم کنید</li>
|
||
<li>همان مقدار را در فیلد "Bridge API Key" بالا وارد کنید</li>
|
||
<li>کاربران وردپرس باید در لاراول با همان ایمیل موجود باشند (از <code>php artisan ifnex:sync-wp-users</code> استفاده کنید)</li>
|
||
</ol>
|
||
</div>
|
||
<?php
|
||
}
|