در پروژه‌ای که یک سیستم اطلاع‌رسانی پیشرفته را با وردپرس می‌ساختیم، یک توسعه‌دهنده جوان یک فیلتر (Filter) را به‌جای اکشن (Action) استفاده کرده بود و سه روز دنبال این بود که چرا کدش اجرا نمی‌شود. جالب اینجا بود که کد اصلاً خطا نمی‌داد و همین موضوع، تشخیص را سخت‌تر می‌کرد. وقتی پرونده را بررسی کردیم، فهمیدیم که تفاوت بین اکشن و فیلتر، در وردپرس فقط یک تفاوت فنی نیست؛ یک تفاوت فلسفی است که ریشه در معماری هسته دارد. اگر آن سه روز را روی یک صفحه مستندات صرف کرده بود، صد ساعت وقت تیم را نجات داده بود. در این تحلیل، دقیقاً همان تفاوت‌هایی را باز می‌کنم که در پروژه‌های واقعی به آن‌ها برخورده‌ام: از مکانیزم اجرای داخلی و نقش do_action و apply_filters، تا کدهای نمونه، اشتباهات رایج، و کاربردهای پیشرفته در معماری افزونه‌های سازمانی. اگر تازه با مفهوم هوک در وردپرس آشنا شده‌اید، پیشنهاد می‌کنم ابتدا هوک‌های وردپرس: قلب تپنده توسعه را بخوانید تا لایه‌های زیرین این بحث را درک کنید.

هوک چیست و چرا وردپرس آن را ساخت؟

هوک (Hook) یا همان «قلاب» در وردپرس، یکی از بنیادین‌ترین مفاهیم معماری این سیستم است. هوک یک نقطه اتصال در هسته وردپرس است که به توسعه‌دهندگان اجازه می‌دهد بدون دست‌زدن به کد هسته، رفتار وردپرس را تغییر دهند یا داده‌های آن را اصلاح کنند. این مفهوم، در واقع پاسخ وردپرس به یک مسئله معماری بنیادین در نرم‌افزارهای متن‌باز است: چطور می‌توان بدون دست‌زدن به هسته، قابلیت‌های جدید به سیستم اضافه کرد و پس از هر آپدیت هسته، این تغییرات پابرجا بمانند؟ پاسخ، سیستم هوک است که در قلب وردپرس نشسته و پایه اکوسیستم بزرگی از افزونه‌ها و قالب‌ها را فراهم می‌کند. اگر با مفهوم کلی وردپرس آشنا نیستید، پیشنهاد می‌کنم ابتدا وردپرس چیست و چگونه شروع به کار با آن کنیم؟ را بخوانید تا لایه‌های اصلی CMS را بهتر درک کنید.

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

هوک، قراردادی بین هسته وردپرس و توسعه‌دهنده است: هسته می‌گوید «من این‌جا توقف می‌کنم تا تو کدت را اجرا کنی» — و این قرارداد، پایه تمام اکوسیستم افزونه‌ها است.

اکشن در وردپرس: مکانیزم اجرای رفتار در لحظه مشخص

اکشن، یک هوک است که در لحظه مشخصی از اجرای وردپرس فراخوانی می‌شود و به توسعه‌دهنده اجازه می‌دهد در آن لحظه، کدی را اجرا کند. برخلاف فیلتر، اکشن هیچ داده‌ای را تغییر نمی‌دهد و هیچ مقداری را برنمی‌گرداند. هدف اکشن، صرفاً «اجرای یک عمل» در آن لحظه است. مثال‌های رایج اکشن در هسته وردپرس عبارتند از: init که در زمان مقدارگیری وردپرس فراخوانی می‌شود، admin_init که در زمان بارگذاری پیشخوان فراخوانی می‌شود، wp_footer که در انتهای هر صفحه فرانت‌اند فراخوانی می‌شود، و save_post که در زمان ذخیره یک نوشته فراخوانی می‌شود. برای یادگیری نحوه ساخت اکشن سفارشی، چگونه یک Action سفارشی در وردپرس بسازیم راهنمای دقیقی است.

