Giáo trình ôn tập WordPress bài bản + Vibe Coding

Chương 5 – Gutenberg/Block Editor, WP-CLI & Multisite

Cỡ chữ: 16px
Font:
Nền:
← Chương Trước Chương Tiếp →

NGÀY 5 (Chi tiết): Gutenberg/Block Editor, WP-CLI & Multisite

Đây là mảng dev lâu năm (học WP từ thời PHP thuần) hay yếu nhất vì Gutenberg đòi JS/React. Mục tiêu hôm nay: hiểu đúng khái niệm và nói được luồng hoạt động — không cần thành thạo viết block phức tạp trong 1 ngày.


PHẦN A: GUTENBERG / BLOCK EDITOR

1. Vì sao WordPress chuyển sang Gutenberg (bối cảnh — hay được hỏi mở đầu)

Trước 2018, WordPress dùng editor cổ điển (TinyMCE) — nội dung lưu dạng 1 khối HTML lớn trong post_content. Gutenberg thay đổi cách tiếp cận: nội dung được chia thành các “block” độc lập (paragraph, heading, image, custom block…), mỗi block có dữ liệu riêng, cho phép xây dựng trang phức tạp bằng cách ghép block thay vì viết HTML tay hoặc nhồi shortcode.

Điều quan trọng cần hiểu: Gutenberg không phải công nghệ hoàn toàn mới thay thế wpposts — nội dung Gutenberg vẫn lưu trong postcontent như cũ, chỉ khác là dưới dạng HTML có kèm HTML comment đặc biệt để đánh dấu ranh giới block:

`html
<!– wp:paragraph –>
<p>Đây là nội dung đoạn văn.</p>
<!– /wp:paragraph –>

<!– wp:my-plugin/book-card {“bookId”:5,”showPrice”:true} –>
<div class=”wp-block-my-plugin-book-card”>…</div>
<!– /wp:my-plugin/book-card –>
`

Comment <!-- wp:my-plugin/book-card {...} --> chứa tên block và attributes dạng JSON — đây là cách Gutenberg “nhớ” block nào với dữ liệu gì, để khi mở lại editor, React biết render đúng UI tương ứng.

2. Cấu trúc 1 block cơ bản

block.json — file khai báo metadata (chuẩn mới từ WP 5.8+, thay cho khai báo bằng PHP thuần):

`json
{
“apiVersion”: 3,
“name”: “my-plugin/book-card”,
“title”: “Book Card”,
“category”: “widgets”,
“icon”: “book”,
“attributes”: {
“bookId”: { “type”: “number”, “default”: 0 },
“showPrice”: { “type”: “boolean”, “default”: true }
},
“supports”: { “html”: false },
“editorScript”: “file:./index.js”,
“style”: “file:./style.css”
}
`

Đăng ký block phía PHP:
`php
add_action( ‘init’, function() {
registerblocktype( DIR . ‘/build’ ); // trỏ tới thư mục chứa block.json
});
`

edit.js — component React hiển thị TRONG editor (khi admin đang soạn bài):
`javascript
import { useBlockProps } from ‘@wordpress/block-editor’;

export default function Edit( { attributes, setAttributes } ) {
const { bookId } = attributes;
return (
<div { …useBlockProps() }>
<input
type=”number”
value={ bookId }
onChange={ (e) => setAttributes({ bookId: Number(e.target.value) }) }
/>
</div>
);
}
`

save.js — quyết định HTML nào được LƯU vào post_content (chạy lúc save, không chạy lúc hiển thị frontend nếu dùng Dynamic Block):
`javascript
export default function save( { attributes } ) {
return <div>Book ID: { attributes.bookId }</div>;
}
`

3. Static Block vs Dynamic Block — phân biệt quan trọng

| | Static Block | Dynamic Block |
|—|—|—|
| HTML frontend từ đâu | Sinh sẵn bởi save.js, lưu cứng trong postcontent | Render bằng PHP mỗi lần trang load (rendercallback) |
| Khi nào dùng | Nội dung tĩnh, không đổi theo thời gian (VD: banner tự thiết kế) | Nội dung động, phụ thuộc dữ liệu realtime (VD: “3 bài viết mới nhất”) |
| Ví dụ | Block Paragraph, Heading | Block Latest Posts, Book Card lấy giá mới nhất từ DB |

`php
// Dynamic block — không cần save.js, PHP tự render
registerblocktype( DIR . ‘/build’, [
‘render_callback’ => function( $attributes ) {
$book_id = $attributes[‘bookId’] ?? 0;
$price = getpostmeta( $bookid, ‘book_price’, true );
return ‘<div>Giá: ‘ . esc_html( $price ) . ‘</div>’;
},
]);
`

