نحوه افزودن پنل تنظیمات سفارشی به صفحه تنظیمات

نحوه افزودن پنل تنظیمات سفارشی به صفحه تنظیمات 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 ساخته شده است.