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

چرا توسعه‌پذیری مهم‌تر از قابلیت است

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

سه دلیل که باعث می‌شود توسعه‌پذیری را مهم‌تر از قابلیت بدانم:

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

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

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

افزونهٔ حرفه‌ای، فقط قابلیت نمی‌فروشد؛ مکانیزم توسعهٔ قابلیت هم می‌فروشد. تفاوت این دو، در روز اول دیده نمی‌شود، ولی در ماه ششم، همه‌چیز را عوض می‌کند.

سه لایهٔ ساخت قابلیت با هوک‌ها

در ساخت قابلیت اختصاصی با هوک‌ها، سه لایه وجود دارد که هرکدام نقش متفاوتی دارند. تفکیک این سه، اولین قدم در طراحی حرفه‌ای است:

لایهٔ اول: هوک‌های وردپرس به‌عنوان نقطهٔ اتصال

لایهٔ اول، هوک‌های داخلی وردپرس و افزونه‌های دیگر است که به شما اجازه می‌دهد قابلیت خودتان را به سیستم موجود اضافه کنید. این‌جا شما مصرف‌کنندهٔ هوک هستید، نه تعریف‌کننده‌اش. مثال: اتصال به init برای ثبت نوع نوشتهٔ سفارشی، یا اتصال به the_content برای تزریق محتوا. فهرست پرکاربردترین‌های این لایه در مهم‌ترین Action Hook های وردپرس و مهم‌ترین Filter Hook های وردپرس آمده است.

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

لایهٔ دوم، هوک‌هایی است که خودتان در افزونه یا قالب تعریف می‌کنید تا دیگران بتوانند قابلیت شما را گسترش دهند. این‌جا شما تعریف‌کنندهٔ قرارداد هستید. مثال: افزونهٔ امتیاز وفاداری شما یک Action به نام wphk_loyalty_points_awarded تعریف می‌کند تا افزونه‌های دیگر بتوانند پس از اعطای امتیاز، اقدام دلخواه انجام دهند. این لایه، همان‌جاست که توسعه‌پذیری واقعی متولد می‌شود.

لایهٔ سوم: الگوهای معماری برای هوک‌های سفارشی

لایهٔ سوم، ساختارهایی است که به هوک‌های سفارشی سازمان می‌دهد: تعریف hook handlerها در کلاس‌ها، جداسازی منطق از نمایش، و مستندسازی سیستماتیک. این لایه، تفاوت بین افزونه‌ای با پنج هوک سفارشی پراکنده و افزونه‌ای با ده‌ها هوک سفارشی منظم و قابل نگهداری را می‌سازد. توضیح دقیق این الگوها در راهنمای حرفه‌ای کار با هوک‌های وردپرس آمده است.

در ادامه، هر لایه را با نمونه‌های عملی مرور می‌کنیم، ولی تمرکز اصلی روی لایهٔ دوم و سوم است؛ چون این دو هستند که «قابلیت اختصاصی» شما را از یک کد بسته به یک پلتفرم قابل‌توسعه تبدیل می‌کنند.

تعریف Action سفارشی در افزونهٔ خودتان

اولین ابزار در ساخت قابلیت اختصاصی، تعریف Action سفارشی است. سه کاربرد عمده برای Action سفارشی وجود دارد: اطلاع‌رسانی رویداد، اجازهٔ مداخله در فرایند، و اتصال به سیستم‌های بیرونی. نمونهٔ زیر، ساختار کلی یک Action سفارشی در افزونه را نشان می‌دهد:

/**
 * بعد از اعطای امتیاز وفاداری به کاربر اجرا می‌شود.
 *
 * @since 1.0.0
 *
 * @param int   $user_id      شناسهٔ کاربر
 * @param int   $points       مقدار امتیاز اعطاشده
 * @param array $context      زمینهٔ اعطای امتیاز
 */
do_action( 'wphk_loyalty_points_awarded', $user_id, $points, $context );

سه نکتهٔ کلیدی در همین قطعهٔ کوچک. اول، مستندسازی: در docblock، نام، نوع و معنی هر پارامتر آمده است؛ این مستندسازی، خودش نیمی از ارزش هوک سفارشی است. دوم، انتخاب نام با پیشوند اختصاصی: wphk_ در ابتدای نام هوک، احتمال تعارض با هوک‌های افزونه‌های دیگر را به حداقل می‌رساند. سوم، ترتیب پارامترها بر اساس اهمیت: $user_id، سپس $points، و در آخر $context. این ترتیب، بخشی از قرارداد عمومی هوک است و در نسخه‌های بعدی نباید تغییر کند.