مکانیزم ثبت اکشن در وردپرس، از طریق تابع add_action() انجام می‌شود. این تابع، سه پارامتر اصلی می‌گیرد: نام اکشن، نام تابع callback، و اولویت (priority). سپس در هسته یا کد توسعه‌دهنده، تابع do_action() فراخوانی می‌شود که تمام callbackهای ثبت‌شده برای آن اکشن را به ترتیب اولویت اجرا می‌کند. یک نکته مهم: do_action() هیچ مقداری برنمی‌گرداند — اگر callback شما مقداری را برگرداند، وردپرس آن را نادیده می‌گیرد. این ویژگی، تفاوت بنیادین اکشن با فیلتر را مشخص می‌کند. برای آشنایی با نحوه استفاده صحیح از تابع add_action، نحوه استفاده از add_action در وردپرس را بخوانید.

فیلتر در وردپرس: مکانیزم تغییر داده پیش از خروجی

فیلتر، یک هوک است که به توسعه‌دهنده اجازه می‌دهد یک داده را در مسیر عبورش تغییر دهد و سپس آن داده تغییر‌یافته را برگرداند. برخلاف اکشن که فقط «اجرا می‌شود»، فیلتر «داده می‌گیرد، تغییرش می‌دهد، و برمی‌گرداند». هدف فیلتر، مداخله در داده‌های هسته پیش از خروجی نهایی است. مثال‌های رایج فیلتر در هسته وردپرس عبارتند از: the_content که محتوای نوشته را پیش از نمایش تغییر می‌دهد، the_title که عنوان نوشته را تغییر می‌دهد، wp_mail که ایمیل را قبل از ارسال تغییر می‌دهد، و excerpt_length که طول خلاصه نوشته را تعیین می‌کند. برای یادگیری نحوه ساخت فیلتر سفارشی، چگونه یک Filter سفارشی در وردپرس بسازیم راهنمای دقیقی است.

مکانیزم ثبت فیلتر در وردپرس، از طریق تابع add_filter() انجام می‌شود. این تابع، مشابه add_action()، سه پارامتر اصلی می‌گیرد: نام فیلتر، نام تابع callback، و اولویت. اما تفاوت بنیادین در این است که در فیلتر، تابع callback باید مقداری را برگرداند. اگر callback شما مقداری را برنگرداند، داده اصلی از بین می‌رود و وردپرس مقدار null را به‌عنوان نتیجه استفاده می‌کند. این ویژگی، رایج‌ترین اشتباه توسعه‌دهندگان تازه‌کار در فیلترهاست. برای آشنایی با نحوه استفاده صحیح از تابع add_filter، نحوه استفاده از add_filter در وردپرس را بخوانید.

فیلتر، یک «کارخانه فرآوری» است: داده خام می‌گیرد، آن را تغییر می‌دهد، و نسخه اصلاح‌شده را تحویل می‌دهد — اگر داده برگردانده نشود، کارخانه خالی تحویل می‌دهد.

تفاوت بنیادین: عمل در برابر تغییر داده

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

محوراکشن (Action)فیلتر (Filter)
هدفاجرای عمل در لحظه مشخصتغییر داده پیش از خروجی
مقدار ورودیممکن است هیچ مقداری نگیردحتماً یک یا چند مقدار می‌گیرد
مقدار خروجیهیچ مقداری برنمی‌گرداندحتماً یک مقدار برمی‌گرداند
تابع فراخوان هستهdo_action()apply_filters()
تابع ثبتadd_action()add_filter()
تعداد callback مجازنامحدود (به ترتیب اولویت)نامحدود (به ترتیب اولویت زنجیره‌ای)
کاربرد اصلیافزودن قابلیت، اتصال به رویداداصلاح داده، سفارشی‌سازی خروجی