Câu trả lời mẫu khi phỏng vấn: “Em chọn Dynamic Block khi dữ liệu hiển thị có thể thay đổi sau khi bài viết đã publish — VD hiển thị giá sách hiện tại, vì nếu dùng Static Block, giá sẽ bị ‘đóng băng’ tại thời điểm lưu bài, không tự cập nhật khi giá đổi trong DB.”

4. @wordpress/scripts — công cụ build

`bash
npm install @wordpress/scripts –save-dev
`
`json
// package.json
“scripts”: {
“build”: “wp-scripts build”,
“start”: “wp-scripts start”
}
`
Đây là wrapper quanh Webpack, đã cấu hình sẵn theo chuẩn WordPress (React, JSX, tối ưu bundle) — không cần tự setup Webpack từ đầu.

5. theme.json — cho Block Theme / FSE (Full Site Editing)

Chỉ cần hiểu khái niệm, không cần chuyên sâu: theme.json là file khai báo design tokens của theme (màu sắc, font, spacing) theo format chuẩn để cả block editor lẫn frontend đều dùng chung 1 nguồn — tránh việc phải định nghĩa màu sắc 2 lần (1 lần trong CSS, 1 lần trong editor settings).

`json
{
“version”: 2,
“settings”: {
“color”: {
“palette”: [
{ “slug”: “primary”, “color”: “#1a73e8”, “name”: “Primary” }
]
}
}
}
`


PHẦN B: WP-CLI

1. Vì sao cần biết WP-CLI

WP-CLI là công cụ dòng lệnh quản trị WordPress — thay vì click chuột trong wp-admin, chạy lệnh trực tiếp. Cực kỳ quan trọng khi làm việc với deploy, automation, xử lý site lớn (thao tác hàng loạt mà làm tay trong UI sẽ rất chậm).

2. Các lệnh hay dùng nhất — nên thuộc

`bash
# Cài plugin
wp plugin install woocommerce –activate

# Update toàn bộ plugin
wp plugin update –all

# Export/Import database
wp db export backup.sql
wp db import backup.sql

# ⭐ Lệnh quan trọng nhất khi deploy/di chuyển site — đổi domain hàng loạt
wp search-replace ‘https://old-domain.com’ ‘https://new-domain.com’

# Chỉ xem trước, không thực sự đổi (an toàn khi test)
wp search-replace ‘https://old-domain.com’ ‘https://new-domain.com’ –dry-run

# Tạo user mới
wp user create john john@example.com –role=editor

# Xoá toàn bộ post trash
wp post delete $(wp post list –post_status=trash –format=ids) –force

# Kiểm tra thông tin core
wp core version
wp core update
`

3. Vì sao wp search-replace không phải chỉ là “tìm-thay chuỗi” đơn giản

Điểm hay bị hỏi: vì WordPress lưu dữ liệu serialize PHP trong DB (VD: theme settings, widget data dạng a:2:{s:4:"name";s:3:"abc";}), nếu bạn tìm-thay bằng lệnh SQL thô (UPDATE wpoptions SET optionvalue = REPLACE(...)), độ dài chuỗi serialize sẽ bị lệch (vì REPLACE không tự cập nhật lại con số độ dài trong chuỗi serialize) → làm hỏng dữ liệu, PHP không unserialize được nữa.

wp search-replace xử lý đúng vấn đề này — nó parse và tính lại độ dài chuỗi serialize chính xác trước khi ghi lại. Đây là lý do dev có kinh nghiệm luôn dùng wp search-replace thay vì tự viết SQL khi cần đổi domain hàng loạt.

4. WP-CLI trong CI/CD

WP-CLI thường được dùng trong script deploy tự động — VD: sau khi pull code mới lên server, chạy wp plugin update --all, wp cache flush, wp rewrite flush tự động thay vì làm tay.


PHẦN C: MULTISITE

1. Multisite là gì

Multisite (WordPress Network) cho phép 1 cài đặt WordPress duy nhất (1 codebase, 1 lần cài core) quản lý nhiều site cùng lúc — mỗi site có nội dung riêng nhưng dùng chung: file WordPress core, danh sách plugin/theme đã cài, và có thể chia sẻ user.

2. Kích hoạt (chỉ cần biết khái niệm, không cần thao tác tay)

`php
// wp-config.php
define( ‘WPALLOWMULTISITE’, true );
`
Sau đó vào Tools → Network Setup trong wp-admin để hoàn tất.

2 kiểu subsite:
– Subdomain: site1.example.com, site2.example.com
– Subdirectory: example.com/site1, example.com/site2

3. Cấu trúc DB thay đổi thế nào

Multisite thêm bảng mới: wpblogs, wpsite, wpsitemeta. Mỗi subsite có bộ bảng riêng với prefix số: wp2posts, wp2postmeta, wp3posts… (site đầu tiên vẫn dùng wpposts không có số). Bảng wpuserswpusermeta thì dùng chung cho toàn network — đây là điểm hay bị hỏi: “user có phải tạo lại cho từng site không?” → Không, user là chung network-wide, chỉ cần gán quyền (role) riêng cho từng site.