نحوهٔ استفادهٔ توسعه‌دهنده‌های دیگر از این Action، ساده است:

add_action( 'wphk_loyalty_points_awarded', 'my_custom_thank_you', 10, 3 );

function my_custom_thank_you( $user_id, $points, $context ) {
    // ارسال پیام تشکر به کاربر یا همگام‌سازی با CRM
}

الگوهای بیشتری از تعریف Action سفارشی، در چگونه یک Action سفارشی در وردپرس بسازیم آمده است. یک تصمیم ظریف که در پروژه‌های خودم زیاد به‌کار می‌برم: در ابتدای Action سفارشی، شرطی می‌گذارم که در صورت نبود مصرف‌کننده، حتی فراخوانی do_action را هم رد کند. این شرط کوچک، در سایت‌های پربازدید، سرعت قابل توجهی می‌سازد:

if ( has_action( 'wphk_loyalty_points_awarded' ) ) {
    do_action( 'wphk_loyalty_points_awarded', $user_id, $points, $context );
}

تابع has_action، هزینه‌ای نزدیک به صفر دارد، ولی از فراخوانی بدون مصرف‌کننده جلوگیری می‌کند. در افزونه‌هایی که ده‌ها هوک سفارشی دارند، این الگو، تفاوت واقعی در بار سرور می‌سازد.

تعریف Filter سفارشی برای سفارشی‌سازی داده‌ها

دومین ابزار، Filter سفارشی است. Filter، به توسعه‌دهنده‌های بعدی اجازه می‌دهد دادهٔ خروجی یا ورودی افزونهٔ شما را سفارشی کنند. سه کاربرد عمده: تغییر مقدار پیش‌فرض تنظیمات، سفارشی‌سازی خروجی HTML، و اصلاح داده پیش از ذخیره در دیتابیس. نمونهٔ زیر، ساختار یک Filter سفارشی برای سفارشی‌سازی فهرست امتیازات اعطایی را نشان می‌دهد:

$default_points = 10;

/**
 * فیلتر مقدار امتیاز پیش‌فرض هنگام اعطا.
 *
 * @since 1.0.0
 *
 * @param int   $points   مقدار پیش‌فرض امتیاز
 * @param int   $user_id  شناسهٔ کاربر
 * @param array $context  زمینهٔ اعطای امتیاز
 */
$points = apply_filters( 'wphk_loyalty_default_points', $default_points, $user_id, $context );

و توسعه‌دهندهٔ بعدی می‌تواند مقدار پیش‌فرض را براساس شرایط خودش تغییر دهد:

add_filter( 'wphk_loyalty_default_points', 'my_custom_points', 10, 3 );

function my_custom_points( $points, $user_id, $context ) {
    if ( isset( $context['campaign'] ) && 'summer' === $context['campaign'] ) {
        return $points * 2;
    }
    return $points;
}

سه درس عملی از این نمونه. اول، همیشه مقدار پارامتر اول را بازگردانید؛ حتی در شرایطی که تغییر نمی‌دهید. این قاعده، تفاوت بین افزونه‌ای که «کار می‌کند» و افزونه‌ای که «محتوای سایت را ناپدید می‌کند» است. دوم، پارامترهای زمینه‌ای ($context) را در اختیار مصرف‌کننده بگذارید؛ این پارامتر، به توسعه‌دهندهٔ بعدی اجازه می‌دهد شرایط سفارشی را در نظر بگیرد. سوم، در docblock مشخص کنید که این Filter در چه شرایطی اجرا می‌شود. الگوهای بیشتر در چگونه یک Filter سفارشی در وردپرس بسازیم آمده است.

Action سفارشی، فرصت مداخله در «اتفاق» می‌دهد؛ Filter سفارشی، فرصت مداخله در «داده». تفکیک این دو، تفاوت بین یک افزونهٔ معمولی و یک افزونهٔ حرفه‌ای است.

قرارداد توسعه‌پذیری: نام، پارامترها، مستندسازی

هر هوک سفارشی، در واقع یک قرارداد با توسعه‌دهنده‌های آینده است. اگر این قرارداد به‌درستی طراحی شود، افزونهٔ شما سال‌ها قابل‌توسعه باقی می‌ماند. اگر نه، به یک راز تبدیل می‌شود که فقط سازندهٔ اولیه می‌فهمد. سه جزء اصلی این قرارداد:

جزء اول: نام هوک

نام هوک، اولین چیزی است که توسعه‌دهندهٔ بعدی می‌بیند و باید به‌تنهایی گویا باشد. الگوهای پیشنهادی:

  • پیشوند اختصاصی: wphk_، myplugin_ یا مشابهش. بدون پیشوند، احتمال تعارض با افزونه‌های دیگر جدی است.
  • توصیف دقیق عمل: wphk_loyalty_points_awarded بهتر از wphk_event است، چون خود نام می‌گوید چه اتفاقی افتاده.
  • زمان در نام: اگر هوک پیش از یک اقدام یا بعد از آن اجرا می‌شود، در نام مشخص کنید: wphk_before_order_save، wphk_after_order_save.
  • پرهیز از اختصارات: wphk_loyalty_points_awarded بهتر از wphk_lpa است، چون توسعه‌دهندهٔ بعدی بدون مراجعه به مستندات، منظور را می‌فهمد.

جزء دوم: امضای پارامترها

ترتیب، تعداد و نوع پارامترها، بخشی از قرارداد است. تصمیم‌های کلیدی در طراحی این بخش:

  • حداقل تعداد لازم: هر پارامتر اضافه، بار حافظه و پیچیدگی را بالا می‌برد. اگر می‌توانید بدون پارامتری کار کنید، بدون آن طراحی کنید.
  • ترتیب معنادار: مهم‌ترین داده در ابتدا؛ داده‌های زمینه‌ای در ادامه.
  • نوع پایدار: اگر پارامتر اول در نسخهٔ فعلی عدد است، در نسخه‌های بعدی هم باید عدد بماند. تغییر نوع، کدهای مصرف‌کننده را می‌شکند.
  • اختیاری بودن پارامترهای زمینه: پارامترهای اضافه‌تر، اگر معنای کاملی ندارند، می‌توانند به‌عنوان آرایهٔ $context تجمیع شوند.

جزء سوم: مستندسازی

هر هوک سفارشی باید با docblock همراه باشد. سه نکتهٔ اصلی که در این مستندات باید بیاید: @since برای نسخه‌ای که هوک اضافه شده؛ @param برای هر پارامتر با نوع و معنی؛ و توضیح کوتاهی که چه زمان اجرا می‌شود. نمونه:

/**
 * بعد از اعطای امتیاز وفاداری به کاربر اجرا می‌شود.
 *
 * @since 1.0.0
 *
 * @param int   $user_id   شناسهٔ کاربر
 * @param int   $points    مقدار امتیاز اعطاشده
 * @param array $context   زمینهٔ اعطا، شامل کلیدهای 'source'، 'campaign' و 'timestamp'
 */
do_action( 'wphk_loyalty_points_awarded', $user_id, $points, $context );

مستندسازی، وقت‌گیر به‌نظر می‌رسد ولی در عمل، بارها و بارها ارزشش را نشان می‌دهد. تجربهٔ من می‌گوید افزونه‌هایی که هوک‌هایشان مستند نبوده، در بازهٔ ۶ تا ۱۲ ماه، یا رها شده‌اند یا توسط کسی بازنویسی شده‌اند؛ چون هیچ‌کس نمی‌توانسته با اطمینان روی آن‌ها توسعه بدهد. برای مطالعهٔ این الگو در سطح سازمانی، هوک‌های وردپرس در توسعه افزونه چه کاربردی دارند مرجع کامل‌تری است.

الگوی کلاس‌محور برای هوک‌های سفارشی در پروژه‌های بزرگ

در پروژه‌هایی که ده‌ها هوک سفارشی دارند، تعریف همه‌چیز به‌صورت توابع مستقل، به‌سرعت غیرقابل نگهداری می‌شود. الگوی کلاس‌محور، این مشکل را حل می‌کند. ایدهٔ اصلی: هر قابلیت، در یک کلاس مستقل تعریف شود که هم هوک سفارشی خودش را ثبت می‌کند و هم hook handlerهای خودش را به آن متصل می‌کند.

namespace WPHKLoyalty;

class Points_Manager {

    public function init() {
        add_action( 'wphk_order_completed', array( $this, 'award_points' ), 10, 2 );
    }

