اولین باری که سعی کردم یک تابع وردپرس را تغییر دهم، سراغ فایل هسته رفتم و خطی در آن تغییر دادم. سایت دو هفته بعد آپدیت شد و همهٔ تغییراتم در یک چشم به هم زدن رفت. آن روز فهمیدم که اگر قرار است کدی در وردپرس بنویسم که عمر کند، باید زبان مادری این سیستم را یاد بگیرم: hook (هوک). در این آموزش، از سطح «چیست» شروع می‌کنم، بعد مکانیزم داخلی را باز می‌کنم و در انتها به الگوهای حرفه‌ای و اشتباهات پرهزینه می‌رسم — همان مسیری که خودم روی صدها افزونه و قالب پیموده‌ام.

هوک چیست و چرا وردپرس بدون آن کار نمی‌کند؟

هوک یک نقطهٔ اتصال در جریان اجرای کد است که هستهٔ وردپرس عمداً در آن ناحیه یک «رابط عمومی» باز کرده تا افزونه‌ها و قالب‌ها بتوانند بدون دست‌زدن به هسته، رفتار سایت را تغییر دهند. اگر بخواهیم هوک را در یک جمله توصیف کنیم: هوک، قراردادِ رسمی بین وردپرس و کد شماست برای تغییر رفتار، بدون ویرایش هسته. این قرارداد، دلیل اصلی این است که می‌توانید وردپرس و همهٔ افزونه‌هایتان را آزادانه آپدیت کنید و کد شما همچنان کار کند. اگر درک کلی شما از وردپرس ضعیف است، پیش از این مقاله، وردپرس چیست و چگونه شروع به کار با آن کنیم را بخوانید و بعد ادامه دهید.

هوک، همان چیزی است که به وردپرس اجازه می‌دهد هم رایگان بماند و هم قابل توسعه — بدون آن، هر پروژه یک شاخه از هستهٔ اختصاصی می‌شد.

تفاوت اکشن و فیلتر

هوک‌ها دو دستهٔ اصلی دارند: Action (اکشن) و Filter (فیلتر). اکشن زمانی اجرا می‌شود که وردپرس می‌خواهد بگوید «یک رخداد دارد اتفاق می‌افتد، اگر کسی کارِ اضافه‌ای می‌خواهد بکند حالا وقتش است»؛ مثل لحظه‌ای که یک نوشته منتشر می‌شود (publish_post) یا یک کاربر وارد می‌شود (wp_login). فیلتر اما زمانی اجرا می‌شود که وردپرس یک مقدار دارد و می‌خواهد بگوید «اگر کسی می‌خواهد این مقدار را تغییر دهد، اجازه دارد» — مثل تغییر متن یک نوشته قبل از نمایش (the_content) یا تغییر قیمت یک محصول ووکامرس.

تفاوت بنیادی این دو را در تابع برگشتی می‌توان دید: اکشن return ندارد، فیلتر باید مقدار گرفته‌شده را (به‌احتمال تغییر) بازگرداند. اگر این تفاوت را نمی‌دانید و در فیلتر return نمی‌کنید، سایت‌تان به‌طرز نامحسوسی بخشی از محتوا یا داده را از دست می‌دهد. تحلیل تفصیلی این دو را در تفاوت Action و Filter در وردپرس چیست باز کرده‌ام و اگر به لایهٔ عمیق‌تر علاقه‌مند هستید، مقالهٔ مهم‌ترین Action Hook های وردپرس فهرست کاربردی‌شان را نشان می‌دهد.

آناتومی add_action و add_filter

پایهٔ همه‌چیز در دو تابع است: add_action() و add_filter(). هر دو چهار پارامتر می‌گیرند که سه‌تای اول همیشه و چهارمی اختیاری است.

add_action( 'init', 'my_custom_function', 10, 1 );
add_filter( 'the_content', 'my_content_modifier', 20, 2 );

پارامتر اول، نام هوک است؛ پارامتر دوم، نام تابعی که می‌خواهید اجرا شود؛ پارامتر سوم، priority است؛ و پارامتر چهارم تعداد آرگومان‌هایی است که می‌خواهید از وردپرس دریافت کنید. اگر به‌عنوان مثال در فیلتر the_content بخواهید فقط متن محتوا را بگیرید، پارامتر چهارم را 1 بگذارید؛ اگر بخواهید هم محتوا و هم تنظیمات را بگیرید، 2. یک اشتباه کلاسیک مبتدی‌ها: تعریف تابع با دو پارامتر و فراموش کردن عدد آخر، که باعث می‌شود پارامتر دوم همیشه null باشد.