نکته کلیدی که در این جدول نهفته، تفاوت بین «عمل» و «تغییر داده» است. اکشن، یک عمل انجام می‌دهد — مثل ارسال ایمیل، ذخیره لاگ، یا ریدایرکت کاربر. فیلتر، یک داده را تغییر می‌دهد — مثل اضافه کردن متن به انتهای محتوا، تغییر طول خلاصه، یا اصلاح ساختار آرایه‌ای از اطلاعات. این تفاوت، در معماری افزونه‌های سازمانی اهمیت بنیادین دارد. اگر منطق کسب‌وکار شما «انجام یک عمل» است، اکشن انتخاب درستی است؛ اگر منطق شما «تغییر یک داده» است، فیلتر انتخاب درست است. برای درک عمیق‌تر این تفکیک در معماری افزونه، راهنمای توسعه افزونه وردپرس از صفر نقطه شروع خوبی است.

مکانیزم داخلی: WP_Hook و ساختار داده پشت صحنه

برای درک عمیق تفاوت اکشن و فیلتر، باید معماری داخلی آن‌ها را بشناسید. در نسخه‌های اولیه وردپرس، هوک‌ها در یک آرایه سراسری به‌نام $wp_filter ذخیره می‌شدند. اما از نسخه ۴.۷، وردپرس یک کلاس جدید به‌نام WP_Hook معرفی کرد که مدیریت هوک‌ها را به عهده دارد. این کلاس، هم برای اکشن و هم برای فیلتر استفاده می‌شود — یعنی در سطح فنی، هیچ تفاوتی بین اکشن و فیلتر در ساختار داده وجود ندارد. تفاوت فقط در نحوه فراخوانی و رفتار callbackهای ثبت‌شده است.

کلاس WP_Hook، یک ساختار داده‌ای مبتنی بر آرایه است که callbackها را در دو دسته نگه می‌دارد: callbackهایی که از هوک فعلی حذف شده‌اند و callbackهایی که فعال هستند. هر callback، با یک شناسه یکتا و یک اولویت مشخص ذخیره می‌شود. وقتی یک فیلتر با apply_filters() فراخوانی می‌شود، کلاس WP_Hook به ترتیب اولویت، هر callback را صدا می‌زند و نتیجه هر callback را به‌عنوان ورودی callback بعدی قرار می‌دهد. این مکانیزم، همان چیزی است که در اصطلاح به آن «زنجیره فیلتر» (Filter Chain) می‌گویند. برای یادگیری نحوه استفاده پیشرفته از این کلاس، راهنمای حرفه‌ای کار با هوک‌های وردپرس راهنمای کاملی است.

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

نقش return value در فیلترها: مهم‌ترین تفاوت عملی

مهم‌ترین تفاوت عملی بین اکشن و فیلتر، نقش مقدار بازگشتی (return value) است. در اکشن‌ها، مقدار بازگشتی callback نادیده گرفته می‌شود. اما در فیلترها، مقدار بازگشتی callback، همان نتیجه نهایی فیلتر است. اگر callback شما مقداری را برنگرداند، آن مقدار از زنجیره حذف می‌شود و این می‌تواند به خرابی داده منجر شود. این تفاوت ساده، منبع رایج‌ترین اشتباهات توسعه‌دهندگان تازه‌کار است. کد زیر یک اشتباه رایج را نشان می‌دهد:

// اشتباه: مقدار برگردانده نمی‌شود
add_filter( 'the_content', 'wpkar_wrong_filter' );
function wpkar_wrong_filter( $content ) {
    $content .= '<p>متن اضافه شده</p>';
    // مقدار برگردانده نمی‌شود — نتیجه: null
}

// درست: مقدار برگردانده می‌شود
add_filter( 'the_content', 'wpkar_correct_filter' );
function wpkar_correct_filter( $content ) {
    $content .= '<p>متن اضافه شده</p>';
    return $content; // مقدار برگردانده می‌شود
}