4. Khi nào nên dùng Multisite, khi nào KHÔNG nên — câu hỏi tư duy hay gặp

Nên dùng Multisite khi:
– Nhiều site có chung 1 tổ chức quản lý, cần cùng bộ plugin/theme, cùng đội ngũ quản trị (VD: hệ thống site cho các chi nhánh/phòng ban của 1 công ty, hoặc mạng lưới blog của 1 trường đại học cho từng khoa).
– Cần tiết kiệm chi phí quản lý hạ tầng — update core/plugin 1 lần áp dụng cho tất cả site.

KHÔNG nên dùng Multisite khi:
– Các site thuộc về khách hàng khác nhau, không liên quan nhau — vì Multisite là single point of failure: nếu network gặp sự cố (hack, lỗi core), TẤT CẢ site trong network bị ảnh hưởng cùng lúc.
– Các site cần plugin/theme rất khác nhau về phiên bản hoặc yêu cầu kỹ thuật riêng biệt — Multisite chia sẻ chung 1 bộ core/plugin, khó tách biệt hoàn toàn.
– Team không có kinh nghiệm vận hành Multisite — nó phức tạp hơn quản lý nhiều site độc lập ở một số khía cạnh (backup, migrate 1 site riêng lẻ ra khỏi network khó hơn).

Câu trả lời mẫu:
> “Em sẽ đề xuất Multisite khi khách hàng có nhu cầu quản lý tập trung nhiều site liên quan (VD: chuỗi cửa hàng, các chi nhánh), cần đồng bộ plugin/theme và có đội IT đủ kinh nghiệm vận hành. Nhưng nếu là các dự án độc lập cho nhiều khách hàng khác nhau, em sẽ tách site riêng để tránh rủi ro ‘một site sập kéo theo tất cả’, và dễ migrate/bàn giao riêng lẻ hơn.”


PHẦN D: THỰC HÀNH TAY

  1. Cài @wordpress/scripts, tạo 1 block tĩnh đơn giản (VD: block hiện 1 quote tuỳ chỉnh) — chỉ cần chạy được npm run build và thấy block hiện trong editor, kéo thả được.
  2. Cài WP-CLI (nếu local dev có sẵn — LocalWP/DevKinsta thường tích hợp sẵn), thử chạy wp post list, wp plugin list.
  3. Thử wp search-replace 'http://oldsite.local' 'http://newsite.local' --dry-run trên site test để xem output (không cần site thật đổi domain).
  4. Đọc thêm 1 bài viết ngắn về Multisite (không cần cài thật) để nắm chắc khái niệm — vì mảng này ít khi cần thực hành sâu, chủ yếu cần hiểu đúng để trả lời phỏng vấn.

PHẦN E: TỰ KIỂM TRA CUỐI NGÀY

  1. Gutenberg lưu dữ liệu block ở đâu, dưới hình thức nào? (Vẫn lưu trong postcontent, dưới dạng HTML kèm comment <!-- wp:... --> chứa tên block và attributes JSON)_
  2. Static Block và Dynamic Block khác nhau ở điểm nào, cho ví dụ khi nào chọn cái nào? (Static lưu HTML cứng lúc save; Dynamic render bằng PHP mỗi lần load — chọn Dynamic khi dữ liệu thay đổi theo thời gian)
  3. Vì sao không nên tự viết SQL REPLACE để đổi domain hàng loạt, mà phải dùng wp search-replace? (Dữ liệu serialize PHP có độ dài chuỗi ghi cứng trong nó, REPLACE thô sẽ làm lệch độ dài, hỏng dữ liệu)
  4. Trong Multisite, bảng nào dùng chung toàn network, bảng nào tách riêng theo từng site? (wpusers/wpusermeta dùng chung; wpposts/wppostmeta… tách riêng theo prefix số)
  5. Kể 1 lý do chính đáng để KHÔNG chọn Multisite dù khách hàng có nhiều site. (Single point of failure — 1 site gặp sự cố ảnh hưởng cả network; hoặc các site cần yêu cầu kỹ thuật khác biệt nhau)
📝 2,538 từ 📅 14/07/2026 👁 5 lượt đọc
← Chương Trước Chương Tiếp →
Giáo trình ôn tập WordPress bài bản + Vibe Coding

Giáo trình ôn tập WordPress bài bản + Vibe Coding

Tác giả: Giang Thanh Nhon

Trạng thái: Đang tiến hành

Số chương: 7

Đánh giá: ⭐ 10/10

💬 Bình luận (0)

Hãy là người đầu tiên bình luận về chương này!