داکیومنت رسمی الوند داکیومنت رسمی الوند
سیستم هوک

سیستم هوک

با استفاده از این پلتفرم می توانید با نحوه کد نویسی سیستم مدیریت محتوا الوند آشنا شوید.

پیشرفته نویسنده: تیم الوند به‌روزرسانی: 1405/02/22

سیستم هوک الوند یک معماری رویدادمحور (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پاکسازی همه

نکات مهم

    1. همه callbackها با call_user_func_array فراخوانی می‌شوند
    1. اولویت پیش‌فرض: 10
    1. callbackهای پلاگین‌های غیرفعال به صورت خودکار نادیده گرفته می‌شوند (با Reflection)
    1. فیلترها همیشه باید مقدار دریافتی را برگردانند
    1. اکشن‌ها مقدار بازگشتی ندارند

3 رأی
داکیومنت رسمی الوند
© تمامی حقوق برای شرکت دیجیتال نگاران ایرانیان. کلیه حقوق محفوظ است.