Trong quá trình phát triển website thương mại điện tử bằng WordPress, việc giữ nguyên bản sắc thiết kế từ Figma hay Adobe XD lên giao diện WooCommerce là một thách thức lớn. Mặc định, WooCommerce cung cấp một cấu trúc khá cứng nhắc.
Hôm nay, mình sẽ hướng dẫn các bạn cách thay đổi hoàn toàn Product Loop Item (thẻ sản phẩm trong danh sách) theo một layout custom riêng bằng phương pháp Template Override.
1. Tại sao không nên dùng CSS để “vọc” layout mặc định?
Nhiều bạn thường chọn cách dùng CSS position: absolute để dịch chuyển các thành phần. Tuy nhiên, cách này khiến code rất rối và khó phản hồi (responsive) trên Mobile. Việc can thiệp trực tiếp vào cấu trúc HTML sẽ giúp:
- Code sạch, chuẩn cấu trúc SEO.
- Dễ dàng quản lý các class CSS theo hệ thống (như Bootstrap hoặc Tailwind).
- Kiểm soát hoàn toàn các tính năng như nút xem nhanh (Quickview) hay nhãn (Labels).
2. Quy trình thực hiện
Bước 1: Tạo file ghi đè trong Theme
WooCommerce cho phép chúng ta “đè” file giao diện của họ bằng file trong theme của mình.
- Truy cập vào thư mục theme (khuyên dùng Child Theme).
- Tạo thư mục woocommerce (nếu chưa có).
- Copy file content-product.php từ đường dẫn plugins/woocommerce/templates/ vào thư mục vừa tạo.
Đường dẫn đích: wp-content/themes/[your-theme]/woocommerce/content-product.php
Bước 2: Chỉnh sửa cấu trúc HTML Custom
Mở file content-product.php bạn vừa copy và thay thế bằng đoạn mã dưới đây. Layout này sử dụng cấu trúc thẻ <figure> cho phần ảnh và .product-body cho phần thông tin.
PHP
<?php
defined( 'ABSPATH' ) || exit;
global $product;
if ( empty( $product ) || ! $product->is_visible() ) return;
?>
<div <?php wc_product_class( 'product product-2', $product ); ?>>
<figure class="product-media">
<?php if ( $product->is_on_sale() ) : ?>
<span class="product-label label-circle label-sale">Sale</span>
<?php endif; ?>
<a href="<?php the_permalink(); ?>">
<?php echo $product->get_image('woocommerce_thumbnail'); ?>
</a>
<div class="product-action-vertical">
<a href="#" class="btn-product-icon btn-wishlist" title="Add to wishlist"></a>
</div>
<div class="product-action">
<a href="<?php echo esc_url($product->add_to_cart_url()); ?>" class="btn-product btn-cart">
<span>Add to cart</span>
</a>
<a href="#" class="btn-product btn-quickview"><span>Quick view</span></a>
</div>
</figure>
<div class="product-body">
<div class="product-cat">
<?php echo wc_get_product_category_list( $product->get_id(), ', ' ); ?>
</div>
<h3 class="product-title">
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
</h3>
<div class="product-price">
<?php echo $product->get_price_html(); ?>
</div>
<?php if ( $product->get_rating_count() > 0 ) : ?>
<div class="ratings-container">
<div class="ratings">
<div class="ratings-val" style="width: <?php echo ( ( $product->get_average_rating() / 5 ) * 100 ); ?>%;"></div>
</div>
<span class="ratings-text">(<?php echo $product->get_rating_count(); ?> Reviews)</span>
</div>
<?php endif; ?>
</div>
</div>
Bước 3: Vô hiệu hóa các Hook mặc định
Vì chúng ta đã tự định nghĩa HTML, chúng ta cần yêu cầu WooCommerce ngừng “nhồi nhét” các hàm mặc định vào loop. Thêm đoạn code này vào file functions.php của theme:
PHP
remove_action( 'woocommerce_before_shop_loop_item', 'woocommerce_template_loop_product_link_open', 10 );
remove_action( 'woocommerce_after_shop_loop_item', 'woocommerce_template_loop_product_link_close', 5 );
remove_action( 'woocommerce_shop_loop_item_title', 'woocommerce_template_loop_product_title', 10 );
remove_action( 'woocommerce_after_shop_loop_item_title', 'woocommerce_template_loop_price', 10 );
remove_action( 'woocommerce_after_shop_loop_item_title', 'woocommerce_template_loop_rating', 5 );
remove_action( 'woocommerce_before_shop_loop_item_title', 'woocommerce_template_loop_product_thumbnail', 10 );
remove_action( 'woocommerce_after_shop_loop_item', 'woocommerce_template_loop_add_to_cart', 10 );
Bước 4: Một vài lỗi phổ biến thường gặp (quan trọng)
Khi các bạn làm xong bước 3, có thể bạn sẽ gặp 1 vài lỗi layout. Cho nên các bạn cần kiểm tra các điểm sau đây:
1/ Layout sản phẩm của bạn sẽ nằm trong thẻ <ul class=”column-4″ > nếu bạn sử dụng shortcode: [ products limit=”10″ columns=”4″]. Chính vì vậy mà bạn cần thay đổi những thẻ div con bên trong thành thẻ <li> nhé.
2/ Bị xung đột css với woocommerce. Bạn nên bỏ đi những class mặc định của woo. Ví dụ: <div <?php wc_product_class( ‘product product-2’, $product ); ?>> đổi lại thành <div class=”product product-2″>.
3/ Các sản phẩm sẽ không dàn đều cột, hoặc cột đầu tiên sẽ bị bỏ trống vì có chứa nội dung trong pseudo class ::before như hình dưới đây:

Nguyên nhân vì mặc định css của woo khi chia cột sẽ thêm các class như: products, last, first. Nhưng khi ta sử dụng các class riêng của chúng ta theo bảng thiết kế thì nó sẽ dàn cột không đều.
Giải pháp: Viết Css ghi đè Css của Woo là được. Các bạn tham khảo đoạn code bên dưới mình viết nhé
/* Xóa cột trống đầu tiên vì có pseudo class before */
ul.products.columns-4::before {
content: none !important;
display: none !important;
grid-column: 0 !important;
/* Đảm bảo không chiếm diện tích grid */
}
/* Ép thẻ UL hiển thị dạng Grid */
.woocommerce ul.products.columns-4 {
grid-auto-flow: row dense;
/* Tự động lấp đầy các ô trống */
display: grid !important;
grid-template-columns: repeat(4, 1fr) !important;
/* Chia đúng 4 cột đều nhau */
gap: 20px;
/* Khoảng cách giữa các sản phẩm */
list-style: none;
}
/* Đảm bảo thẻ li của bạn không bị vỡ */
.woocommerce ul.products li.product-2 {
/* Đảm bảo không dùng float cũ */
width: 100% !important;
/* Để grid kiểm soát độ rộng */
margin: 0 !important;
float: none !important;
/* Xóa float để tránh xung đột layout cũ */
display: block;
}
/* Xử lý khoảng xám dư bị lệch sang phải */
.product-2 .product-media {
background: transparent !important;
display: flex;
justify-content: center;
}
3. Một số lưu ý để layout hoàn hảo hơn
- CSS Aspect Ratio: Để các thẻ sản phẩm luôn cao bằng nhau dù ảnh gốc khác kích thước, hãy sử dụng thuộc tính aspect-ratio: 1/1; và object-fit: cover; cho hình ảnh.
- Nút Wishlist: Nếu bạn dùng plugin YITH Wishlist, hãy thay thế thẻ <a> bằng shortcode của plugin để tính năng hoạt động.
- Mobile Optimization: Layout dạng hover thường không hoạt động tốt trên điện thoại. Hãy đảm bảo bạn có CSS riêng để các nút chức năng hiển thị cố định trên màn hình nhỏ.
Kết luận
Việc làm chủ cấu trúc content-product.php giúp bạn không còn phụ thuộc vào các Theme có sẵn. Bạn có thể tự tin nhận mọi dự án thiết kế khó nhất và hiện thực hóa nó trên nền tảng WooCommerce một cách chuyên nghiệp.
Chúc các bạn thành công!