    public function award_points( $order_id, $order ) {
        if ( ! $order instanceof WC_Order ) {
            return;
        }
        $user_id = $order->get_user_id();
        $points  = $this->calculate_points( $order );

        /**
         * پس از اعطای امتیاز وفاداری اجرا می‌شود.
         *
         * @since 1.0.0
         *
         * @param int    $user_id  شناسهٔ کاربر
         * @param int    $points   مقدار امتیاز
         * @param WC_Order $order  شیء سفارش
         */
        do_action( 'wphk_loyalty_points_awarded', $user_id, $points, $order );
    }

    private function calculate_points( $order ) {
        $base = (int) apply_filters( 'wphk_loyalty_base_points', 10, $order );
        return $base;
    }
}

سه مزیت این الگو در پروژه‌های بزرگ. اول، تفکیک مسئولیت: هر کلاس، مسئول یک قابلیت است؛ افزودن قابلیت جدید، فقط یک کلاس جدید می‌خواهد بدون تغییر کلاس‌های قبلی. دوم، قابلیت جایگزینی: اگر توسعه‌دهندهٔ بعدی بخواهد رفتار امتیازدهی را تغییر دهد، می‌تواند کلاس را ارث‌بری کند و متد را بازنویسی کند. سوم، مستندسازی یکپارچه: همهٔ هوک‌های مرتبط با یک قابلیت، در یک فایل و یک کلاس قرار دارند و پیدا کردنشان آسان است.

یک نکتهٔ عملی از تجربهٔ پروژه‌های تیمی: در این الگو، هوک‌های سفارشی را با نام کلاس مرتبط کنید. مثلاً هوک wphk_loyalty_points_awarded، با کلاس Points_Manager در ارتباط است. این انتظام، در بازبینی کد و در مستندسازی، کمک بزرگی است. مرجع تکمیلی این الگو در راهنمای حرفه‌ای کار با هوک‌های وردپرس و چگونه ترتیب اجرای هوک‌ها را مدیریت کنیم آمده است.

ساخت قابلیت اختصاصی در قالب با هوک سفارشی

هوک‌های سفارشی، محدود به افزونه‌ها نیستند؛ در قالب‌ها هم ابزار قدرتمندی هستند. دو کاربرد اصلی:

کاربرد اول: تعریف جای خالی در فایل‌های قالب

در فایل‌های قالب، می‌توانید نقاطی را به‌عنوان «جای خالی» علامت بزنید تا افزونه‌ها یا چایلد تم، محتوا یا قابلیت به آن‌ها اضافه کنند:

<?php
// در header.php قالب
do_action( 'wphk_before_site_logo' );
// کد لوگو
do_action( 'wphk_after_site_logo' );

// در footer.php قالب
do_action( 'wphk_before_footer_widgets' );
// کد ویجت‌های فوتر
do_action( 'wphk_after_footer_widgets' );
?>

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

کاربرد دوم: فیلتر برای سفارشی‌سازی خروجی قالب

علاوه بر Action، Filterهای سفارشی در قالب به شما اجازه می‌دهند داده‌های خروجی را سفارشی کنید:

$columns = apply_filters( 'wphk_footer_columns_count', 4 );

echo '<div class="footer-columns cols-' . (int) $columns . '">';
// رندر ستون‌ها
echo '</div>';

حالا چایلد تم یا افزونه‌ای دیگر می‌تواند تعداد ستون‌های فوتر را تغییر دهد:

add_filter( 'wphk_footer_columns_count', function( $columns ) {
    return 3;
} );

این الگو، به قالب شما انعطاف می‌دهد بدون این‌که نیاز باشد فایل‌های قالب را تغییر دهید. قاعده‌ای که در پروژه‌های خودم رعایت می‌کنم: هر مقدار قابل‌تغییر در قالب، بهتر است به Filter تبدیل شود. سپس چایلد تم می‌تواند بدون دست‌زدن به کد والد، آن را تغییر دهد. اگر با چایلد تم آشنا نیستید، قالب وردپرس چایلد چیست و چه زمانی به آن نیاز داریم تفاوت‌ها را توضیح می‌دهد.

سه سناریوی واقعی که با هوک سفارشی حل شدند

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

پروندهٔ اول: افزونهٔ وفاداری که نتوانست رشد کند

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

پروندهٔ دوم: قالب خبری که با افزونه‌های جانبی سر ناسازگاری داشت

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

پروندهٔ سوم: همگام‌سازی با CRM که نیاز به انعطاف داشت

