التطوير

تطوير الإضافات

تعلّم كيفية بناء إضافاتك الخاصة لكليجا.

تضيف إضافات كليجا مزايا جديدة إلى السكربت دون المساس بملفات النواة. تعيش كل إضافة في مجلد خاص بها داخل plugins/، وتُعرّف نفسها في ملف init.php واحد، ثم تربط دوالها بـ خطّافات تستدعيها النواة أثناء تنفيذ الصفحة.

ولأن الإضافات لا تعدّل النواة، فإن ترقية كليجا لا تمحو تعديلاتك. يحمّل النظام الإضافات المثبّتة والمفعّلة فقط، لذا يمكن تعطيل أي إضافة معطوبة من لوحة التحكم بدل حذفها يدوياً.

تشرح هذه الصفحة نظام الإضافات في كليجا 3.x. يوجد المحمّل في includes/plugins.php، ومدير الإضافات في includes/adm/j_plugins.php.

كيف يعمل النظام

مع كل طلب، يهيّئ ملف includes/common.php كائن Plugins المفرد. يقرأ الباني جدول plugins ويحتفظ بالصفوف التي قيمة plg_disabled فيها تساوي صفراً، ثم يضمّن ملف init.php لكل مجلد مطابق داخل plugins/.

يملأ كل ملف init.php مصفوفة $kleeja_plugin ببيانات الإضافة ودوال دورة حياتها ودوال خطّافاتها. يسجّل المحمّل بعدها هذه الدوال في خريطة عامة مرتّبة حسب أولوية الإضافة.

تستدعي ملفات النواة بعد ذلك Plugins::getInstance()->run('hook_name', get_defined_vars()) عند نقاط ثابتة. تستقبل كل دالة مسجّلة على ذلك الخطّاف متغيرات المستدعي، ويُدمج ما تُرجعه في نطاق المستدعي.

بنية المجلد

الإضافة مجلد يطابق اسمه المفتاح المستخدم داخل init.php. يقرأ كليجا اسم المجلد من القرص ثم يبحث عنه في المصفوفة، لذا يجب أن يتطابق الاثنان.

plugins/
plugins/
└── my_plugin/
    ├── init.php      # مطلوب — تعريف الإضافة بالكامل
    ├── icon.png      # اختياري — تظهر في قائمة الإضافات
    ├── index.html    # اختياري — يمنع عرض محتويات المجلد
اسم المجلد هو مفتاح الإضافة. يجب أن يعرّف الملف plugins/my_plugin/init.php المصفوفة $kleeja_plugin['my_plugin']، وإلا تجاهل المحمّل الإضافة. استخدم الحروف الصغيرة والأرقام والنقاط والشرطات السفلية، وبطول ثلاثة محارف على الأقل.

ملف init.php

يبدأ كل ملف init.php بحارس. يُعرَّف الثابت IN_PLUGINS_SYSTEM في includes/plugins.php، لذا يتوقف الملف عن العمل إذا طلبه أحدهم مباشرة من المتصفح.

plugins/my_plugin/init.php
<?php
// منع التشغيل المباشر
if (! defined('IN_PLUGINS_SYSTEM')) {
    exit();
}

$kleeja_plugin['my_plugin']['information'] = [ /* ... */ ];
$kleeja_plugin['my_plugin']['first_run']['ar'] = 'شكراً لتثبيت الإضافة!';
$kleeja_plugin['my_plugin']['install']   = function ($plg_id) { /* ... */ };
$kleeja_plugin['my_plugin']['update']    = function ($old_version, $new_version) { /* ... */ };
$kleeja_plugin['my_plugin']['uninstall'] = function ($plg_id) { /* ... */ };
$kleeja_plugin['my_plugin']['functions'] = [ /* اسم الخطّاف => دالة */ ];
عرّف المفاتيح الستة كلها حتى لو كانت بعض الدوال فارغة. يقرأ المحمّل ومدير الإضافات المفاتيح information وupdate وinstall وuninstall مباشرة، والمفتاح الناقص يسبّب تحذيراً من PHP. أما الإضافة التي لا تعرّف دالة uninstall فلا يمكن إزالتها من لوحة التحكم إطلاقاً — يعيدك المدير إلى قائمة الإضافات.

