Chuyển tới nội dung chính

1. Template Hooks: Product Item (Khối Sản Phẩm)

Product Item là khối UI hiển thị một sản phẩm thu gọn trong Grid hoặc Carousel. Các hooks được đăng ký trong bootstrap/template-object.php, chỉ được thêm nếu config Admin cho phép hiển thị tiêu đề/giá.


Sơ Đồ Hooks​

View render khối sản phẩm là views/loop/item_product.blade.php. Sáu action được phát theo đúng thứ tự sau — không có hook cha tên product_object:

<div class="item product-item">
product_item_before (đầu card)
<div class="product">
product_object_before_image (trước thẻ <a> bọc ảnh)
<a href="...">
product_object_image (vùng ảnh đại diện)
</a>
product_object_after_image (sau thẻ <a> bọc ảnh)
</div>
<div class="title">
product_object_info (vùng thông tin: tiêu đề, giá)
├── priority = product.object.title.position → Title
└── priority = product.object.price.position → Price
</div>
product_item_after (cuối card)
</div>

Danh Sách Hook​

Mọi action đều nhận một tham số: $product (object sản phẩm).

Hook NamePriority Mặc ĐịnhHandler mặc địnhVị Trí
product_item_before—(không có)Ngay đầu card
product_object_before_image—(không có)Trước thẻ <a> bọc ảnh
product_object_image10ProductObject::imageBên trong thẻ <a> — vùng ảnh
product_object_after_image—(không có)Sau thẻ <a> bọc ảnh
product_object_infoconfig*ProductObject::titleTên sản phẩm
product_object_infoconfig*ProductObject::priceGiá sản phẩm
product_item_after—(không có)Cuối card

(*) Priority của title và price lấy từ config Commerce:

  • Config::get('product.object.title.position') — mặc định 10
  • Config::get('product.object.price.position') — mặc định 20

Admin có thể hoán đổi vị trí giá và tên từ trang cài đặt Commerce.

[!NOTE] Handler title chỉ được đăng ký khi product.object.title.show bật; tương tự price với product.object.price.show. Tắt trong Admin thì hook vẫn phát nhưng không có handler mặc định nào chạy.

Filter điều khiển kích thước ảnh​

FilterGiá trị mặc địnhMô tả
product_object_image_typesourceKiểu ảnh dùng cho khối sản phẩm (source, large, medium, thumb)
add_filter('product_object_image_type', fn() => 'medium');

Ví Dụ Thực Tế​

💡 Thêm Badge Giảm Giá vào vùng ảnh​

add_action('product_object_image', function($product) {
if($product->price_sale > 0 && $product->price_sale < $product->price) {
$percent = round((($product->price - $product->price_sale) / $product->price) * 100);
echo '<span class="badge-sale">-'.$percent.'%</span>';
}
}, 5); // Trước ảnh (priority 10) → hiện lên trên ảnh

💡 Thêm Button "Thêm Vào Giỏ Nhanh"​

add_action('product_object_info', function($product) {
if(!$product->hasVariation) {
echo '<button class="btn-quick-add" data-id="'.$product->id.'" data-price="'.$product->price.'">';
echo '🛒 Thêm vào giỏ';
echo '</button>';
}
}, 30); // Sau giá (priority 20)

💡 Thêm Đánh Giá Sao (Rating)​

// Plugin rating-star hook vào đây
add_action('product_object_info', function($product) {
$rating = DB::table('ratings')->where('product_id', $product->id)->avg('score');
if($rating) {
$stars = round($rating);
echo '<div class="star-rating" data-score="'.$rating.'">';
echo str_repeat('⭐', $stars);
echo '</div>';
}
}, 15); // Giữa title(10) và price(20)

💡 Thêm Nhãn "Hết hàng"​

add_action('product_object_image', function($product) {
$stock = DB::table('stocks')->where('product_id', $product->id)->value('quantity');
if($stock !== null && $stock <= 0) {
echo '<div class="out-of-stock-overlay">Hết hàng</div>';
}
}, 15);

Filters Liên Quan​

products_model_retrieved​

Thêm field tính toán vào mỗi Product khi lấy từ DB:

add_filter('products_model_retrieved', function($product) {
$product->discount_percent = 0;
if($product->price > 0 && $product->price_sale > 0) {
$product->discount_percent = round(
(($product->price - $product->price_sale) / $product->price) * 100
);
}
return $product;
});