نحوه افزودن پنل تنظیمات سفارشی به صفحه تنظیمات LA24Core.
مرور کلی
فیلتر `la24_register_setting` پنلهایی به صفحه **تنظیمات** LA24Core اضافه میکند. هر پنل دارای اولویت (ترتیب نمایش)، نام نمایشی و یک کلاس callback است که HTML پنل شامل فرم آن را رندر میکند.

امضای هوک
php
apply_filters( 'la24_register_setting', array $settings );**نوع:** Filter
**پارامترها:** `$settings` (آرایه) — رجیستری پنلهای تنظیمات فعلی
**بازگشتی:** آرایه — رجیستری تغییریافته
ثبت پنل تنظیمات
php
add_filter( 'la24_register_setting', function ( $settings ) {
$settings['my_crm_settings'] = array(
'priority' => 50,
'name' => __( 'تنظیمات CRM من', 'my-crm-ext' ),
'call_back' => '\MyPlugin\Settings\MyCrmSettings',
);
return $settings;
} );فیلدهای پنل تنظیمات
| فیلد | نوع | توضیح |
|---|---|---|
| کلید (کلید آرایه) | string | شناسه منحصربهفرد پنل تنظیمات |
| `priority` | int | ترتیب نمایش تب/پنل (صعودی) |
| `name` | string | برچسب پنل که در رابط تنظیمات نشان داده میشود |
| `call_back` | string | نام کامل کلاس تنظیمات (با namespace) |
کلاس تنظیمات
کلاسی که در `call_back` معرفی میشود باید **اینترفیس `\LoyalAxis\interfaces\Settings`** (فایل `includes/interfaces/Settings.php`) را پیادهسازی کند:
php
namespace LoyalAxis\interfaces;
interface Settings {
public static function render_view();
public static function request_process();
}هر دو متد **استاتیک** هستند و پارامتری نمیگیرند:
| متد | فراخوانی از سمت | مسئولیت |
|---|---|---|
| `request_process()` | `GeneralSettings::request_processor()` — یکبار در هر بارگذاری صفحه، **پیش از** رندر شدن هر پنلی | خواندن `$_POST`، پاکسازی (sanitize) و ذخیره مقادیر ارسالشده، و در صورت نیاز نمایش پیام موفقیت/خطا |
| `render_view()` | `GeneralSettings::tab_content_settings()` — پس از اینکه `request_process()` همهٔ پنلهای ثبتشده اجرا شد | چاپ HTML/فرم پنل، پر شده با مقادیر *فعلی* تنظیمات |
از آنجا که تمام فراخوانیهای `request_process()` پیش از هر فراخوانی `render_view()` اجرا میشوند، مقداری که در همین درخواست ذخیره شده هنگام خواندن در `render_view()` از قبل بهروز است — نیازی نیست داخل متد رندر، مقدار `$_POST` را با تنظیمات ذخیرهشده هماهنگ کنید.
نمونهٔ کلاسی که این قرارداد را رعایت میکند:
php
<?php
namespace MyPlugin\Settings;
use LoyalAxis\interfaces\Settings;
defined( 'ABSPATH' ) || exit;
class MyCrmSettings implements Settings {
public static function render_view() {
$api_key = la24_get_option( 'api_key', 'my_crm_options' );
?>
<form method="post">
<table class="form-table">
<tr>
<th><?php esc_html_e( 'کلید API', 'my-crm-ext' ); ?></th>
<td>
<input type="text" name="my_crm_api_key"
value="<?php echo esc_attr( $api_key ); ?>"
class="regular-text" />
</td>
</tr>
</table>
<button type="submit" name="my_crm_submit" class="button button-primary">
<?php esc_html_e( 'ذخیره تنظیمات', 'my-crm-ext' ); ?>
</button>
</form>
<?php
}
public static function request_process() {
if ( isset( $_POST['my_crm_submit'] ) ) {
la24_update_options( array(
'api_key' => sanitize_text_field( $_POST['my_crm_api_key'] ?? '' ),
), 'my_crm_options' );
}
}
}این ساختار همانی است که خود LA24Core در تمام ماژولهای داخلیاش بهکار میبرد. پیادهسازی مرجع، کلاس `LA24License_Settings.php` است (`includes/plugins/license/includes/classes/LA24License_Settings.php`):
php
class LA24License_Settings implements Settings {
use Notification;
public static function render_view() {
echo Form::start_form_tag( "post", "", "" );
echo Form::start_form( 0, "la24-section-box" );
echo Form::header( __( "Software License Management", 'la24core' ), 12, "la24-titr" );
$enable_sos = la24_get_option( 'enable_sos', 'la24license_options' );
echo Form::checkbox( __( "Emergency Conditions (New Sales Suspension)", 'la24core' ), 6, "enable_sos", "enable_sos", "", $enable_sos, 0, $enable_sos, '' );
// ...سایر فیلدها، هرکدام با la24_get_option() خوانده میشوند...
echo Form::submit_btn( __( "Save Settings", 'la24core' ), 12, "licenseplugin_submit", "la24_licenseplugin_submit" );
echo Form::close_form();
echo Form::close_form_tag();
}
public static function request_process() {
if ( isset( $_POST['la24_licenseplugin_submit'] ) ) {
la24_update_options(
array(
'global_keys' => /* ... */,
'interval_check_expire_license' => $_POST['interval_check_expire_license'] ?? '',
'enable_sos' => $_POST['enable_sos'] ?? '',
),
'la24license_options'
);
la24_update_options( array( 'active_setting_tab' => 'plugin_license' ) );
self::alert( __( 'License management settings saved successfully.', 'la24core' ), true, 'success' );
}
}
}دقت کنید همان ساختار `MyCrmSettings` بالا اینجا هم تکرار شده: `implements Settings`، متد استاتیک `render_view()` که مقادیر را با `la24_get_option()` میخواند، و متد استاتیک `request_process()` که ذخیره را پشت شرط `isset( $_POST[''] )` قرار میدهد و همهچیز را با یک فراخوانی `la24_update_options()` ذخیره میکند.
> **نکته:** `LA24License_Settings::request_process()` پس از ذخیره، `la24_update_options( array( 'active_setting_tab' => 'plugin_license' ) )` را نیز فراخوانی میکند تا صفحهٔ تنظیمات با همان تبی که کاربر ذخیره کرده دوباره باز شود. برای پنل خودتان هم میتوانید همین کار را با کلید پنل خودتان انجام دهید.
> **توجه:** پنلهای خود LA24Core فیلد nonce اضافه نمیکنند — دسترسی به صفحهٔ تنظیمات پیش از اجرای `request_process()` از طریق یک بررسی capability (`la24_generalsettings_access`) کنترل میشود. اگر افزونهٔ شما به محافظت CSRF بیشتری نیاز دارد، آزادید که `wp_nonce_field()` / `wp_verify_nonce()` را دور منطق ذخیرهٔ خودتان اضافه کنید.
`Form::*` (که در مثال بالا استفاده شده) ابزار داخلی رندر فرم در LA24Core است (`\LoyalAxis\classes\utilities\Form`) و اجباری نیست — HTML ساده، همانطور که در مثال `MyCrmSettings` آمده، هم بهخوبی کار میکند.
ذخیره و خواندن تنظیمات
دو روش برای ذخیرهٔ مقادیری که پنل تنظیمات شما جمعآوری میکند وجود دارد.
روش الف — توابع استاندارد وردپرس
از `update_option()` / `get_option()` بهطور مستقیم استفاده کنید. این روش در هر جای وردپرس کار میکند و اگر مقداری باید توسط کدی خارج از LA24Core هم خوانده شود (افزونهٔ دیگر، قالب و…) انتخاب درستی است:
php
// ذخیره
update_option( 'my_crm_api_key', sanitize_text_field( $_POST['api_key'] ?? '' ) );
// خواندن با مقدار پیشفرض
$api_key = get_option( 'my_crm_api_key', '' );هر مقداری که به این شکل ذخیره شود، یک ردیف جداگانه در جدول `wp_options` اشغال میکند. اگر پنل شما چند فیلد دارد، آنها را در یک آرایه گروهبندی کنید تا جدول شلوغ نشود:
php
// ذخیره
update_option( 'my_crm_options', array(
'api_key' => sanitize_text_field( $_POST['api_key'] ?? '' ),
'enabled' => (bool) ( $_POST['enabled'] ?? false ),
) );
// خواندن با مقادیر پیشفرض
$opts = wp_parse_args( get_option( 'my_crm_options', array() ), array(
'api_key' => '',
'enabled' => false,
) );روش ب — توابع کمکی LA24
توابع `la24_get_option()` و `la24_update_options()` این گروهبندی را بهطور خودکار برایتان انجام میدهند، و همان چیزی هستند که تمام ماژولهای داخلی LA24Core — از جمله `LA24License_Settings.php` بالا — استفاده میکنند:
php
// ذخیره
la24_update_options( array(
'api_key' => sanitize_text_field( $_POST['api_key'] ?? '' ),
'enabled' => $_POST['enabled'] ?? '',
), 'my_crm_options' );
// خواندن
$api_key = la24_get_option( 'api_key', 'my_crm_options' );
$enabled = la24_get_option( 'enabled', 'my_crm_options' );برای شرح کامل نحوهٔ عملکرد این دو تابع به [بخش بعدی](#آموزش-la24_get_option-و-la24_update_options) مراجعه کنید.
هر دو روش داخل یک کلاس تنظیمات قابلقبول هستند — هرکدام که با بقیهٔ افزونهٔ شما هماهنگتر است را انتخاب کنید. فقط این دو روش را برای *یک کلید یکسان* ترکیب نکنید: `update_option()` و `la24_update_options()` از دادههای یکدیگر خبر ندارند، چون دومی همهچیز را بهصورت یک آرایهٔ سریالایزشده زیر یک نام گروه ذخیره میکند.
آموزش: la24_get_option() و la24_update_options()
هر دو تابع در فایل `includes/helpers/la24-core-functions.php` تعریف شدهاند و لایهای نازک روی کلاس داخلی `\LoyalAxis\classes\utilities\Options` هستند:
php
function la24_get_option( $key, $option = 'la24_options' ) {
return Options::get_option( $key, $option );
}
function la24_update_options( array $data, $option = 'la24_options' ) {
return Options::update_options( $data, $option );
}یک تابع کمکی مرتبط در همان فایل، `la24_delete_option( $key, $option = 'la24_options' )`، یک کلید را از یک گروه حذف میکند.
مفهوم «گروه»
برخلاف `update_option()` که برای هر مقدار یک ردیف جداگانه در وردپرس میسازد، توابع کمکی LA24 **چند کلید را درون یک option سریالایزشدهٔ واحد** ذخیره میکنند — همان پارامتر `$option` (که «گروه» هم نامیده میشود). `LA24License_Settings.php` تمام تنظیمات خودش (`global_keys`، `interval_check_expire_license`، `enable_sos`، `product_id_support`، `days_support` و…) را درون یک گروه به نام `'la24license_options'` نگه میدارد و همه را با یک فراخوانی ذخیره میکند:
php
la24_update_options(
array(
'global_keys' => $temp_global_key,
'interval_check_expire_license' => $_POST['interval_check_expire_license'] ?? '',
'enable_sos' => $_POST['enable_sos'] ?? '',
'product_id_support' => $_POST['product_id_support'],
'days_support' => $_POST['days_support'],
),
'la24license_options'
);… و هرکدام را جداگانه میخواند:
php
$enable_sos = la24_get_option( 'enable_sos', 'la24license_options' );اگر پارامتر گروه را حذف کنید، پیشفرض آن `'la24_options'` است — همان گروهی که تنظیمات اصلی خود LA24Core (ورود، ظاهر، عمومی و…) در آن قرار دارند. **همیشه برای افزونهٔ خودتان یک نام گروه صریح و منحصربهفرد بگذارید** (مثلاً `'my_crm_options'`) تا کلیدهایتان با تنظیمات خود LA24Core یا افزونهای دیگر تداخل نکند.
`la24_get_option( $key, $group = 'la24_options' )`
مقدار `$key` را از آرایهٔ ذخیرهشدهٔ گروه میخواند:
۱. اگر گروه از قبل مقداری **غیرخالی** برای `$key` داشته باشد، همان مقدار بدون تغییر برگردانده میشود (شامل آرایهها).
۲. در غیر این صورت، LA24Core بهدنبال یک `default` ثبتشده برای `$key` میگردد (به بخش بعد نگاه کنید) و در صورت وجود همان را برمیگرداند، وگرنه `null`.
`la24_update_options( array $data, $group = 'la24_options' )`
آرایهٔ `$data` را با آرایهٔ موجود گروه ادغام میکند و با یک فراخوانی `update_option()` ذخیره میکند:
- هر کلید موجود در `$data` همان کلید در گروه را بازنویسی میکند.
- **یک مقدار خالی (`''`، `null`، `false`، `0`، `[]`) بهجای ذخیره شدن، آن کلید را از گروه حذف میکند** — برای مثال، یک چکباکس تیکنخورده در فراخوانی بعدی `la24_get_option()` بهدرستی به مقدار پیشفرض خودش برمیگردد، بهجای اینکه بهصورت رشتهٔ خالی ذخیره شده باشد.
- کلیدهایی که در `$data` نیستند دستنخورده باقی میمانند.
بنابراین یک `request_process()` معمولی فقط لازم است فیلدهایی را که واقعاً ارسال شدهاند ارسال کند:
php
public static function request_process() {
if ( isset( $_POST['my_crm_submit'] ) ) {
la24_update_options( array(
'api_key' => sanitize_text_field( $_POST['api_key'] ?? '' ),
'enabled' => $_POST['enabled'] ?? '',
), 'my_crm_options' );
}
}اختیاری: مقادیر پیشفرض و قوانین پاکسازی
میتوانید متادیتای هر کلید در گروه خودتان — یک مقدار `default` و یک قانون پاکسازی `rule` — را با هوک کردن فیلتر `la24_settings_option` ثبت کنید، دقیقاً همانطور که `LA24License_Hook::settings_option()` برای ماژول License انجام میدهد:
php
add_filter( 'la24_settings_option', function ( $settings ) {
$settings['my_crm_options'] = array(
'api_key' => array(
'rule' => 'text_field', // در هر بار ذخیره از Sanitizer::text_field() عبور میکند
'default' => '',
),
'enabled' => array(
'rule' => 'number',
),
);
return $settings;
} );مقادیر مجاز برای `rule` مستقیماً با متدهای کلاس `\LoyalAxis\classes\utilities\Sanitizer` مطابقت دارند — `text_field`، `number`، `url`، `email`، `checkbox`، `html` و چند نوع `array_of_*` برای فیلدهای تکرارشونده.
این مرحله اختیاری است — `la24_get_option()` / `la24_update_options()` بدون آن هم بهدرستی کار میکنند، به شرطی که خودتان پیش از فراخوانی `la24_update_options()`، مقادیر `$_POST` را پاکسازی کنید — دقیقاً همانطور که در مثالهای بالا انجام شده. ثبت یک `rule` عمدتاً شما را از تکرار `sanitize_text_field()` در هر نقطهٔ ذخیره بینیاز میکند، و یک `default` شما را از تکرار `?: 'مقدار-پیشفرض'` در هر نقطهٔ خواندن بینیاز میکند.
مثال کامل پنل تنظیمات
برای یک پنل تنظیمات چندفیلدی با تنظیمات گروهبندیشده و بازخورد موفقیت، به کلاس `DealsSettings` در **developer-guide-la24_extension_examples_fa.md** مراجعه کنید که مستقیماً بر اساس `LA24License_Settings.php` واقعی موجود در LA24Core ساخته شده است.