معلومات الإضافة

تصف مصفوفة information الإضافة للوحة التحكم، وتتحكم بفحص التوافق وترتيب التحميل.

المفتاحالنوعالغرض
plugin_titlearrayالاسم المعروض لكل لغة، مثل ['en' => 'My Plugin', 'ar' => 'إضافتي']. يرجع إلى en ثم إلى أول عنصر.
plugin_developerstringاسم المطوّر، ويُخزَّن في plg_author.
plugin_versionstringإصدار الإضافة. يعتمد عليه فحص التحديث التلقائي، فارفعه مع كل إصدار.
plugin_descriptionarrayوصف مختصر لكل لغة. يظهر في قائمة الإضافات مقتطعاً عند 100 محرف.
plugin_kleeja_version_minstringأدنى إصدار مدعوم من كليجا. يفشل التثبيت دونه.
plugin_kleeja_version_maxstringأعلى إصدار مدعوم من كليجا. استخدم 0 لإلغاء الحد.
plugin_priorityintترتيب التحميل. الرقم الأعلى يعمل أولاً، و0 هو الوضع الطبيعي.
settings_pagestringاختياري. سلسلة الاستعلام لصفحة إعدادات الإضافة، تُضاف بعد admin/?، وتُظهر أيقونة ترس بجانب الإضافة.
plugins/my_plugin/init.php
$kleeja_plugin['my_plugin']['information'] = [
    'plugin_title' => [
        'en' => 'My Plugin',
        'ar' => 'إضافتي',
    ],
    'plugin_developer' => 'اسمك',
    'plugin_version'   => '1.0',
    'plugin_description' => [
        'en' => 'Does something useful',
        'ar' => 'تقوم بشيء مفيد',
    ],
    'plugin_kleeja_version_min' => '3.2.0',
    'plugin_kleeja_version_max' => '3.9',
    'plugin_priority'           => 0,
    'settings_page'             => 'cp=options&amp;smt=my_plugin',
];
يُفحص حدّا الإصدار مرة واحدة فقط، عند التثبيت، عبر version_compare() مقابل KLEEJA_VERSION. اجعل plugin_kleeja_version_max واسعاً — فالحد الأعلى الضيّق يمنع التثبيت على إصدارات كليجا الأحدث حتى لو كانت الإضافة تعمل عليها.

رسالة التشغيل الأول

يحمل المفتاح first_run رسالة HTML تظهر فور نجاح التثبيت. يختار كليجا النص المطابق للغة الموقع ويرجع إلى en عند عدم وجوده.

plugins/my_plugin/init.php
$kleeja_plugin['my_plugin']['first_run']['ar'] = '
شكراً لتثبيت هذه الإضافة. للإبلاغ عن الأخطاء: <br>
info@example.com
';

عند غياب first_run تعيدك لوحة التحكم إلى قائمة الإضافات بعد ثانيتين بدل انتظار نقرة منك.

دالة التثبيت

تعمل دالة install مرة واحدة، بعد إدراج صف الإضافة في جدول plugins. تستقبل الدالة رقم plg_id الجديد، ومرّره إلى add_config_r() وadd_olang() كي يربط كليجا إعداداتك وعباراتك اللغوية بالإضافة.

