Bỏ qua tới nội dung
Theme

CSS của Child Theme WordPress không tải được

File style.css của child theme không tải được vì WordPress không tự enqueue nó cho bạn. Stylesheet của child theme phải được đăng ký thủ công trong

Đã đăng

File style.css của child theme không tải được vì WordPress không tự enqueue nó cho bạn. Stylesheet của child theme phải được đăng ký thủ công trong file functions.php của child theme, và đoạn enqueue đó gần như lúc nào cũng dính một trong hai lỗi: hoặc là không có nó luôn, hoặc là nó tải mà không khai báo stylesheet của theme cha là dependency, nên các rule CSS của bạn rơi sai vị trí trong cascade và bị đè. Sửa lại đoạn enqueue là CSS quay về. Chiêu @import cũ mà chắc bạn copy từ một bài hướng dẫn năm 2013 là cách sửa sai.

Vì sao lỗi này xảy ra

Một child theme kinh điển gồm hai file bắt buộc: một style.css với khối header khai báo theme cha, và một functions.php. Dòng Template: trong header cho WordPress biết kế thừa template từ theme cha nào. Đó là điều duy nhất WordPress làm tự động. Nó đọc header, nối dây template fallback, rồi dừng. Nó không bao giờ enqueue file style.css của child theme ở front end.

Trong khi đó, theme cha enqueue stylesheet của nó từ functions.php của nó, hook vào wp_enqueue_scripts. File functions.php của child chạy trước, rồi tới của theme cha, rồi mọi thứ trên hook đó mới kích hoạt. Nếu child không bao giờ gọi wp_enqueue_style cho file của chính nó, trình duyệt sẽ không bao giờ request file đó. Trang trông y hệt theme cha thô, bởi vì thực chất nó đúng là như vậy.

Lỗi thứ hai tinh vi hơn. Bạn enqueue stylesheet của child, nó tải được, nhưng các override lại chẳng có tác dụng gì. Đó là vấn đề thứ tự tải. Khi hai rule có độ ưu tiên (specificity) bằng nhau, cái tải sau cùng thắng. Nếu CSS của child tải trước CSS của theme cha, theme cha thắng mọi lần hòa. Mảng dependency trong wp_enqueue_style chính là thứ ép thứ tự.

Còn một điều nữa mà người ta hay nhầm: get_template_directory_uri() trỏ tới thư mục theme cha, còn get_stylesheet_directory_uri() trỏ tới thư mục theme đang kích hoạt (child). Đảo hai cái này là bạn enqueue style.css của theme cha lần thứ hai và chẳng bao giờ đụng tới của child.

Cách sửa, theo thứ tự

Đầu tiên, xác nhận cái gì đang thực sự được tải. Mở trang bị lỗi, xem source, và tìm tên thư mục child theme của bạn. WordPress render các style đã enqueue thành <link id="handle-css" href="..."> — cái id là handle của bạn cộng thêm -css. Nếu style.css của child hoàn toàn không có trong <head>, thì đoạn enqueue không chạy. Nếu nó có ở đó nhưng CSS không áp dụng, thì đó là vấn đề dependency/thứ tự. Chỉ một lần kiểm tra này cho bạn biết mình dính lỗi nào trong hai lỗi.

Thứ hai, tìm handle thật của theme cha. Đa số theme hiện đại (Astra, GeneratePress, các theme Twenty-*) đã tự enqueue stylesheet của chúng dưới một handle cụ thể — astra-theme-css, generate-style-css, twenty-twenty-four-style, v.v. Bạn cần chính xác chuỗi đó. Grep theme cha, hoặc đọc nó từ <link id="...-css"> trong view source (bỏ phần đuôi -css).

Thứ ba, viết đoạn enqueue. Với trường hợp phổ biến là theme cha đã tự tải stylesheet của nó, bạn không enqueue lại theme cha. Bạn chỉ enqueue child, và liệt kê handle của theme cha làm dependency để file của bạn tải sau nó:

<?php
add_action( 'wp_enqueue_scripts', 'child_enqueue_styles', 20 );

function child_enqueue_styles() {
    wp_enqueue_style(
        'child-style',
        get_stylesheet_directory_uri() . '/style.css',
        array( 'astra-theme-css' ), // <-- the parent's REAL handle
        wp_get_theme()->get( 'Version' )
    );
}

Nếu theme cha không enqueue stylesheet của chính nó (một số theme cũ hoặc tối giản dựa vào @import), thì enqueue cả hai, và cho child phụ thuộc vào theme cha:

<?php
add_action( 'wp_enqueue_scripts', 'child_enqueue_styles' );

function child_enqueue_styles() {
    wp_enqueue_style(
        'parent-style',
        get_template_directory_uri() . '/style.css'
    );
    wp_enqueue_style(
        'child-style',
        get_stylesheet_directory_uri() . '/style.css',
        array( 'parent-style' ),
        wp_get_theme()->get( 'Version' )
    );
}

Tham số wp_get_theme()->get('Version') chính là bộ phá cache của bạn. Tăng dòng Version: trong header style.css của child là trình duyệt tải lại. Bỏ qua nó là bạn sẽ sửa CSS rồi thề rằng chẳng có gì thay đổi trong khi thật ra chỉ là bị cache.

Nếu functions.php có lỗi cú pháp, cả file chết lặng lẽ và không có đoạn enqueue nào của bạn chạy — biểu hiện y hệt “CSS không tải được”. Bật WP_DEBUG lên, hoặc dán debug.log của bạn vào công cụ giải mã error log WordPress của chúng tôi để phát hiện lỗi fatal thật nhanh.

Những điều không nên làm

Đừng dùng @import. Lời khuyên thời Codex là đặt @import url("../parenttheme/style.css"); ở đầu file style.css của child. Nó chạy được, nhưng chậm — trình duyệt không thể bắt đầu tải CSS của theme cha cho tới khi nó đã parse xong CSS của child, nên hai request chạy nối tiếp thay vì song song. Ngay cả handbook chính thức của WordPress đã khuyến cáo không nên dùng nó suốt nhiều năm nay. Nếu bài hướng dẫn của bạn bảo làm thế này, thì chính bài đó là lý do CSS của bạn giật cục.

Đừng hardcode handle 'parent-style' rồi enqueue file của theme cha một cách mù quáng. Đoạn snippet nổi tiếng của Codex làm đúng như vậy, và nó sai với bất kỳ theme nào đã đăng ký stylesheet dưới một handle khác. Kết cục là bạn tải CSS của theme cha hai lần và dependency của bạn trỏ tới một handle có thể không tồn tại.

Đừng gọi wp_enqueue_style ở cấp cao nhất của functions.php. Nó phải chạy bên trong một hàm được hook vào wp_enqueue_scripts. Gọi quá sớm thì nó chẳng làm gì cả.

Đừng copy nguyên functions.php của theme cha vào child. Cả hai đều tải; của child chạy trước. Copy như vậy gây khai báo hàm trùng lặp và lỗi fatal.

Một lưu ý: tất cả những điều này áp dụng cho theme kinh điển (dùng PHP-template). Nếu theme cha của bạn là block theme, việc tạo kiểu chủ yếu chạy qua theme.json và Site Editor, và các override trong style.css hoạt động khác đi — cái đó tôi ít tin hơn nên hãy test trực tiếp thay vì mặc định đoạn enqueue này là cách sửa.

Vẫn kẹt?

Xác nhận dòng Template: trong header style.css của child khớp chính xác với tên thư mục của theme cha, phân biệt hoa thường — chứ không phải tên hiển thị của theme cha. Rồi kiểm tra lại view source: handle có mặt, tải sau theme cha, chuỗi query version đã được tăng. Nếu thẻ <link> có đó, tải sau cùng, mà CSS vẫn không áp dụng, thì đó không còn là vấn đề enqueue nữa — đó là specificity, và cách sửa chuyển vào bên trong chính các rule.