نکته دوم در مورد return value، تفاوت بین زنجیره فیلتر و زنجیره اکشن است. در زنجیره فیلتر، مقدار بازگشتی هر callback، ورودی callback بعدی است. یعنی اگر سه callback به یک فیلتر متصل باشند، مقدار اولیه به callback اول می‌رسد، نتیجه callback اول به callback دوم، نتیجه callback دوم به callback سوم، و نتیجه نهایی به فراخوان اصلی برمی‌گردد. این مکانیزم، امکان زنجیره‌سازی تغییرات را فراهم می‌کند. اما در اکشن‌ها، هیچ زنجیره‌ای وجود ندارد چون هیچ مقداری بین callbackها منتقل نمی‌شود. هر callback اکشن، مستقل از دیگری اجرا می‌شود. این تفاوت، در معماری افزونه‌های سازمانی اهمیت بنیادین دارد — اگر می‌خواهید تغییرات مختلف روی یک داده اعمال شوند، فیلتر انتخاب درستی است؛ اگر می‌خواهید چند عمل مستقل در یک لحظه انجام شوند، اکشن انتخاب درستی است. برای یادگیری الگوهای پیشرفته، ساخت قابلیت اختصاصی با هوک‌های وردپرس راهنمای دقیقی است.

Priority و ترتیب اجرا در اکشن و فیلتر

هم اکشن و هم فیلتر، پارامتری به‌نام «اولویت» (priority) دارند که ترتیب اجرای callbackها را تعیین می‌کند. مقدار پیش‌فرض اولویت، عدد ۱۰ است. callbackهایی که اولویت پایین‌تر دارند، زودتر اجرا می‌شوند — یعنی اولویت ۵ قبل از اولویت ۱۰ اجرا می‌شود. اگر چند callback اولویت یکسانی داشته باشند، به ترتیبی که ثبت شده‌اند اجرا می‌شوند. این مکانیزم، هم در اکشن و هم در فیلتر یکسان است و تفاوت بنیادینی بین آن‌ها وجود ندارد. اما این مکانیزم در پروژه‌های واقعی، اهمیت زیادی دارد. برای درک عمیق این مفهوم، Priority در هوک‌های وردپرس چیست راهنمای جامعی است.

یک نکته مهم که در پروژه‌های سازمانی به آن برخورده‌ام: در فیلترها، ترتیب اولویت اهمیت بیشتری دارد چون تغییرات روی یک داده اعمال می‌شوند و ترتیب اعمال، می‌تواند نتیجه نهایی را تغییر دهد. مثلاً اگر یک فیلتر، یک متن را به بزرگ تبدیل کند و فیلتر دیگر، یک کلمه به آن اضافه کند، نتیجه نهایی بستگی به ترتیب اجرا دارد. در اکشن‌ها، چون callbackها مستقل از هم اجرا می‌شوند، ترتیب اولویت اهمیت کمتری دارد — مگر در مواردی که یکی از callbackها داده‌ای تولید می‌کند که callback بعدی به آن وابسته است. یک تکنیک حرفه‌ای: از اولویت‌های میانی مثل ۵، ۱۵، و ۲۰ به‌جای ۱۰ استفاده کنید تا در آینده اگر نیاز به اضافه کردن callback بین دو callback موجود داشتید، فضای مانور داشته باشید. برای یادگیری استراتژی‌های پیشرفته مدیریت اولویت، چگونه ترتیب اجرای هوک‌ها را مدیریت کنیم را بخوانید.

مثال‌های عملی: کد نوشتن اکشن و فیلتر

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

add_action( 'wp_footer', 'wpkar_add_tracking_code' );
function wpkar_add_tracking_code() {
    if ( ! is_user_logged_in() ) {
        echo '<script>/* کد رهگیری اینجا */</script>';
    }
}

مثال دوم، اضافه کردن اعتباردهی به انتهای هر نوشته. این یک «تغییر داده» است چون محتوای نوشته را تغییر می‌دهد و باید مقدار تغییر‌یافته را برگرداند:

add_filter( 'the_content', 'wpkar_add_footer_to_content' );
function wpkar_add_footer_to_content( $content ) {
    if ( is_singular( 'post' ) ) {
        $content .= '<div class="author-bio">نویسنده: ' . esc_html( get_the_author() ) . '</div>';
    }
    return $content;
}

مثال سوم، محدودسازی طول خلاصه نوشته. این هم یک «تغییر داده» است چون طول خلاصه را تغییر می‌دهد:

add_filter( 'excerpt_length', 'wpkar_custom_excerpt_length', 999 );
function wpkar_custom_excerpt_length( $length ) {
    return 30;
}

حالا به این سه مثال با دقت نگاه کنید. در مثال اول، تابع wpkar_add_tracking_code هیچ مقداری برنمی‌گرداند چون هدفش فقط «اجرای عمل» است. در مثال دوم و سوم، توابع مقدار جدید را return می‌کنند چون هدفشان «تغییر داده» است. اگر در مثال دوم یا سوم، return $content یا return 30 را فراموش کنید، نتیجه به‌ترتیب یک محتوای خالی و یک عدد پیش‌فرض خواهد بود. این تفاوت ساده، تفاوت بنیادین اکشن و فیلتر را نشان می‌دهد. برای یادگیری عمیق‌تر در مورد نحوه استفاده از فیلترها در قالب و افزونه، هوک‌های وردپرس در توسعه قالب چه کاربردی دارند و هوک‌های وردپرس در توسعه افزونه چه کاربردی دارند را بخوانید.

کِی اکشن، کِی فیلتر؟ چارچوب تصمیم‌گیری

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

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

این چارچوب، در عمل بیش از ۹۰٪ موارد را پوشش می‌دهد. یک نکته ظریف که در پروژه‌های سازمانی به آن برخورده‌ام: گاهی یک کاربرد را می‌توان هم با اکشن و هم با فیلتر پیاده کرد، اما یکی از آن‌ها «درست‌تر» است. مثلاً اضافه کردن یک پیام به انتهای محتوا را می‌توانید با اکشن wp_footer پیاده کنید (اگر می‌خواهید در فوتر نمایش داده شود) یا با فیلتر the_content (اگر می‌خواهید داخل محتوای نوشته باشد). انتخاب درست، بستگی به این دارد که «دقیقاً کجا» می‌خواهید پیام نمایش داده شود. اگر در فوتر است، اکشن درست‌تر است چون عملی در لحظه رندر فوتر انجام می‌شود. اگر در محتوا است، فیلتر درست‌تر است چون محتوا تغییر داده می‌شود.

تفاوت اکشن و فیلتر، در نهایت تفاوت بین «چه کاری انجام می‌دهم» و «چه داده‌ای را تغییر می‌دهم» است — پاسخ این پرسش ساده، انتخاب شما را مشخص می‌کند.

اکشن و فیلتر در ووکامرس: مثال واقعی

ووکامرس یکی از بهترین مثال‌ها برای درک تفاوت اکشن و فیلتر است چون در معماری آن، هر دو به‌طور گسترده استفاده می‌شوند. در ووکامرس، اکثر صفحات از قالب‌های PHP تشکیل شده‌اند که شامل اکشن‌های متعددی هستند. مثلاً در صفحه محصول، اکشن woocommerce_before_single_product_summary قبل از خلاصه محصول اجرا می‌شود، اکشن woocommerce_single_product_summary برای نمایش اطلاعات محصول استفاده می‌شود، و اکشن woocommerce_after_single_product_summary بعد از خلاصه محصول اجرا می‌شود. هر یک از این اکشن‌ها، نقاط اتصالی هستند که توسعه‌دهنده می‌تواند کد سفارشی خودش را به آن‌ها متصل کند. برای یادگیری نحوه استفاده از این اکشن‌ها، هوک‌های وردپرس برای ووکامرس راهنمای جامعی است.

