سیستم هوک الوند یک معماری رویدادمحور (Event-Driven) برای توسعهپذیری است که در کلاس Hook در core/modules.php پیادهسازی شده. این سیستم از دو نوع اکشن (Action) و فیلتر (Filter) تشکیل شده و از الگوی WordPress-style پیروی میکند.
معماری
Hook Class (core/modules.php)
|-- addAction() # ثبت اکشن
|-- doAction() # اجرای اکشن
|-- addFilter() # ثبت فیلتر
|-- applyFilters() # اعمال فیلترها
|-- hasHook() # بررسی وجود هوک
|-- removeHook() # حذف یک callback
|-- clearHook() # پاکسازی همه callbackها
اکشنها (Actions)
اکشنها در نقاط مشخصی از اجرای برنامه فراخوانی میشوند و به پلاگینها اجازه میدهند کد دلخواه خود را در آن نقاط اجرا کنند.
ثبت اکشن
php
Hook::addAction(string $hookName, callable $callback, int $priority = 10): void
مثال:
php
Hook::addAction('theme/footer', function() {
echo '<p>متن دلخواه در فوتر</p>';
});
اجرای اکشن
php
Hook::doAction(string $hookName, ...$params): void
مثال:
php
Hook::doAction('frontend/footer');
Hook::doAction('admin/dashboard/widgets/snapshot', $snapshotColClass, $dashboardWidgets);
فیلترها (Filters)
فیلترها به پلاگینها اجازه میدهند مقادیر بازگشتی را تغییر دهند. تابع applyFilters مقدار را از طریق همه فیلترهای ثبت شده عبور میدهد.
ثبت فیلتر
php
Hook::addFilter(string $hookName, callable $callback, int $priority = 10): void
مثال:
php
Hook::addFilter('service_providers/payment', function($providers) {
$providers[] = [
'slug' => 'my_gateway',
'title' => 'درگاه من',
'class' => 'MyGatewayPlugin'
];
return $providers;
});
اعمال فیلتر
php
Hook::applyFilters(string $hookName, $value, ...$params)
مثال:
php
$catalog = Hook::applyFilters('service_providers/payment', []);
$metaTags = Hook::applyFilters('header_template/meta_tags', $metaTags, $context);
اولویتبندی (Priority)
هر هوک میتواند یک اولویت عددی داشته باشد. عدد کمتر = اجرای زودتر:
php
Hook::addAction('init', $callback, 1); // اول بالا
Hook::addAction('init', $callback, 10); // پیشفرض
Hook::addAction('init', $callback, 20); // اول پایین
پرش از پلاگینهای غیرفعال
سیستم هوک به صورت خودکار callbackهایی که متعلق به پلاگینهای غیرفعال هستند را نادیده میگیرد. این کار با استفاده از ReflectionMethod/ReflectionFunction برای تشخیص فایل مبدأ callback انجام میشود.
متدهای کمکی
hasHook
php
Hook::hasHook(string $hookName): bool
بررسی میکند که آیا هوک مشخص شده دارای callback ثبت شده است یا خیر.
removeHook
php
Hook::removeHook(string $hookName, callable $callback, int $priority = 10): void
یک callback خاص را از هوک حذف میکند.
clearHook
php
Hook::clearHook(string $hookName): void
همه callbackهای یک هوک را پاک میکند.
لیست هوکهای سیستمی
هوکهای سرویسدهندگان
| هوک | نوع | توضیح |
|---|---|---|
service_providers/payment | فیلتر | ثبت درگاههای پرداخت |
service_providers/shipping | فیلتر | ثبت سرویسهای حمل و نقل |
payment/gateways | فیلتر | تعریف درگاههای پرداخت (key, send, receive) |
payment/gateway/load | اکشن | بارگذاری کلاس درگاه پرداخت |
forms/payment/pre_verify | فیلتر | پیشتایید پرداخت فرم |
forms/payment/default_gateway | فیلتر | درگاه پیشفرض فرم |
هوکهای داشبورد
| هوک | نوع | توضیح |
|---|---|---|
admin/dashboard/widgets/snapshot | اکشن | ویجتهای خلاصه داشبورد |
admin/dashboard/widgets/insights-secondary | اکشن | ویجتهای ثانویه داشبورد |
admin/navbar/leftBtn:before | اکشن | دکمه قبل از نوار بالای ادمین |
هوکهای مسیریابی و URL
| هوک | نوع | توضیح |
|---|---|---|
analyze_url/result | فیلتر | تغییر نتیجه تحلیل URL |
analyze_url/seo_resolution | فیلتر | تفکیک SEO در مسیریابی مدرن |
routing_handle_folder | فیلتر | مدیریت مسیر پوشهها |
routing_resolve_resource | اکشن | تفکیک نوع منبع مسیریابی |
alvand/preprocess_uri | فیلتر | پیشپردازش URI قبل از مسیریابی |
alvand/site_url | فیلتر | تغییر URL سایت |
هوکهای قالب
| هوک | نوع | توضیح |
|---|---|---|
theme/footer | اکشن | تزریق کد در فوتر قالب |
frontend/footer | اکشن | تزریق کد در فوتر فرانتاند |
frontend/footer:after | اکشن | تزریق کد پس از فوتر |
header_template/meta_tags | فیلتر | تغییر متا تگهای <head> |
header_template/schema | فیلتر | تغییر اسکیما ژورنال |
header_template/breadcrumb_schema | فیلتر | تغییر اسکیما مسیر راهنما |
header_template/lines | فیلتر | تغییر خطوط هدر |
header_template/html | فیلتر | تغییر HTML کامل هدر |
header_template/rendered | اکشن | پس از رندر هدر |
هوکهای مدیریت
| هوک | نوع | توضیح |
|---|---|---|
admin/menu/items | فیلتر | افزودن آیتم به منوی ادمین |
ajax_handle_befor_end | اکشن | قبل از پایان پاسخ AJAX |
ajax_handle_form | اکشن | پردازش فرم AJAX |
admin/footer/before | اکشن | قبل از فوتر ادمین |
هوکهای کش
| هوک | نوع | توضیح |
|---|---|---|
cache/fragment | فیلتر | کش بخشی از صفحه |
cache/plugin/loaded | اکشن | پس از بارگذاری پلاگین کش |
هوکهای محتوا
| هوک | نوع | توضیح |
|---|---|---|
ProductUpdated | اکشن | پس از بروزرسانی محصول |
SettingsChanged | اکشن | پس از تغییر تنظیمات |
cron/hourly | اکشن | کرون ساعتی |
cron/daily | اکشن | کرون روزانه |
هوکهای Sitemap
| هوک | نوع | توضیح |
|---|---|---|
sitemap/index_sections | فیلتر | تغییر بخشهای ایندکس |
sitemap/table_rows | فیلتر | تغییر ردیفهای جدول |
sitemap/url_xml | فیلتر | تغییر خروجی XML |
نمونههای واقعی
ثبت درگاه پرداخت زرینپال
php
// plugins/zarinpal/index.php
// ثبت در سرویس payment
Hook::addFilter('service_providers/payment', static function (array $providers): array {
$providers[] = [
'key' => 'zarinpal',
'name' => 'زرینپال',
'type' => 'payment',
];
return $providers;
});
// تعریف درگاه
Hook::addFilter('payment/gateways', static function (array $gateways): array {
$gateways['zarinpal'] = [
'key' => 'zarinpal',
'send' => 'process_SEND_request_payment_zarinpal',
'receive' => 'process_RECEIVE_request_payment_zarinpal',
];
return $gateways;
});
// بارگذاری کلاس درگاه
Hook::addAction('payment/gateway/load', static function (string $gatewayKey): void {
if ($gatewayKey === 'zarinpal') {
zarinpal_plugin_require_class();
}
});
ویجت داشبورد سئو
php
// plugins/seo/index.php
Hook::addAction('admin/dashboard/widgets/snapshot', static function (): void {
// رندر کارت خلاصه وضعیت سئو
echo '
<div class="col-sm-6 col-lg-3">
<div class="card">
<div class="card-body">
<h6>امتیاز سئو</h6>
<div class="progress">...</div>
</div>
</div>
</div>';
});
پیشوند زبانی در URL (multilang)
php
// plugins/multilang/defines/hooks.php
// حذف پیشوند زبان از URI قبل از مسیریابی
Hook::addFilter('alvand/preprocess_uri', static function (string $uri): string {
$langs = ['fa', 'en', 'ar'];
$parts = explode('/', trim($uri, '/'));
if (in_array($parts[0] ?? '', $langs)) {
array_shift($parts);
}
return '/' . implode('/', $parts);
}, 1);
// افزودن پیشوند زبان به URL
Hook::addFilter('alvand/site_url', static function (string $url): string {
$lang = $_SESSION['alvand_lang'] ?? 'fa';
if ($lang !== 'fa') {
return rtrim($url, '/') . '/' . $lang;
}
return $url;
}, 1);
منوی ادمین (basalam)
php
// plugins/basalam/index.php
Hook::addFilter('admin/menu/items', static function (array $items): array {
$items[] = [
'id' => 'basalam',
'title' => 'باسلام',
'icon' => 'ti ti-brand-shopee',
'url' => '/admin/plugins/basalam/dashboard',
];
return $items;
});
خلاصه متدها
| متد | ورودی | خروجی | توضیح |
|---|---|---|---|
addAction | (hookName, callback, priority) | void | ثبت اکشن |
doAction | (hookName, ...params) | void | اجرای اکشنها |
addFilter | (hookName, callback, priority) | void | ثبت فیلتر |
applyFilters | (hookName, value, ...params) | mixed | اعمال فیلترها |
hasHook | (hookName) | bool | بررسی وجود هوک |
removeHook | (hookName, callback, priority) | void | حذف یک callback |
clearHook | (hookName) | void | پاکسازی همه |
نکات مهم
- همه callbackها با
call_user_func_arrayفراخوانی میشوند - اولویت پیشفرض: 10
- callbackهای پلاگینهای غیرفعال به صورت خودکار نادیده گرفته میشوند (با Reflection)
- فیلترها همیشه باید مقدار دریافتی را برگردانند
- اکشنها مقدار بازگشتی ندارند