در یک پروژهٔ فروشگاهی، مشتری می‌خواست پس از تکمیل هر سفارش، اطلاعات به یک CRM ارسال شود. اما این تصمیم، تصمیم همیشگی نبود؛ ممکن بود بعداً مشتری CRM را عوض کند یا همگام‌سازی را کاملاً قطع کند. راه‌حل: به‌جای قرار دادن منطق همگام‌سازی مستقیم در افزونهٔ اصلی، یک Action سفارشی به نام wphk_order_completed_sync تعریف کردیم و منطق همگام‌سازی را در یک فایل جدا نوشتیم که به همان هوک متصل می‌شد. نتیجه: اگر روزی مشتری خواست CRM را عوض کند، فقط فایل همگام‌سازی را تغییر می‌دهیم؛ هستهٔ افزونه دست‌نخورده می‌ماند. این نوع انعطاف، در پروژه‌های صنعتی ارزش زیادی می‌سازد. توضیح جامع‌تر این الگو در اتصال وردپرس به سرویس‌های خارجی با API آمده است.

سه پروندهٔ بالا، تصادفی انتخاب نشده‌اند. در هر سه، مشکل از ابتدا قابل پیش‌بینی بود و با یک تصمیم کوچک در طراحی، به یک فرصت تبدیل شد. ریشهٔ مشترک این سه، تعریف هوک سفارشی با یک قرارداد دقیق بود.

کارایی در هوک‌های سفارشی

هوک‌های سفارشی، ابزار قدرتمندی هستند ولی در صورت استفادهٔ نادرست، می‌توانند به یکی از دلایل کندی سایت تبدیل شوند. سه اصل که در پروژه‌های پربازدید به‌کار می‌برم:

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

همان‌طور که در بحث Action سفارشی گفتیم، استفاده از has_action و has_filter پیش از فراخوانی، از هزینهٔ بی‌مصرف جلوگیری می‌کند:

if ( has_action( 'wphk_loyalty_points_awarded' ) ) {
    do_action( 'wphk_loyalty_points_awarded', $user_id, $points, $context );
}

در سایتی که ده‌ها هوک سفارشی دارد و نیمی از آن‌ها بدون مصرف‌کننده هستند، این الگو می‌تواند صدها میلی‌ثانیه در هر بازدید صرفه‌جویی کند.

اصل دوم: عدم ارسال داده سنگین

پارامترهای هوک سفارشی، بخشی از قرارداد عمومی است؛ ولی این دلیل نمی‌شود که همهٔ داده را در آن‌ها بریزید. اگر داده‌ای سنگین است و فقط در بعضی موارد لازم است، بهتر است یک تابع دسترسی جداگانه ارائه کنید و در هوک فقط شناسه را بگذارید. این تفکیک، هم حافظه را ذخیره می‌کند و هم قرارداد را ساده‌تر نگه می‌دارد.

اصل سوم: تزریق منطق سنگین در هوک دیرهنگام

اگر منطق هوک سفارشی شما سنگین است (کوئری پیچیده، فراخوانی سرویس بیرونی)، بهتر است در هوک دیرهنگام‌تر مثل wp_loaded با اولویت بالا اجرا شود، نه در init یا wp_head. این انتقال کوچک، تجربهٔ کاربر را به‌طور محسوس بهبود می‌دهد. تحلیل این اثر روی شاخص‌های Core Web Vitals در Core Web Vitals چیست و چرا گوگل بر آن تاکید دارد و اثر آن روی مصرف منابع هاست در کاهش مصرف منابع هاست با عدد سنجیده شده است.

اشتباهات رایج در ساخت هوک سفارشی

در بازبینی ده‌ها افزونه و قالب اختصاصی، این شش الگو بیشترین تکرار را داشته‌اند:

اشتباهپیامد واقعیاصلاح
نبود پیشوند اختصاصی در نام هوکتعارض با افزونه‌های دیگرپیشوند یکتا مثل wphk_
تغییر پارامترها پس از انتشارشکستن کدهای مصرف‌کنندهافزودن پارامتر در انتها، عدم تغییر ترتیب قدیمی
نبود مستندسازی @since و @paramعدم امکان توسعه بدون مطالعهٔ منبعdocblock کامل برای هر هوک
فراخوانی do_action بدون بررسی وجود مصرف‌کنندههزینهٔ بی‌دلیل در هر بازدیداستفاده از has_action
ارسال داده سنگین در پارامترهامصرف حافظه بالا، کندیارسال شناسه، دسترسی از طریق تابع
استفاده از نام‌های مبهم بدون پیشوند در کلاس‌هاتعارض namespace در پروژه‌های بزرگاستفاده از namespace یا پیشوند کلاس

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