فیلترها در ووکامرس هم به‌طور گسترده استفاده می‌شوند. مثلاً فیلتر woocommerce_product_get_price قیمت محصول را قبل از نمایش تغییر می‌دهد، فیلتر woocommerce_cart_item_name نام محصول در سبد خرید را تغییر می‌دهد، و فیلتر woocommerce_checkout_fields فیلدهای تسویه‌حساب را سفارشی‌سازی می‌کند. تفاوت مهم این است که اکشن‌ها «عمل اجرا می‌کنند» — مثل اضافه کردن یک بخش جدید به صفحه محصول — و فیلترها «داده را تغییر می‌دهند» — مثل تغییر قیمت یا متن. اگر می‌خواهید درک عمیق‌تری از سفارشی‌سازی ووکامرس داشته باشید، سفارشی‌سازی صفحه محصول در ووکامرس و سفارشی‌سازی سبد خرید و تسویه‌حساب ووکامرس را بخوانید.

عیب‌یابی: چطور بفهمیم کدام هوک در کار است؟

گاهی در پروژه‌های واقعی، توسعه‌دهنده یک اکشن یا فیلتر را اضافه می‌کند و انتظار دارد کد اجرا شود، اما هیچ اتفاقی نمی‌افتد. عیب‌یابی این مسئله، نیازمند یک رویکرد سیستماتیک است. سه مرحله اصلی در عیب‌یابی هوک‌ها وجود دارد. مرحله اول، بررسی نام هوک. یکی از رایج‌ترین اشتباهات، استفاده از نام اشتباه برای هوک است. مثلاً save_post یک اکشن است اما save_post_data یک فیلتر است؛ اگر این دو را با هم اشتباه کنید، کد شما اجرا نمی‌شود. راه‌حل: همیشه نام دقیق هوک را در مستندات رسمی وردپرس یا مستندات افزونه مربوطه بررسی کنید.

مرحله دوم، بررسی نوع هوک. اگر یک فیلتر را به‌جای اکشن استفاده کنید (یا برعکس)، کد شما ممکن است اجرا شود اما نتیجه ندهد. مثلاً اگر تابعی که قرار است داده را تغییر دهد را با add_action ثبت کنید، تابع اجرا می‌شود اما مقدار بازگشتی نادیده گرفته می‌شود و داده اصلی تغییر نمی‌کند. راه‌حل: همیشه بررسی کنید که هوک موردنظر از نوع اکشن است یا فیلتر. مستندات رسمی وردپرس، همیشه نوع هوک را مشخص می‌کند. مرحله سوم، بررسی اولویت و پارامترها. اگر اولویت شما پایین‌تر یا بالاتر از اولویت‌های موجود است، ممکن است کد شما در زمان اشتباهی اجرا شود. راه‌حل: از ابزارهایی مثل Query Monitor استفاده کنید که تمام هوک‌های اجرا شده در هر صفحه را نشان می‌دهد. برای یادگیری عمیق‌تر این موضوع، دیباگ کردن Action و Filter در وردپرس راهنمای کاملی است. و اگر در حال عیب‌یابی مشکلات رایج هستید، اشتباهات رایج هنگام استفاده از هوک‌ها راهنمای خوبی است.