plugins/my_plugin/init.php
$kleeja_plugin['my_plugin']['install'] = function ($plg_id) {
    add_config_r([
        'my_plugin_enabled' => [
            'value'  => '1',
            'html'   => configField('my_plugin_enabled', 'yesno'),
            'plg_id' => $plg_id,
            'type'   => 'my_plugin',
            'order'  => '1',
        ],
        'my_plugin_api_key' => [
            'value'  => '',
            'html'   => configField('my_plugin_api_key'),
            'plg_id' => $plg_id,
            'type'   => 'my_plugin',
            'order'  => '2',
        ],
    ]);

    add_olang([
        'CONFIG_KLJ_MENUS_MY_PLUGIN' => 'إعدادات إضافتي',
        'MY_PLUGIN_ENABLED'          => 'تفعيل الإضافة',
        'MY_PLUGIN_API_KEY'          => 'مفتاح الواجهة البرمجية',
    ], 'ar', $plg_id);
};
يُخفي كليجا أخطاء قاعدة البيانات أثناء التثبيت، لذا يفشل الاستعلام الخاطئ بصمت. اختبر دالة التثبيت على قاعدة بيانات تجريبية قبل النشر.

دالة التحديث

يقارن المحمّل الإصدار المثبّت المخزَّن في plg_ver بقيمة plugin_version في init.php مع كل طلب. فإذا أعلن الملف إصداراً أحدث، استدعى كليجا دالة update ثم كتب الإصدار الجديد في قاعدة البيانات.

plugins/my_plugin/init.php
$kleeja_plugin['my_plugin']['update'] = function ($old_version, $new_version) {
    if (version_compare($old_version, '1.1', '<')) {
        add_config('my_plugin_timeout', '30', 3, configField('my_plugin_timeout'), 'my_plugin');
    }

    if (version_compare($old_version, '2.0', '<')) {
        update_config('my_plugin_api_key', '');
    }
};

احرس كل ترحيل بفحص version_compare() على $old_version. فقد يقفز المستخدمون عدة إصدارات دفعة واحدة، ويجب أن تتعامل الدالة مع كل مسار من أي إصدار قديم إلى الإصدار الحالي.

دالة الإزالة

تعمل دالة uninstall قبل حذف صف الإضافة. احذف فيها كل ما أنشأته دالة التثبيت — الإعدادات والعبارات اللغوية وأي جداول خاصة.

plugins/my_plugin/init.php
$kleeja_plugin['my_plugin']['uninstall'] = function ($plg_id) {
    delete_config([
        'my_plugin_enabled',
        'my_plugin_api_key',
    ]);

    foreach (['ar', 'en'] as $language) {
        delete_olang(null, $language, $plg_id);
    }
};
تمرير null كمعامل أول لـ delete_olang() مع تمرير plg_id يحذف كل العبارات التابعة للإضافة في تلك اللغة. هذه أنظف طريقة للتراجع عن add_olang().

الخطّافات

الخطّافات هي المدخل الوحيد لنظام الإضافات إلى منطق النواة. يوفّر كليجا أكثر من 200 خطّاف موزّعة على index.php وgo.php وdo.php وucp.php وadmin/index.php وملفات includes/.

كيف تستدعي النواة الخطّاف

تبدو معظم مواضع الاستدعاء هكذا. يستقبل الخطّاف كل متغير في النطاق عند تلك النقطة، وتكتب extract() القيم المُرجَعة فوقها.

includes/common.php
is_array($plugin_run_result = Plugins::getInstance()->run('end_common', get_defined_vars()))
    ? extract($plugin_run_result)
    : null; //run hook

تستخدم المواضع الأحدث الاختصار runHook()، وهو مكافئ تماماً:

do.php
extract(runHook('begin_download_page', get_defined_vars()));

كتابة دالة خطّاف

سجّل دوال الخطّافات في مصفوفة functions مفهرسةً باسم الخطّاف. تأخذ كل دالة مصفوفة $args واحدة، وتُرجع مصفوفة من المتغيرات المطلوب كتابتها — أو لا تُرجع شيئاً إن كانت للمراقبة فقط.

plugins/my_plugin/init.php
$kleeja_plugin['my_plugin']['functions'] = [
    // تغيير متغير في نطاق المستدعي
    'Saaheader_links_func' => function ($args) {
        $extra = $args['extra'] . '<meta name="generator" content="Kleeja">';

        return compact('extra');
    },

    // مراقبة فقط — بلا قيمة مُرجَعة
    'ok_added_users_register' => function ($args) {
        my_plugin_log('new user: ' . $args['username']);
    },
];
دوال الخطّافات إغلاقات (closures)، فهي لا ترث نطاق المستدعي. اقرأ حالة النواة من $args، واستدعِ المتغيرات العامة صراحةً عبر global $config; عند الحاجة إليها.

