- Nguyên tắc vàng
- Tạo child theme chuẩn (cấu trúc tối thiểu)
- Enqueue CSS/JS đúng cách (classic & block)
- Ưu tiên theme.json (block theme) để style không vỡ khi update
- CSS bền vững: dùng :where() và biến
- Ghi đè template an toàn (classic theme)
- Ghi đè template (block theme)
- Dùng hooks/filters thay vì sửa template
- Tách logic thành plugin mini (không để trong child theme)
- Ví dụ thực chiến: tinh gọn header và thêm nút CTA
- Kiểm soát khác biệt sau khi update
- Checklist nhanh trước khi xuất bản
- Kết luận
Nguyên tắc vàng
- Không sửa trực tiếp file của parent theme.
- Chức năng (logic) nên đưa vào plugin riêng; child theme tập trung phần trình bày.
- Ghi đè có chủ đích: CSS → theme.json → template parts → hooks/filters → cuối cùng mới là template.
- Ghi chú, đặt tên handle rõ ràng, quản lý version để tránh cache.
Tạo child theme chuẩn (cấu trúc tối thiểu)
wp-content/
└─ themes/
├─ parent-theme/
└─ my-child-theme/
├─ style.css
├─ functions.php
├─ assets/
│ ├─ css/custom.css
│ └─ js/custom.js
├─ template-parts/ (classic theme)
├─ templates/ (block theme)
└─ parts/ (block theme)
style.css của child theme (bắt buộc có phần header):
/*
Theme Name: My Child Theme
Template: parent-theme
Version: 1.0.0
Description: Child theme tối ưu cập nhật.
Text Domain: my-child
*/
Enqueue CSS/JS đúng cách (classic & block)
Đảm bảo nạp parent CSS trước, child CSS sau; gắn version theo theme để tránh cache cũ.
<?php
// functions.php trong child theme
add_action('wp_enqueue_scripts', function () {
// 1) Nạp CSS của parent
wp_enqueue_style(
'parent-style',
get_template_directory_uri() . '/style.css',
[],
wp_get_theme(get_template())->get('Version')
);
// 2) Nạp CSS của child
wp_enqueue_style(
'my-child-style',
get_stylesheet_directory_uri() . '/assets/css/custom.css',
['parent-style'],
wp_get_theme()->get('Version')
);
// 3) Nạp JS của child (nếu cần)
wp_enqueue_script(
'my-child-js',
get_stylesheet_directory_uri() . '/assets/js/custom.js',
[],
wp_get_theme()->get('Version'),
true
);
}, 20);
// Ví dụ loại bỏ 1 file CSS của parent nếu không cần:
add_action('wp_enqueue_scripts', function () {
wp_dequeue_style('parent-unwanted-css-handle');
}, 100);
Ưu tiên theme.json (block theme) để style không vỡ khi update
Với block theme, child theme có thể định nghĩa theme.json để kế thừa và ghi đè token/setting một cách có cấu trúc.
{
"$schema": "https://schemas.wp.org/trunk/theme.json",
"version": 2,
"settings": {
"color": {
"palette": [
{ "name": "Primary", "slug": "primary", "color": "#2f6fff" },
{ "name": "Text", "slug": "text", "color": "#1a1a1a" }
]
},
"spacing": { "units": [ "px", "em", "rem", "vh", "vw" ] }
},
"styles": {
"color": { "text": "var(--wp--preset--color--text)" },
"typography": { "fontSize": "16px", "lineHeight": "1.6" },
"blocks": {
"core/heading": {
"typography": { "fontWeight": "700" }
}
}
}
}
CSS bền vững: dùng :where() và biến
Giảm độ ưu tiên để dễ override về sau, tránh dùng !important tràn lan.
:root {
--my-primary: #2f6fff;
--my-radius: 12px;
}
:where(.btn-primary) {
background: var(--my-primary);
border-radius: var(--my-radius);
}
Ghi đè template an toàn (classic theme)
Chỉ override file cần thiết và bám theo template hierarchy của WordPress. Ví dụ parent dùng get_template_part('template-parts/content', 'single'), bạn chỉ cần tạo file tương ứng bên child.
Parent:
└─ template-parts/
└─ content-single.php
Child (ghi đè):
└─ template-parts/
└─ content-single.php
Ví dụ thêm badge vào tiêu đề bài viết mà không phá bố cục:
<?php
// my-child-theme/template-parts/content-single.php
the_title('<h1 class="entry-title">', '</h1>');
$badge = get_post_meta(get_the_ID(), '_vip_badge', true);
if ($badge) {
echo '<span class="post-badge">VIP</span>';
}
get_template_part('template-parts/content', 'body'); // vẫn tái sử dụng phần thân nếu parent tách nhỏ
Ghi đè template (block theme)
Với block theme, chỉ cần đặt file cùng tên vào thư mục templates/ hoặc parts/ của child.
Parent:
└─ templates/
└─ single.html
Child (ghi đè):
└─ templates/
└─ single.html
Ví dụ đơn giản cho templates/single.html trong child:
<!-- wp:template-part {"slug":"header","tagName":"header"} /-->
<main class="site-main">
<!-- wp:post-title {"level":1} /-->
<div class="entry-meta"><!-- wp:post-date /--></div>
<!-- wp:post-content /-->
</main>
<!-- wp:template-part {"slug":"footer","tagName":"footer"} /-->
Dùng hooks/filters thay vì sửa template
Nếu parent theme cung cấp hooks, bạn có thể thêm/bớt thành phần mà không phải copy cả file template.
<?php
// Thêm schema.org attribute vào body_class
add_filter('body_class', function ($classes) {
$classes[] = 'has-schema';
return $classes;
});
// Điều chỉnh excerpt length
add_filter('excerpt_length', function () {
return 24;
}, 20);
// Bỏ 1 action do parent thêm, rồi thay thế bằng action riêng
add_action('after_setup_theme', function () {
remove_action('wp_head', 'parent_theme_emoji_loader', 7);
add_action('wp_head', function () {
// loader thay thế nhẹ hơn
echo "<!-- custom head minimal -->";
}, 7);
}, 20);
Tách logic thành plugin mini (không để trong child theme)
Logic nên đi cùng site (plugin) thay vì đi cùng theme (đổi theme là mất). Ví dụ custom post type:
<?php
/**
* Plugin Name: Site Logic - CPT
*/
add_action('init', function () {
register_post_type('movie', [
'label' => 'Movies',
'public' => true,
'show_in_rest' => true,
'supports' => ['title','editor','thumbnail','excerpt']
]);
});
Ví dụ thực chiến: tinh gọn header và thêm nút CTA
Mục tiêu: bỏ 1 CSS nặng, thêm CTA vào sau tiêu đề, style bằng CSS nhẹ — bền vững qua update.
<?php
// functions.php (child)
// 1) Bỏ style nặng của parent, nạp child CSS
add_action('wp_enqueue_scripts', function () {
wp_dequeue_style('parent-heavy-header'); // handle do parent đăng ký
wp_enqueue_style(
'my-child-style',
get_stylesheet_directory_uri() . '/assets/css/custom.css',
['parent-style'],
wp_get_theme()->get('Version')
);
}, 100);
// 2) Thêm CTA bằng hook (giả sử parent có hook 'parent_after_title')
add_action('parent_after_title', function () {
echo '<a class="btn-primary" href="/signup">Đăng ký ngay</a>';
});
/* assets/css/custom.css */
:where(.btn-primary){
display:inline-block;
padding:.6rem 1rem;
background:var(--my-primary, #2f6fff);
color:#fff;
border-radius:10px;
text-decoration:none;
font-weight:700;
}
Kiểm soát khác biệt sau khi update
- So sánh thay đổi: dùng git cho child theme, sau khi update parent thì rà lại các file đã override.
- Tránh override toàn bộ template lớn; chỉ override phần tử con (template part) hoặc dùng hooks.
- Ghi chú trong đầu file (chức năng, ngày sửa, lý do) để bảo trì về sau.
- Nếu dùng ACF, bật Local JSON để versioning field group; template chỉ đọc dữ liệu.
Checklist nhanh trước khi xuất bản
- Đặt
Template:đúng folder name của parent trongstyle.css. - Enqueue CSS/JS theo đúng thứ tự; có version.
- Ưu tiên
theme.json(block) hoặc CSS biến/:where() để override sạch. - Hook/Filter trước khi đụng tới template override.
- Logic thành plugin; child theme chỉ để trình bày.
Kết luận
Tối ưu child theme không chỉ là “copy file sang để sửa”, mà là chiến lược bền vững: kế thừa đúng cách, ghi đè có chủ đích, ưu tiên hooks/filters/theme.json và tách logic thành plugin. Làm đúng từ đầu, mỗi lần parent theme cập nhật bạn chỉ cần kiểm tra nhẹ rồi tiếp tục phát triển, không lo mất công sức tùy biến.
Bình luận