ده اشتباه رایج در استفاده از اکشن و فیلتر

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

  • اشتباه اول: استفاده از اکشن به‌جای فیلتر. رایج‌ترین اشتباه. اگر تابع شما مقداری را برمی‌گرداند و انتظار دارید داده تغییر کند، باید از فیلتر استفاده کنید نه اکشن.
  • اشتباه دوم: فراموش کردن return در فیلتر. اگر در فیلتر return نداشته باشید، داده اصلی از بین می‌رود. همیشه مقدار جدید را return کنید.
  • اشتباه سوم: استفاده از return در اکشن. return در اکشن بی‌فایده است چون هیچ‌کس مقداری که برمی‌گردانید را نمی‌خواند. از return در اکشن پرهیز کنید.
  • اشتباه چهارم: اولویت نادرست. اگر اولویت شما پایین‌تر از اولویت callbackهای دیگر است، ممکن است کد شما بعد از آن‌ها اجرا شود و انتظار شما برآورده نشود. همیشه اولویت را با دقت انتخاب کنید.
  • اشتباه پنجم: استفاده از تابع بی‌نام در callback. توابع بی‌نام (anonymous function) را نمی‌توان با remove_action یا remove_filter حذف کرد. همیشه از توابع نام‌دار استفاده کنید.
  • اشتباه ششم: عدم تعیین پارامتر چهارم add_filter. اگر callback شما بیش از یک پارامتر می‌گیرد، حتماً پارامتر چهارم را تنظیم کنید وگرنه پارامترهای اضافی نادیده گرفته می‌شوند.
  • اشتباه هفتم: نادیده گرفتن زنجیره فیلتر. اگر callback شما به یک فیلتر متصل است و انتظار دارد داده اصلی را ببیند، اما callbackهای قبلی داده را تغییر داده‌اند، شما داده اصلی را نمی‌بینید. همیشه به ترتیب اولویت توجه کنید.
  • اشتباه هشتم: استفاده از فیلتر برای اجرای عمل. اگر تابع شما فقط می‌خواهد چیزی را چاپ کند یا ایمیل بفرستد، باید از اکشن استفاده کنید. استفاده از فیلتر برای این کار، داده اصلی را به خطر می‌اندازد.
  • اشتباه نهم: نبود تست بعد از اضافه کردن هوک. همیشه بعد از اضافه کردن هوک، صفحه مربوطه را تست کنید تا مطمئن شوید کد اجرا می‌شود و نتیجه درست است.
  • اشتباه دهم: عدم مستندسازی هوک‌های سفارشی. اگر یک هوک سفارشی می‌سازید، حتماً مستندات آن را در کد اضافه کنید تا توسعه‌دهندگان دیگر بدانند این هوک چه کاری انجام می‌دهد و چه پارامترهایی می‌گیرد.

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

تفاوت اصلی بین اکشن و فیلتر در وردپرس چیست؟

تفاوت اصلی این است که اکشن برای «انجام دادن عملی» استفاده می‌شود و هیچ مقداری برنمی‌گرداند، در حالی که فیلتر برای «تغییر دادن داده» استفاده می‌شود و حتماً یک مقدار برمی‌گرداند. در سطح فنی، اکشن‌ها با do_action فراخوانی می‌شوند و فیلترها با apply_filters.

چطور بفهمم یک هوک از نوع اکشن است یا فیلتر؟

سه راه برای تشخیص وجود دارد. اول، مستندات رسمی وردپرس همیشه نوع هوک را مشخص می‌کند. دوم، اگر تابع callback شما مقداری را برمی‌گرداند، هوک از نوع فیلتر است. سوم، نام هوک‌ها معمولاً نشان‌دهنده نوعشان هستند — مثلاً the_content یک فیلتر است چون محتوا را تغییر می‌دهد، و wp_footer یک اکشن است چون کدی را در فوتر اجرا می‌کند.

آیا می‌توانم یک اکشن را به‌جای فیلتر استفاده کنم؟

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

چرا مقدار بازگشتی در فیلترها این‌قدر مهم است؟

چون فیلترها به‌صورت زنجیره‌ای اجرا می‌شوند. مقدار بازگشتی هر callback، ورودی callback بعدی است. اگر callback شما مقداری را برنگرداند، آن مقدار از زنجیره حذف می‌شود و مقدار null جایگزین می‌شود. این می‌تواند به خرابی داده و حتی به خطاهای جبران‌ناپذیر منجر شود.

آیا اولویت در اکشن و فیلتر یکسان است؟

بله، پارامتر اولویت هم در اکشن و هم در فیلتر یکسان است. مقدار پیش‌فرض ۱۰ است و callbackهایی که اولویت پایین‌تر دارند زودتر اجرا می‌شوند. اما در فیلترها، ترتیب اولویت اهمیت بیشتری دارد چون تغییرات روی یک داده اعمال می‌شوند و ترتیب اعمال، نتیجه نهایی را تغییر می‌دهد.