القيمة المُرجَعة مهمة:

القيمة المُرجَعةالأثر
compact('var') أو ['var' => $value]تستبدل $var في نطاق المستدعي.
[] أو null أو بلا returnتترك المستدعي دون تغيير.
مفتاح جديد غير موجود لدى المستدعيينشئ ذلك المتغير في نطاق المستدعي.

الأولوية والتسلسل

يتحكم plugin_priority بالترتيب. يرتّب المحمّل الخطّافات من الأولوية الأعلى إلى الأدنى، فتعمل الإضافة ذات الأولوية 10 قبل الإضافة ذات الأولوية 0.

تتسلسل الخطّافات: تدمج run() القيمة المُرجَعة من كل دالة في $args قبل استدعاء الدالة التالية. لذا ترى الإضافة المتأخرة القيم التي أنتجتها الإضافة السابقة، لا القيم الأصلية.

امنح الإضافات أولويات مختلفة حين يهمّ الترتيب. يفهرس المحمّل قائمته الداخلية بالأولوية، لذا تستبدل الإضافتان المتساويتان في الأولوية إحداهما الأخرى في تلك القائمة — تعمل خطّافاتهما رغم ذلك، لكن السجل الداخلي يصبح ملتبساً.

أسماء الخطّافات الديناميكية

تُبنى بعض أسماء الخطّافات من متغير الطلب، ما يتيح للإضافة أن تستولي على اسم صفحة غير موجود في النواة. تبني لوحة التحكم ثلاثة منها من قيمة cp المطلوبة:

admin/index.php
Plugins::getInstance()->run("require_admin_page_begin_{$go_to}", get_defined_vars());
Plugins::getInstance()->run("require_admin_page_end_{$go_to}", get_defined_vars());
Plugins::getInstance()->run("not_exists_{$go_to}", get_defined_vars());

مرجع الخطّافات

مجموعة مختارة من أكثر الخطّافات فائدة. للحصول على القائمة الكاملة ابحث في الشيفرة بالأمر grep -rn "run('" --include="*.php" ..

الخطّافالموضعمتى يعمل
boot_commonincludes/common.php:250بعد جهوزية الإعدادات وقاعدة البيانات ومحرك القوالب.
end_commonincludes/common.php:396بعد انتهاء الإقلاع، وقبل تنفيذ سكربت الصفحة.
Saaheader_links_funcincludes/functions_display.php:104عند بناء قوائم الترويسة — أضف وسوم الميتا عبر $extra، أو عناصر القائمة عبر $top_menu.
Saaheader_funcincludes/functions_display.php:150بعد توليد HTML الترويسة وقبل طباعته.
Saafooter_funcincludes/functions_display.php:235بعد إسناد متغيرات التذييل وقبل توليده.
print_Saafooter_funcincludes/functions_display.php:241بعد توليد HTML التذييل وقبل طباعته.
begin_index_pageindex.php:30عند بدء صفحة الرفع.
end_index_pageindex.php:181عند انتهاء صفحة الرفع.
begin_go_pagego.php:21عند بدء أي طلب على go.php.
default_go_pagego.php:709حين لا تطابق قيمة go أي صفحة في النواة.
begin_download_pagedo.php:17عند بدء طلب تحميل.
down_go_pagedo.php:396قبل عرض صفحة التحميل مباشرة.
begin_usrcp_pageucp.php:18عند بدء أي طلب على لوحة المستخدم.
login_after_submitucp.php:67بعد إرسال نموذج تسجيل الدخول.
ok_added_users_registerucp.php:282بعد إدراج صف مستخدم جديد.
begin_admin_pageadmin/index.php:221عند بدء لوحة التحكم، بعد اكتشاف الامتدادات.
end_admin_pageadmin/index.php:404حين يصبح كل شيء جاهزاً للعرض — اضبط $extra_admin_header_code أو $extra_admin_footer_code.
kleeja_send_mailincludes/functions.php:242قبل إرسال كليجا لرسالة بريدية.
kleeja_fetch_file_startincludes/FetchFile.php:79عند بدء جلب ملف بعيد.
style_parse_funcincludes/style.php:116عند ترجمة قالب — عدّل $html لحقن شيفرة.
delete_cache_funcincludes/functions.php:281عند مسح عنصر من الذاكرة المؤقتة.