Priority، پارامترها و ترتیب اجرا

در وردپرس، همهٔ توابعی که به یک هوک متصل شده‌اند، به‌ترتیب عدد priority اجرا می‌شوند. عدد پیش‌فرض ۱۰ است و بازهٔ معمول بین ۱ تا ۱۰۰. اگر کد شما نیاز دارد پیش از تابعی که افزونهٔ دیگری روی همان هوک وصل کرده اجرا شود، عدد کوچک‌تری مثل ۵ انتخاب کنید؛ اگر باید بعد از آن اجرا شود، عدد بزرگ‌تری مثل ۲۰. این عدد، تنها کنترل‌کنندهٔ ترتیب است و هیچ راه دیگری برای مرتب‌سازی هوک‌ها وجود ندارد.

یکی از کاربردهای مهم priority در قالب‌های حرفه‌ای است: مثلاً افزودن استایل‌شیت قالب فرزند باید بعد از استایل والد انجام شود تا اولویت داشته باشد — که در قالب وردپرس چایلد چیست و چه زمانی به آن نیاز داریم با یک مثال کامل نشانش داده‌ام. بدون تسلط بر priority، ترتیب اجرای CSS و JS دائم بهم می‌ریزد و ظاهر سایت ناپایدار می‌ماند.

حذف هوک و کِی باید مراقب باشیم

همان‌قدر که اتصال به هوک مهم است، جدا کردن آن هم کاربرد دارد. دو تابع remove_action() و remove_filter() دقیقاً همان پارامترهای اضافه‌کننده را می‌گیرند و برای اینکه کار کنند باید سه چیز دقیقاً مطابق باشند: نام هوک، نام تابع، و priority. اگر priority درست نباشد، حذف انجام نمی‌شود و خطایی هم دیده نمی‌شود — این یکی از بی‌صدا‌ترین باگ‌های وردپرس است. نکتهٔ حیاتی دیگر، زمان اجرای حذف است: باید پس از اتصال افزونه به آن هوک اجرا شود. یک راه‌حل رایج، اجرای حذف روی هوک init با priority بزرگ‌تر است.

روش کامل و مثال‌های واقعی را در نحوه حذف یک Action Hook در وردپرس و حذف Filter Hook نوشته‌ام. اگر جایی گیر کردید و حس کردید حذف نمی‌شود، معمولاً مقصر یک priority نادرست است.

ساخت هوک سفارشی برای افزونه‌های خودتان

هوک‌ها فقط از آنِ هستهٔ وردپرس نیستند. اگر افزونه‌ای می‌نویسید که احتمالاً دیگران هم می‌خواهند سفارشی‌سازی‌اش کنند، باید برای افزونهٔ خودتان هوک تعریف کنید. دو تابع کافی است: do_action( 'my_plugin_after_save' , $order_id ) در جایی که می‌خواهید یک رخداد عمومی اعلام کنید، و apply_filters( 'my_plugin_price', $price ) هر جا که می‌خواهید مقدار قابل تغییر باشد. ساختار استاندارد افزونه با نقاط هوک، در ساختار فایل‌های یک افزونه استاندارد وردپرس و مسیر کامل ساخت را در راهنمای توسعه افزونه وردپرس از صفر نوشته‌ام. یک عادت حرفه‌ای که روی پروژه‌های خودم اجرا می‌کنم: هر افزونهٔ اختصاصی، حداقل یک هوک عمومی برای رخداد اصلی خودش داشته باشد؛ حتی اگر در آن پروژه هرگز استفاده نشود، آماده‌سازیِ توسعهٔ آینده است.

جدول هوک‌های پرکاربرد و جای درست‌شان

هوکنوعکاربرد رایجpriority توصیه‌شده
initاکشنثبت نوع‌نوشته، ثبت shrtcode، آغاز افزونه10
wp_enqueue_scriptsاکشنافزودن CSS/JS در فرانت‌اند10
the_contentفیلترتغییر خروجی محتوا قبل از نمایش10 تا 20
save_postاکشنذخیره متادیتا همراه نوشته20
wp_loginاکشنثبت رخداد ورود کاربران10
woocommerce_thankyouاکشنپس از ثبت موفق سفارش10