چطور یک هوک سفارشی بسازم که هم قابل توسعه با اکشن باشد و هم با فیلتر؟

شما می‌توانید در کد خود هم از do_action و هم از apply_filters استفاده کنید. معمولاً ساختار توصیه‌شده این است که اکشن را برای نقاط توسعه (مانند قبل و بعد از یک عملیات) و فیلتر را برای تغییر داده‌ها به‌کار ببرید. یک الگوی خوب: در ابتدای یک تابع، یک اکشن با نام before_my_action و در انتهای آن یک اکشن با نام after_my_action تعریف کنید، و در میان آن‌ها از فیلتر my_data برای تغییر داده استفاده کنید.

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

بله، اکشن‌ها هم می‌توانند پارامتر داشته باشند. وقتی do_action( 'my_action', $arg1, $arg2 ) را فراخوانی می‌کنید، این پارامترها به callback منتقل می‌شوند. اما برخلاف فیلترها، پارامترها به‌صورت زنجیره‌ای منتقل نمی‌شوند و هر callback مستقل از دیگری آن‌ها را دریافت می‌کند.

چرا در ووکامرس از اکشن‌ها بیشتر استفاده می‌شود؟

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

چطور یک هوک را حذف کنم؟

برای حذف اکشن از remove_action و برای حذف فیلتر از remove_filter استفاده کنید. نکته مهم: برای حذف یک هوک، باید همان نام تابع، همان اولویت، و همان تعداد پارامترهایی که در add_action یا add_filter استفاده کرده‌اید را مشخص کنید. همچنین، تابع callback شما باید نام‌دار باشد، نه بی‌نام. برای یادگیری بیشتر، نحوه حذف یک Action Hook در وردپرس و نحوه حذف یک Filter Hook در وردپرس را بخوانید.

آیا اکشن و فیلتر از نظر معماری داخلی متفاوت هستند؟

در سطح معماری داخلی، هر دو از یک کلاس مشترک به‌نام WP_Hook استفاده می‌کنند که در نسخه ۴.۷ معرفی شد. اما تفاوت در نحوه فراخوانی و رفتار callbackها است: در اکشن، callbackها مستقل اجرا می‌شوند و مقدار بازگشتی نادیده گرفته می‌شود؛ در فیلتر، callbackها به‌صورت زنجیره‌ای اجرا می‌شوند و مقدار بازگشتی هر کدام، ورودی callback بعدی است.

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

هوک‌ها ذاتاً امن هستند اما استفاده نادرست از آن‌ها می‌تواند به مشکلات امنیتی منجر شود. مثلاً اگر در یک فیلتر، داده‌ای که از کاربر می‌آید را بدون پاک‌سازی تغییر دهید و در فرانت‌اند نمایش دهید، می‌تواند به حمله XSS منجر شود. همیشه داده‌های ورودی و خروجی را با توابع استاندارد وردپرس مثل esc_html و esc_url پاک کنید. برای یادگیری عمیق‌تر امنیت در هوک‌ها، هوک‌های وردپرس و افزایش امنیت کد را بخوانید.

چطور می‌توانم بفهمم چه هوک‌هایی در یک صفحه اجرا می‌شوند؟

ابزار اصلی برای این کار، افزونه Query Monitor است که تمام هوک‌های اجرا شده در هر صفحه را با جزئیات کامل نشان می‌دهد. همچنین، می‌توانید از افزونه‌های دیباگ دیگر مثل Debug Bar استفاده کنید. برای یادگیری روش‌های دستی هم، می‌توانید در کد خود do_action( 'debug_all_hooks' ) اضافه کنید و در یک اکشن، فهرست تمام هوک‌های فعال را با $wp_filter چاپ کنید.

معماری هوک: انتخاب درست، لایه‌بندی درست

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

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

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