نگاهی از منظر معماری توسعهٔ نرم‌افزار

ساخت قابلیت اختصاصی با هوک‌های سفارشی، از منظر معماری نرم‌افزار، پیاده‌سازی یک الگوی کلاسیک است: Inversion of Control (IoC) به‌معنای واقعی. در الگوی معمول، شما در کد خودتان تصمیم می‌گیرید چه کاری، کجا و چه زمانی انجام شود. در الگوی هوک‌محور، شما فقط «نقاط مداخله» را اعلام می‌کنید و تصمیم اجرا به سایر بخش‌های سیستم واگذار می‌شود. سه پیامد معماری این تصمیم را در پروژه‌های جدی دیده‌ام:

پیامد اول: کاهش وابستگی بین اجزا. وقتی افزونهٔ A و افزونهٔ B هر دو به یک هوک سفارشی متصل می‌شوند، هیچ‌کدام از دیگری اطلاع مستقیم ندارد. این استقلال، آزمون‌پذیری را بالا می‌برد و اجازه می‌دهد یکی بدون شکستن دیگری آپدیت شود. در معماری نرم‌افزار، این را «کاهش coupling» می‌گویند و از معیارهای کلیدی کیفیت طراحی است.

پیامد دوم: قابلیت تست واحد. هوک‌های سفارشی، امکان جداسازی رفتار از چرخهٔ وردپرس را می‌دهند. این ویژگی، در محیط‌های CI/CD که به تست واحد نیاز دارند، ارزشمندی خودش را نشان می‌دهد. اگر با مسیر ساخت افزونه‌های تست‌پذیر آشنا نیستید، توسعه وردپرس چیست و از کجا شروع کنیم نقطهٔ شروع مناسبی است.

پیامد سوم: ایجاد قرارداد قابل تکامل. برخلاف رابط‌های سخت که تغییرشان همیشه شکستن است، هوک سفارشی می‌تواند به‌آرامی تکامل پیدا کند: پارامترهای جدید در انتها اضافه می‌شوند، هوک‌های تازه برای رفتارهای جدید تعریف می‌شوند، و نسخه‌های قدیمی هم پشتیبانی می‌شوند. این انعطاف، در پروژه‌های با عمر طولانی، ارزش ذخیره‌ای دارد.

در معماری نرم‌افزار، ابزارهایی که «همکاری بدون وابستگی» را ممکن می‌کنند، معمولاً گران‌تر از ابزارهای مستقیم‌اند ولی در بلندمدت، ارزان‌ترین بوده‌اند. هوک سفارشی، دقیقاً چنین ابزاری است.

یک نکتهٔ عملی از تجربهٔ پروژه‌های تیمی: پیش از اینکه هوک سفارشی تعریف کنید، از خودتان بپرسید آیا واقعاً به این نقطهٔ مداخله نیاز است یا می‌توان به‌سادگی از فیلترهای عمومی وردپرس استفاده کرد. هوک سفارشی، زمانی ارزش دارد که یا رفتار خاصی در افزونهٔ شما وجود دارد که در وردپرس معادل ندارد، یا اینکه می‌خواهید یک قرارداد توسعه‌پذیری صریح با توسعه‌دهنده‌های دیگر ببندید. برای تصمیم‌گیری دقیق‌تر، مقایسهٔ هوک‌های عمومی و سفارشی در تفاوت Action و Filter در وردپرس چیست و راهنمای حرفه‌ای کار با هوک‌های وردپرس مفید است.

نقشهٔ پیشنهادی و گام بعدی

ساخت قابلیت اختصاصی با هوک‌های وردپرس، سه لایه دارد: استفاده از هوک‌های موجود، تعریف هوک‌های سفارشی، و سازمان‌دهی آن‌ها در قالب معماری. لایهٔ اول، مهارت پایه است؛ لایهٔ دوم، مهارت حرفه‌ای؛ و لایهٔ سوم، مهارت معماری است که پروژه را در بلندمدت نجات می‌دهد. کلیدهای اصلی: پیشوند اختصاصی در نام هوک، مستندسازی @since و @param، بازگشت سریع در نبود مصرف‌کننده، ارسال حداقل داده در پارامترها، و سازمان‌دهی کلاس‌محور در پروژه‌های بزرگ.

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