اشتباهات رایج توسعه‌دهندگان با هوک‌ها

  • نادیده‌گرفتن did_action(): وقتی می‌خواهید مطمئن شوید یک رخداد قبلاً اجرا شده، نبود این بررسی باعث می‌شود برخی کدها دو بار اجرا شوند.
  • اتصال به هوک‌های خیلی خاص به‌جای هوک‌های عمومی: مثلاً به‌جای اتصال به wp_loaded، به یک هوک داخلی قالب وصل شدن؛ این کد با هر تغییر قالب می‌شکند.
  • تعریف تابع بدون پیشوند یکتا: در محیطی که چند افزونه فعال است، تابعی به نام custom_setup() ممکن است با تابعی از افزونهٔ دیگر تصادم کند و خطای Cannot redeclare function بدهد.
  • نبود کامنت برای priority غیرمعمول: اگر مقدار priority از ۱۰ فاصله دارد، دلیلش را در همان خط کامنت کنید تا در بازبینی کد، همکار شما بفهمد چرا.
  • اجرای منطق سنگین در هوک‌های پرتکرار: مثل init یا wp_loaded. این نوع کدها ممکن است در پیشخوان هم اجرا شوند و سرعت را کاهش دهند — تحلیلی مرتبط در افزونه‌های وردپرس چطور روی سرعت سایت اثر می‌گذارند.

دیباگ و رهگیری هوک‌ها

وقتی نمی‌دانید چه کسی یا چه چیزی یک هوک خاص را تغییر داده، دو ابزار کار شما را راه می‌اندازند. اول، افزونهٔ Query Monitor که در پنل خودش فهرست همهٔ هوک‌های اجراشده و توابع متصل به آن‌ها را نشان می‌دهد؛ دوم، یک الگوی دستی که خودم زیاد به‌کار می‌برم: روی یک هوک موقتی، با priority بسیار بزرگ (مثلاً ۹۹۹) یک تابع کمکی وصل کنید که مقدار فعلی پارامترها را در error_log بنویسد. به این ترتیب می‌بینید ترتیب واقعی اجرا چگونه است و کدام افزونه آخرین اثر را گذاشته. اگر موضوع به یک خطای مشخص تبدیل شد، مقالهٔ پیدا کردن افزونه مشکل‌ساز وردپرس روش گام‌به‌گام ایزوله‌سازی را دارد.

از دید توسعه‌دهنده ارشد: هوک به‌عنوان لایهٔ عمومی‌سازی

در معماری نرم‌افزار، الگوی hook چیزی جز پیاده‌سازی سبک‌وزنی از Observer Pattern (الگوی ناظر) نیست. هسته به‌جای اینکه در زمان نوشتن، کد مصرف‌کننده را بشناسد، نقاط رخداد را اعلام می‌کند و هر شنونده‌ای می‌تواند مستقل به آن وصل شود. این طراحی، دو خاصیت مهم می‌دهد: جداسازی بین هسته و توسعه‌دهنده، و ترکیب‌پذیری رخدادها در زمان اجرا. اما این آزادی، بهایی هم دارد — کلاس داخلی WP_Hook که مدیریت لیست توابع را بر عهده دارد، در سایت‌های بسیار بزرگ با هزاران اتصال هوک می‌تواند به گلوگاه تبدیل شود. به همین دلیل است که در افزونه‌های حرفه‌ای، اتصال به هوک‌ها معمولاً مشروط به شرایطی است (فقط در فرانت، فقط در پیشخوان، فقط برای نوع‌نوشتهٔ خاص)، نه همه‌جا و بی‌قید.

اگر می‌خواهید این لایه را در معماری کلان سایت‌تان ببینید، مقالات ساختار هسته وردپرس چگونه کار می‌کند و نحوه استفاده صحیح از هوک‌های وردپرس مکمل این آموزش هستند. یک عادت حرفه‌ای که در تیم‌های توسعه توصیه می‌کنم: قبل از شروع هر افزونه، فهرست هوک‌هایی را که استفاده می‌کنید در یک فایل مستند کنید و ماهی یک بار بازبینی کنید؛ نیمی از مشکلات کارایی افزونه‌های قدیمی، از هوک‌های فراموش‌شده‌ای می‌آید که سال‌ها پیش به‌دلیل یک نیاز کوچک اضافه شده و حالا در هر بازدید سایت اجرا می‌شوند. اگر شما هم تجربه‌ای از یک هوک داشته‌اید که ساعت‌ها عیب‌یابی را نجات داده یا برعکس، پنهان‌کاری کرده، بنویسید — همان جزئیات برای توسعه‌دهنده‌ٔ بعدی ارزش زیادی دارند. 🎣