إضافة إعدادات إلى لوحة التحكم

يخزّن كليجا الإعدادات في جدول config. يظهر الإعداد الذي يملك قيمة option في لوحة التحكم ← الخيارات، مُجمَّعاً في تبويب حسب قيمة type.

تسجيل الإعدادات

استخدم add_config_r() داخل دالة التثبيت. اضبط type على معرّف إضافتك كي تحصل الإعدادات على تبويب خاص بها، ومرّر plg_id كي تختفي من قائمة التبويبات عند تعطيل الإضافة.

plugins/my_plugin/init.php
add_config_r([
    'my_plugin_mode' => [
        'value'  => 'fast',
        'html'   => configField('my_plugin_mode', 'select', [
            'سريع' => 'fast',
            'دقيق' => 'accurate',
        ]),
        'plg_id' => $plg_id,
        'type'   => 'my_plugin',
        'order'  => '1',
    ],
]);

تولّد الدالة configField() من includes/functions_display.php شيفرة الحقل بصيغة قوالب كليجا:

النوعما يولّده
textحقل نصي مرتبط بـ {con.name}، وهو النوع الافتراضي.
yesnoزرّا اختيار يستخدمان العبارتين YES وNO.
selectقائمة منسدلة تُبنى من مصفوفة $select_options بصيغة ['العنوان' => 'القيمة'].

تسمية تبويب الإعدادات

يقرأ تبويب الإعدادات عنوانه من مفتاح اللغة CONFIG_KLJ_MENUS_<TYPE> بحروف كبيرة. أضف تلك العبارة في دالة التثبيت، وأضف عنوان كل إعداد باسمه <NAME> بحروف كبيرة.

plugins/my_plugin/init.php
add_olang([
    'CONFIG_KLJ_MENUS_MY_PLUGIN' => 'إعدادات إضافتي',
    'MY_PLUGIN_MODE'             => 'وضع المعالجة',
], 'ar', $plg_id);

يظهر التبويب حتى بدون CONFIG_KLJ_MENUS_MY_PLUGIN، لكنه يحمل عنوان خيارات أخرى.

قراءة الإعدادات أثناء التشغيل

تُخزَّن الإعدادات مؤقتاً وتُتاح عبر المصفوفة العامة $config:

plugins/my_plugin/init.php
$kleeja_plugin['my_plugin']['functions'] = [
    'end_index_page' => function ($args) {
        global $config;

        if ($config['my_plugin_mode'] === 'fast') {
            // ...
        }
    },
];

العبارات اللغوية

تعيش عبارات الإضافات في جدول lang وتُتاح عبر المصفوفة العامة $olang إلى جانب $lang الخاصة بالنواة. تقرؤها القوالب بالصيغة {olang.KEY}.

الدالةالتوقيعالغرض
add_olang()add_olang(array $words, string $lang, int $plg_id)إدراج عبارات للغة واحدة.
update_olang()update_olang(string $name, string $value, string $lang)تعديل عبارة واحدة.
delete_olang()delete_olang($words, $lang, int $plg_id)حذف العبارات؛ مرّر null مع plg_id لحذف كل عبارات الإضافة.

استدعِ add_olang() مرة لكل لغة تدعمها إضافتك:

plugins/my_plugin/init.php
add_olang(['MY_PLUGIN_TITLE' => 'My Plugin'], 'en', $plg_id);
add_olang(['MY_PLUGIN_TITLE' => 'إضافتي'], 'ar', $plg_id);

القوالب والتصاميم

يعرض كليجا الصفحات عبر الكائن $tpl. تترجم الدالة display($template_name, $style_path) القالب إلى مجلد cache/ وتُرجع الـ HTML، حيث $style_path مسار مطلق يتجاوز التصميم النشط.

تستطيع الإضافة أن تشحن قوالبها الخاصة وتوجّه كليجا إليها. تستبدل الإضافة المرفقة zaki_admin_theme تصميم لوحة التحكم بالكامل من خطّاف end_common:

plugins/zaki_admin_theme/init.php
$kleeja_plugin['zaki_admin_theme']['functions'] = [
    'end_common' => function ($args) {
        if (! defined('IN_ADMIN')) {
            return;
        }

        global $config;

        $args['STYLE_PATH_ADMIN_ABS']   = PATH . 'plugins/zaki_admin_theme/zaki/';
        $args['DEFAULT_PATH_ADMIN_ABS'] = PATH . 'plugins/zaki_admin_theme/zaki/';
        $args['DEFAULT_PATH_ADMIN']     = $config['siteurl'] . 'plugins/zaki_admin_theme/zaki/';
        $args['STYLE_PATH_ADMIN']       = $config['siteurl'] . 'plugins/zaki_admin_theme/zaki/';

        return $args;
    },
];

المتغيرات المنتهية بـ _ABS مسارات على نظام الملفات تُستخدم لتحديد موضع القوالب، أما البقية فروابط تُستخدم داخل القوالب لتحميل ملفات CSS وJavaScript والصور.

لحقن شيفرة داخل قالب قائم بدل استبداله، استخدم الخطّاف style_parse_func وعدّل $html قبل الترجمة، أو الخطّاف Saaheader_func وعدّل $header بعد التوليد.

إضافة صفحات جديدة

صفحة في الواجهة

يستدعي go.php الخطّاف default_go_page حين لا يطابق المعامل go أي صفحة في النواة. اضبط $no_request على false للاستيلاء على الطلب، ثم اختر القالب عبر $stylee و$styleePath.

plugins/my_plugin/init.php
$kleeja_plugin['my_plugin']['functions'] = [
    'default_go_page' => function ($args) {
        if (g('go', 'str') !== 'mypage') {
            return;
        }

        global $tpl;

        $tpl->assign('my_message', 'مرحباً من إضافتي');

        $no_request = false;
        $stylee     = 'my_page';
        $styleePath = PATH . 'plugins/my_plugin/templates/';

        return compact('no_request', 'stylee', 'styleePath');
    },
];

ضع القالب في plugins/my_plugin/templates/my_page.html. عندها يقدّم كليجا الصفحة على العنوان go.php?go=mypage.

صفحة في لوحة التحكم

تبني لوحة التحكم قائمتها من ملفات PHP الموجودة في includes/adm/. وحين تكون الصفحة المطلوبة غير موجودة، تستدعي الخطّاف not_exists_{$go_to} وتضمّن المسار الذي تسنده إلى $include_alternative.

plugins/my_plugin/init.php
'not_exists_mypanel' => function ($args) {
    $include_alternative = PATH . 'plugins/my_plugin/admin_page.php';

    return compact('include_alternative');
},

يضبط ملفك المضمَّن المتغيرين $stylee و$styleePath تماماً كأي امتداد إداري في النواة. تصل إلى الصفحة عبر admin/?cp=mypanel.

إذا كانت إضافتك تحتاج شاشة إعدادات فقط، فاستغنِ عن الصفحة المخصصة واضبط settings_page في مصفوفة المعلومات على cp=options&amp;smt=my_plugin. عندها تعرض لوحة التحكم أيقونة ترس تنقلك مباشرة إلى تبويب إعداداتك.

إدارة الإضافات

