🪝 فصل ۷: Hooks و Filters پیشرفته در ووکامرس
ووکامرس بیش از ۴۰۰ هوک اکشن و فیلتر دارد. در این فصل، حرفهایترین و کاربردیترین آنها را برای سفارشیسازی فروشگاه یاد میگیرید.
🛒 هوکهای سبد خرید
بررسی قبل از افزودن به سبد
// محدودیت تعداد محصول در سبد
add_filter('woocommerce_add_to_cart_validation', function($passed, $product_id, $quantity) {
// محدودیت ۵ عدد از یک محصول
foreach (WC()->cart->get_cart() as $item) {
if ($item['product_id'] == $product_id) {
if (($item['quantity'] + $quantity) > 5) {
wc_add_notice('حداکثر ۵ عدد از این محصول میتوانید بخرید', 'error');
return false;
}
}
}
return $passed;
}, 10, 3);
محدودیت ترکیب محصولات
// نمیتوان محصولات از دو دسته خاص را با هم خرید
add_filter('woocommerce_add_to_cart_validation', function($passed, $product_id) {
$cats = wp_get_post_terms($product_id, 'product_cat', ['fields' => 'slugs']);
if (!in_array('digital', $cats)) return $passed;
// اگر در سبد محصول فیزیکی هست، اجازه نده
foreach (WC()->cart->get_cart() as $item) {
$existing_cats = wp_get_post_terms($item['product_id'], 'product_cat', ['fields' => 'slugs']);
if (in_array('physical', $existing_cats)) {
wc_add_notice('محصول دیجیتال و فیزیکی را نمیتوان همزمان سفارش داد', 'error');
return false;
}
}
return $passed;
}, 10, 2);
افزودن خودکار هدیه
// خرید بالای ۵۰۰ هزار = یک محصول هدیه رایگان
add_action('woocommerce_before_calculate_totals', function($cart) {
if (is_admin() && !defined('DOING_AJAX')) return;
$gift_id = 123; // ID محصول هدیه
$threshold = 500000;
$has_gift = false;
$cart_total = 0;
// محاسبه و چک
foreach ($cart->get_cart() as $key => $item) {
if ($item['product_id'] != $gift_id) {
$cart_total += $item['line_total'];
} else {
$has_gift = $key;
}
}
// اضافه/حذف خودکار
if ($cart_total >= $threshold && !$has_gift) {
WC()->cart->add_to_cart($gift_id, 1, 0, [], ['_is_gift' => true]);
} elseif ($cart_total < $threshold && $has_gift) {
WC()->cart->remove_cart_item($has_gift);
}
});
// محصول هدیه را رایگان کن
add_action('woocommerce_before_calculate_totals', function($cart) {
foreach ($cart->get_cart() as $item) {
if (!empty($item['_is_gift'])) {
$item['data']->set_price(0);
}
}
}, 20);
💳 هوکهای صفحه پرداخت
اضافه کردن فیلد سفارشی
// فیلد "تاریخ تحویل دلخواه"
add_action('woocommerce_after_order_notes', function($checkout) {
woocommerce_form_field('delivery_date', [
'type' => 'date',
'class' => ['form-row-wide'],
'label' => 'تاریخ تحویل دلخواه',
'required' => false,
], $checkout->get_value('delivery_date'));
});
// validation
add_action('woocommerce_checkout_process', function() {
if (!empty($_POST['delivery_date'])) {
$date = strtotime($_POST['delivery_date']);
if ($date < strtotime('+2 days')) {
wc_add_notice('تاریخ تحویل باید حداقل ۲ روز بعد باشد', 'error');
}
}
});
// ذخیره
add_action('woocommerce_checkout_update_order_meta', function($order_id) {
if (!empty($_POST['delivery_date'])) {
$order = wc_get_order($order_id);
$order->update_meta_data('_delivery_date', sanitize_text_field($_POST['delivery_date']));
$order->save();
}
});
// نمایش در پنل ادمین
add_action('woocommerce_admin_order_data_after_billing_address', function($order) {
$date = $order->get_meta('_delivery_date');
if ($date) {
echo 'تاریخ تحویل دلخواه: ' . esc_html($date) . '
';
}
});
فیلد شرطی – فقط برای دستههای خاص
add_action('woocommerce_after_order_notes', function($checkout) {
// اگر در سبد، محصول از دسته «فرش» هست
$has_carpet = false;
foreach (WC()->cart->get_cart() as $item) {
$cats = wp_get_post_terms($item['product_id'], 'product_cat', ['fields' => 'slugs']);
if (in_array('carpet', $cats)) {
$has_carpet = true;
break;
}
}
if ($has_carpet) {
woocommerce_form_field('floor_size', [
'type' => 'text',
'label' => 'متراژ کف اتاق (برای راهنمایی نصب)',
]);
}
});
تغییر متن دکمه پرداخت
add_filter('woocommerce_order_button_text', function($text) {
return 'پرداخت امن و ثبت سفارش';
});
📦 چرخه عمر سفارش
اکشنهای مهم وضعیت سفارش
| هوک | زمان اجرا |
|---|---|
woocommerce_new_order |
هنگام ثبت سفارش جدید |
woocommerce_order_status_pending_to_processing |
پرداخت موفق |
woocommerce_order_status_processing_to_completed |
تکمیل سفارش |
woocommerce_order_status_changed |
هر تغییر وضعیت |
woocommerce_order_refunded |
استرداد |
ارسال SMS هنگام تغییر وضعیت
add_action('woocommerce_order_status_changed', function($order_id, $old_status, $new_status, $order) {
$phone = $order->get_billing_phone();
if (!$phone) return;
$messages = [
'processing' => 'سفارش %s شما در حال پردازش است.',
'completed' => 'سفارش %s ارسال شد. کد رهگیری در پنل کاربری.',
'cancelled' => 'سفارش %s لغو شد.',
'refunded' => 'مبلغ سفارش %s به حساب شما بازگشت.',
];
if (!isset($messages[$new_status])) return;
$message = sprintf($messages[$new_status], $order->get_order_number());
// ارسال با کاوهنگار
wp_remote_post('https://api.kavenegar.com/v1/.../sms/send.json', [
'body' => ['receptor' => $phone, 'message' => $message],
'timeout' => 5,
]);
}, 10, 4);
تغییر وضعیت خودکار بعد از زمان مشخص
// سفارشهای processing بعد از ۷ روز خودکار completed شوند
add_action('init', function() {
if (!wp_next_scheduled('icsd_auto_complete_orders')) {
wp_schedule_event(time(), 'daily', 'icsd_auto_complete_orders');
}
});
add_action('icsd_auto_complete_orders', function() {
$orders = wc_get_orders([
'status' => 'processing',
'date_created' => '<' . (time() - (7 * DAY_IN_SECONDS)),
'limit' => 100,
]);
foreach ($orders as $order) {
$order->update_status('completed', 'تکمیل خودکار پس از ۷ روز');
}
});
📦 هوکهای صفحه محصول
تب جدید در صفحه محصول
add_filter('woocommerce_product_tabs', function($tabs) {
$tabs['warranty'] = [
'title' => 'گارانتی و خدمات پس از فروش',
'priority' => 30,
'callback' => function() {
global $product;
$warranty = $product->get_meta('_warranty_period');
?>
اطلاعات گارانتی
مدت گارانتی: = esc_html($warranty ?: '۱ سال') ?>
پشتیبانی: ۰۲۱-۱۲۳۴۵۶۷۸
- تعویض ۷ روزه
- گارانتی اصالت کالا
- خدمات پس از فروش رایگان
نشان «موجود» / «ناموجود» سفارشی
add_filter('woocommerce_get_availability', function($availability, $product) {
if ($product->is_in_stock()) {
$stock = $product->get_stock_quantity();
if ($stock !== null && $stock < 5) {
$availability['availability'] = 'فقط ' . $stock . ' عدد در انبار!';
$availability['class'] = 'low-stock';
} else {
$availability['availability'] = '✓ موجود در انبار';
}
} else {
$availability['availability'] = 'به زودی موجود میشود - اطلاعرسانی کنید';
}
return $availability;
}, 10, 2);
تخفیف ویژه برای کاربر VIP
add_filter('woocommerce_product_get_price', function($price, $product) {
if (!is_user_logged_in()) return $price;
$user = wp_get_current_user();
if (in_array('vip_customer', (array) $user->roles)) {
return floatval($price) * 0.9; // ۱۰٪ تخفیف
}
return $price;
}, 10, 2);
📧 سفارشیسازی ایمیلها
اضافه کردن متن سفارشی به ایمیلها
add_action('woocommerce_email_after_order_table', function($order, $sent_to_admin, $plain_text, $email) {
if ($sent_to_admin || $email->id !== 'customer_processing_order') return;
echo '';
echo '📞 پشتیبانی ۲۴ ساعته
';
echo 'تماس: ۰۲۱-۱۲۳۴۵۶۷۸
';
echo 'تلگرام: @icsd_support
';
echo '';
}, 10, 4);
تغییر موضوع ایمیل
add_filter('woocommerce_email_subject_customer_processing_order', function($subject, $order) {
return sprintf('🎉 سفارش #%s دریافت شد - %s', $order->get_order_number(), get_bloginfo('name'));
}, 10, 2);
ساخت ایمیل کاملاً جدید
add_filter('woocommerce_email_classes', function($emails) {
require_once __DIR__ . '/includes/class-wc-email-shipped.php';
$emails['WC_Email_Shipped'] = new WC_Email_Shipped();
return $emails;
});
// در فایل کلاس:
class WC_Email_Shipped extends WC_Email {
public function __construct() {
$this->id = 'wc_email_shipped';
$this->title = 'سفارش ارسال شد';
$this->description = 'به مشتری اطلاع میدهد که سفارش پست شد';
$this->customer_email = true;
$this->template_html = 'emails/customer-shipped.php';
$this->template_plain = 'emails/plain/customer-shipped.php';
$this->placeholders = [
'{order_number}' => '',
'{tracking_code}' => '',
];
add_action('icsd_order_shipped_notification', [$this, 'trigger'], 10, 2);
parent::__construct();
}
public function trigger($order_id, $tracking_code) {
$this->object = wc_get_order($order_id);
$this->placeholders['{order_number}'] = $this->object->get_order_number();
$this->placeholders['{tracking_code}'] = $tracking_code;
$this->recipient = $this->object->get_billing_email();
$this->send($this->recipient, $this->get_subject(), $this->get_content(),
$this->get_headers(), $this->get_attachments());
}
public function get_default_subject() {
return '🚚 سفارش {order_number} ارسال شد';
}
}
// تریگر کن
do_action('icsd_order_shipped_notification', $order_id, $tracking_code);
💸 کارمزد و تخفیف پویا
اضافه کردن کارمزد بستهبندی
add_action('woocommerce_cart_calculate_fees', function($cart) {
if (is_admin() && !defined('DOING_AJAX')) return;
// اگر بستهبندی هدیه انتخاب شده
if (!empty($_POST['gift_wrap'])) {
$cart->add_fee('بستهبندی هدیه', 25000, true);
}
// کارمزد پرداخت در محل
$payment_method = WC()->session->get('chosen_payment_method');
if ($payment_method === 'cod') {
$cart->add_fee('کارمزد پرداخت در محل', 15000, false);
}
});
تخفیف خودکار با کد
// تخفیف ۱۰٪ خودکار برای اولین خرید
add_action('woocommerce_before_calculate_totals', function($cart) {
if (is_admin() && !defined('DOING_AJAX')) return;
if (!is_user_logged_in()) return;
$user_id = get_current_user_id();
$orders_count = wc_get_customer_order_count($user_id);
if ($orders_count == 0 && !$cart->has_discount('first_purchase')) {
$cart->apply_coupon('first_purchase');
}
});
function wc_get_customer_order_count($user_id) {
return count(wc_get_orders(['customer_id' => $user_id, 'limit' => -1]));
}
تخفیف بر اساس تعداد
// خرید ۳ تا = ۵٪، ۵ تا = ۱۰٪، ۱۰ تا = ۱۵٪
add_action('woocommerce_before_calculate_totals', function($cart) {
if (is_admin() && !defined('DOING_AJAX')) return;
foreach ($cart->get_cart() as $item) {
$qty = $item['quantity'];
$original = floatval($item['data']->get_regular_price());
$discount = 0;
if ($qty >= 10) $discount = 0.15;
elseif ($qty >= 5) $discount = 0.10;
elseif ($qty >= 3) $discount = 0.05;
if ($discount > 0) {
$item['data']->set_price($original * (1 - $discount));
}
}
});
📊 مدیریت موجودی
کاهش موجودی هنگام ساخت سفارش (نه فقط پرداخت)
// رزرو موجودی به محض ثبت سفارش
add_action('woocommerce_checkout_order_processed', function($order_id) {
$order = wc_get_order($order_id);
foreach ($order->get_items() as $item) {
$product = $item->get_product();
if ($product && $product->managing_stock()) {
$product->set_stock_quantity($product->get_stock_quantity() - $item->get_quantity());
$product->save();
}
}
});
اطلاعرسانی موجودی به ادمین
add_action('woocommerce_low_stock', function($product) {
$email = get_option('admin_email');
$message = sprintf(
'محصول "%s" کمموجود شد (تعداد: %d)',
$product->get_name(),
$product->get_stock_quantity()
);
wp_mail($email, 'هشدار کمموجودی', $message);
});
add_action('woocommerce_no_stock', function($product) {
// اطلاع به مدیر و فروشنده
do_action('icsd_send_telegram', '⚠️ محصول ' . $product->get_name() . ' ناموجود شد');
});
قابلیت «وقتی موجود شد، اطلاعم بده»
// در محصولات ناموجود، فرم ثبت ایمیل
add_action('woocommerce_single_product_summary', function() {
global $product;
if ($product->is_in_stock()) return;
?>
is_in_stock()) return;
$subscribers = get_post_meta($product->get_id(), '_back_in_stock_subscribers', true) ?: [];
foreach ($subscribers as $email) {
wp_mail($email, 'محصول مورد علاقهتان موجود شد!',
$product->get_name() . ' الان موجود است: ' . $product->get_permalink());
}
delete_post_meta($product->get_id(), '_back_in_stock_subscribers');
});
🔍 دیباگ هوکها
پیدا کردن هوکهای فعال
// نمایش تمام هوکهای اجرا شده
add_action('all', function($tag) {
if (strpos($tag, 'woocommerce') !== false) {
error_log('WC Hook fired: ' . $tag);
}
});
افزونه Query Monitor
افزونه Query Monitor را نصب کنید — تب «Hooks & Actions» تمام هوکهای اجرا شده در صفحه فعلی را با priority و callback نشان میدهد.
پیدا کردن هوک کنار یک خروجی
// در فایل قالب، قبل از خروجی:
echo '';
do_action('woocommerce_before_main_content');
echo '';
✅ مرجع کامل: همه هوکهای ووکامرس در سایت رسمی فهرست شدهاند:
https://woocommerce.github.io/code-reference/hooks/hooks.html
📝 خلاصه فصل
- هوکهای قدرتمند سبد خرید برای محدودیت و هدیه
- اضافه کردن فیلد سفارشی به checkout
- چرخه عمر سفارش و SMS خودکار
- سفارشیسازی صفحه محصول و ایمیلها
- کارمزد پویا، تخفیف خودکار و رزرو موجودی
- ابزارهای دیباگ هوکها