Tối ưu child theme để update không bị mất custom

Child theme là “áo khoác” của parent theme: bạn có thể thêm/ghi đè CSS, JS, template mà không chạm vào mã nguồn gốc. Khi parent theme cập nhật, mọi chỉnh sửa của bạn vẫn an toàn. Bài viết này tổng hợp nguyên tắc vàng, kèm code ví dụ thực tế cho cả classic theme lẫn block theme (Full Site Editing) để bạn tối ưu child theme đúng chuẩn, bền vững qua các lần update.

Tối ưu child theme để update không bị mất custom

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 trong style.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


  • Không có bình luận.

Init Toolbox

Nhấn Ctrl + \ trên máy tính, hoặc vuốt sang trái ở bất kỳ đâu trên mobile.

Đăng nhập





Đang tải...