يدير المؤسسون الإضافات من لوحة التحكم ← الإضافات. يعرض المدير ثلاث مجموعات: الإضافات المثبّتة، والمجلدات الموجودة على الخادم دون تثبيت، والإضافات المتاحة في الفهرس البعيد.

الإجراءالأثر
التثبيتيدرج صف plugins، ويشغّل install، ويعرض رسالة first_run.
التعطيليضبط plg_disabled = 1. تبقى الإضافة مثبّتة لكنها لا تُحمَّل، ويختفي تبويب إعداداتها.
التفعيليصفّر plg_disabled.
الإزالةيشغّل uninstall ويحذف صف plugins. تبقى الملفات على الخادم.
حذف المجلديحذف مجلد الإضافة من plugins/.
الرفعيفكّ ضغط ملف .zip مرفوع داخل plugins/.
التنزيليجلب الإضافة من الفهرس البعيد ويفكّ ضغطها، مع تراجع تلقائي عند الفشل.
حسابات المؤسسين وحدها تستطيع تثبيت الإضافات أو إزالتها أو تفعيلها أو تعطيلها أو رفعها. وكل إجراء محمي بمفتاح نموذج ضد هجمات CSRF.

التحزيم والتوزيع

وزّع الإضافة كملف .zip يحتوي مجلداً واحداً في جذره. يرفعه المديرون من لوحة التحكم ← الإضافات، ويفكّ كليجا ضغطه مباشرة داخل plugins/.

Terminal
zip -r my_plugin.zip my_plugin -x "*.git*"

أضف ملف icon.png إلى مجلد الإضافة للحصول على أيقونة مخصصة في قائمة الإضافات، وملف index.html فارغ لمنع عرض محتويات المجلد على الخوادم التي تسمح بذلك.

يقرأ كليجا أيضاً فهرساً عاماً، فتُثبَّت الإضافات المدرجة فيه بنقرة واحدة:

فهرس متجر كليجا.

تنقيح الأخطاء

أضف define('DEV_STAGE', true); إلى ملف config.php لتفعيل أدوات التنقيح. عندها يتوقف تخزين القوالب مؤقتاً، وتُعرض كل أخطاء PHP، ويظهر رابط Debug Info في تذييل الصفحة للمديرين.

تطبع صفحة التنقيح خريطة الخطّافات المسجّلة وقائمة الإضافات المثبّتة، وهي أسرع وسيلة للتأكد من صحة كتابة أسماء خطّافاتك:

includes/plugins.php
public function getDebugInfo(): array
{
    if (!defined('DEV_STAGE')) {
        return [];
    }

    return [
        'all_plugins_hooks' => $this->all_plugins_hooks,
        'installed_plugins' => $this->installed_plugins,
    ];
}

التعافي من إضافة معطوبة

حين تعطّل إضافةٌ الموقعَ إلى حد تعذّر الوصول إلى لوحة التحكم، أوقف النظام بأكمله من config.php:

config.php
define('STOP_PLUGINS', true);

يعود المحمّل فوراً دون تضمين أي إضافة، ويعرض التذييل Hook System: Disabled. احذف السطر بعد تعطيل الإضافة المسببة للمشكلة أو حذفها.

يُضمَّن ملف init.php مع كل طلب دون استثناء. اقصره على التعريفات فقط — لا تنفّذ فيه استعلامات أو طلبات شبكة أو فحص ملفات في المستوى الأعلى، وإلا أبطأت كل صفحة في الموقع.

مثال كامل

إضافة بسيطة تضيف إعداداً واحداً وتلحق ملاحظة مخصصة بتذييل الموقع.

plugins/footer_note/init.php
<?php
// منع التشغيل المباشر
if (! defined('IN_PLUGINS_SYSTEM')) {
    exit();
}

$kleeja_plugin['footer_note']['information'] = [
    'plugin_title' => [
        'en' => 'Footer Note',
        'ar' => 'ملاحظة التذييل',
    ],
    'plugin_developer' => 'اسمك',
    'plugin_version'   => '1.0',
    'plugin_description' => [
        'en' => 'Appends a custom note to the site footer',
        'ar' => 'تضيف ملاحظة مخصصة إلى تذييل الموقع',
    ],
    'plugin_kleeja_version_min' => '3.2.0',
    'plugin_kleeja_version_max' => '3.9',
    'plugin_priority'           => 0,
    'settings_page'             => 'cp=options&amp;smt=footer_note',
];

$kleeja_plugin['footer_note']['first_run']['ar'] = 'اضبط نص الملاحظة من: لوحة التحكم ← الخيارات ← ملاحظة التذييل.';

$kleeja_plugin['footer_note']['install'] = function ($plg_id) {
    add_config_r([
        'footer_note_text' => [
            'value'  => '',
            'html'   => configField('footer_note_text'),
            'plg_id' => $plg_id,
            'type'   => 'footer_note',
            'order'  => '1',
        ],
    ]);

    add_olang([
        'CONFIG_KLJ_MENUS_FOOTER_NOTE' => 'ملاحظة التذييل',
        'FOOTER_NOTE_TEXT'             => 'نص الملاحظة',
    ], 'ar', $plg_id);

    add_olang([
        'CONFIG_KLJ_MENUS_FOOTER_NOTE' => 'Footer note',
        'FOOTER_NOTE_TEXT'             => 'Note text',
    ], 'en', $plg_id);
};

$kleeja_plugin['footer_note']['update'] = function ($old_version, $new_version) {
    // لا ترحيلات حتى الآن
};

$kleeja_plugin['footer_note']['uninstall'] = function ($plg_id) {
    delete_config(['footer_note_text']);

    foreach (['ar', 'en'] as $language) {
        delete_olang(null, $language, $plg_id);
    }
};

$kleeja_plugin['footer_note']['functions'] = [
    'print_Saafooter_func' => function ($args) {
        global $config;

        if (empty($config['footer_note_text'])) {
            return;
        }

        $note   = '<p class="footer-note">' . htmlspecialchars($config['footer_note_text']) . '</p>';
        $footer = str_replace('</body>', $note . '</body>', $args['footer']);

        return compact('footer');
    },
];

المرجع البرمجي

الدوال المساعدة المتاحة للإضافات، وجميعها معرّفة في includes/functions.php ما لم يُذكر خلاف ذلك.

الدالةالتوقيع
add_config()add_config(string $name, string $value, int $order = 0, string $html = '', string $type = '0', int $plg_id = 0, bool $dynamic = false): bool
add_config_r()add_config_r(array $configs): bool
update_config()update_config(string $name, string $value, bool $escape = true, int $group = 0): bool
delete_config()delete_config(string|array $name): bool
add_olang()add_olang(array $words = [], string $lang = 'en', int $plg_id = 0): void
update_olang()update_olang(string $name, string $value, string $lang = 'en'): bool
delete_olang()delete_olang(string|array $words = '', string $lang = 'en', int $plg_id = 0): bool
configField()configField(string $name, string $type = 'text', array $select_options = []): string — في includes/functions_display.php
runHook()runHook(string $hookName, array $definedVariables): array — في includes/plugins.php

الثوابت

الثابتالمعنى
IN_PLUGINS_SYSTEMيُعرَّف أثناء تحميل الإضافات. احرس به كل ملف init.php.
STOP_PLUGINSيُعرَّف في config.php لتعطيل نظام الإضافات بالكامل.
KLEEJA_PLUGINS_FOLDERاسم مجلد الإضافات، وهو plugins افتراضياً.
KLEEJA_VERSIONإصدار كليجا العامل، ويُستخدم في فحص التوافق.
PATHالمسار المطلق لجذر كليجا على نظام الملفات، وينتهي بشرطة مائلة.
DEV_STAGEيفعّل مخرجات التنقيح ويوقف تخزين القوالب مؤقتاً.
IN_ADMINيُعرَّف أثناء عرض لوحة التحكم.
Kleeja 2007-2026