Bài viết phình gấp 9 lần lúc hiển thị, kho dữ liệu vẫn sạch

Ảnh bìa: bài viết phình gấp 9 lần lúc hiển thị trong khi kho dữ liệu vẫn sạch

Bài viết do Nguyễn Nhật Ánh Dương thực hiện, biên soạn theo Chính sách nội dung của Marketing365. Cập nhật lần cuối .

Nội dung
  1. 23 nghìn chữ trong kho, 206 nghìn chữ trên trang
  2. Ba cách đo đầu tiên đều cho danh sách sai
  3. Cách đo còn lại sau khi ba cách kia bị bác
  4. Thủ phạm: những dấu đóng khối thiếu dấu mở
  5. Vá xong mới lộ tầng thứ hai
  6. Đo lại hôm nay, và chỗ tôi còn nợ

Có một loại lỗi khó chịu hơn lỗi làm sập trang: lỗi mà chỗ nào bạn kiểm tra cũng thấy sạch, chỉ người đọc mới thấy hỏng. Đây là ghi chép một lần như vậy trên marketing365.vn — bài viết bị nhân bản gấp chín lần, nhưng nội dung lưu trong kho dữ liệu thì đúng một bản, không thừa một chữ.

Ảnh bìa: bài viết phình gấp 9 lần lúc hiển thị trong khi kho dữ liệu vẫn sạch
Ảnh bìa bài viết. Số liệu bên trong ảnh lấy từ nhật ký thao tác ngày 10/08/2026 và lần đo lại ngày 14/08/2026 trên marketing365.vn.

23 nghìn chữ trong kho, 206 nghìn chữ trên trang

Tôi phát hiện ra do đếm nhầm chỗ. Đang thống kê số mục trong mỗi bài, tôi đếm trên trang thật thay vì đếm trong nội dung lưu. Một bài trả về số mục gấp chín lần con số tôi biết chắc là đúng.

Kiểm lại từng lớp thì mọi lớp đều sạch. Đọc thẳng nội dung bài trong kho dữ liệu: một bản, đúng số mục. Gọi hàm dựng khối bằng dòng lệnh: cũng ra đúng bấy nhiêu chữ. Nhưng mở trang bằng trình duyệt thì phần thân bài dài 206 nghìn chữ, trong khi bản gốc chỉ 23 nghìn.

Đây là chỗ tôi mất nhiều thời gian nhất: cứ tìm trong kho dữ liệu thì không bao giờ thấy, vì trong kho không có gì để thấy. Nội dung bị nhân lên ngay lúc trang được dựng ra, rồi biến mất khi trang đóng.

Muốn nhìn thấy nó bằng dòng lệnh thì phải giả lập đúng ngữ cảnh một trang bài đơn, chứ chạy trần không tái hiện được:

# dựng đúng ngữ cảnh trang bài đơn rồi mới chạy chuỗi lọc nội dung
$q = new WP_Query(['p' => $id, 'post_type' => 'post', 'posts_per_page' => 1]);
$GLOBALS['wp_query'] = $q; $GLOBALS['wp_the_query'] = $q;
$q->is_single = $q->is_singular = true; $q->is_home = false;
$q->the_post();

apply_filters('the_content', $content);   # chạy trần thì sạch, chạy thế này mới phình

Ba cách đo đầu tiên đều cho danh sách sai

Biết một bài hỏng là một chuyện. Biết còn bao nhiêu bài nữa hỏng là chuyện khác, và tôi đã đo sai ba lần trước khi đo đúng.

Lần một: tôi tưởng chỉ cần đọc bài lên, dựng lại cấu trúc khối rồi ghi đè xuống là hệ thống tự chuẩn hoá. Không. Cách ghi lại ấy giữ nguyên chỗ lệch, bài nặng nhất vẫn phình gấp 8,8 lần. Một tiếng đồng hồ cho một giả định chưa kiểm.

Lần hai: đếm số tiêu đề mục hiển thị trên trang, bài nào gấp từ hai lần số mục gốc trở lên thì coi là hỏng. Cách này trả về 64 bài. Sai, vì giao diện luôn cộng thêm bốn tiêu đề của khối bài liên quan ở cuối trang. Bài nào chỉ có bốn mục thì hiển thị thành tám — gấp đúng hai lần, và bị bắt nhầm.

Lần ba: đếm xem tiêu đề mục đầu tiên của bài xuất hiện bao nhiêu lần trên trang, từ ba lần trở lên thì coi là hỏng. Cách này trả về khoảng 240 bài. Cũng sai, và sai còn nặng hơn: một tiêu đề bình thường vốn đã xuất hiện ba đến bốn lần trên trang — một lần ở mục lục, một lần ở thẻ tiêu đề thật, một lần trong phần mô tả ảnh, một lần ở dòng chú thích dưới ảnh.

Điểm chung của cả ba: chúng đều đếm một thứ mà giao diện có quyền tự thêm vào. Đếm thứ mình không kiểm soát thì con số ra được là con số của giao diện, không phải của bài. Tôi từng dính đúng kiểu này ở một vụ khác, khi đoán sai nguồn gây giật layout bốn lần liền.

Cách đo còn lại sau khi ba cách kia bị bác

Bảng bốn cách đo và kết quả quét lại toàn site ngày 14/08/2026
Đo cái gì: tỉ lệ giữa số chữ hiển thị trên trang và số chữ trong nội dung gốc. Phần “đã thử” lấy từ nhật ký thao tác ngày 10/08/2026; phần “đo lại” chạy trực tiếp trên toàn bộ bài đã đăng của marketing365.vn ngày 14/08/2026.

Cách chạy được là bỏ hết mọi thứ đếm được, chỉ lấy một tỉ lệ: số chữ hiển thị chia cho số chữ gốc.

Tỉ lệ này ở bài bình thường quanh 1,1 — phần dôi ra là mục lục và khối bài liên quan, tức là phần giao diện thêm vào, và nó thêm đều ở mọi bài. Bài bị nhân bản thì tỉ lệ vọt lên 4 đến 9. Khoảng trống giữa 1,1 và 4 rộng đến mức chọn ngưỡng ở đâu cũng được; tôi chọn 1,6.

Quét toàn bộ bài đã đăng bằng ngưỡng đó, kết quả ra đúng bốn bài. Không sót bài nào, không bắt nhầm bài nào — đối chiếu tay từng bài trong danh sách thì cả bốn đều hỏng thật.

So sánh: cách đo thứ hai cho 64 bài, cách thứ ba cho 240 bài, cách thứ tư cho 4 bài. Cùng một site, cùng một ngày.

Thủ phạm: những dấu đóng khối thiếu dấu mở

Nội dung bài trong WordPress được đánh dấu bằng các cặp dấu mở và đóng ẩn trong nội dung, mỗi khối một cặp. Bài nặng nhất có 24 dấu mở khối danh sách nhưng chỉ 11 dấu đóng.

Lúc dựng trang, WordPress chạy qua một chuỗi bộ lọc nội dung. Có một bước trong đó đọc lại cấu trúc khối rồi ghi ra lại. Gặp cấu trúc lệch, bước này không báo lỗi — nó ghi ra một bản dài hơn bản vào. Bài đi qua vài vòng như vậy thì thành gấp chín lần.

Cách vá ngắn đến mức đáng ngờ: xoá sạch các dấu đánh khối trong nội dung bốn bài đó.

preg_replace('/<!--\s*\/?wp:[^>]*?-->/s', '', $content)

Sau khi vá, tỉ lệ về 1,05 đến 1,08. Chữ hiển thị không đổi một ký tự nào, số đoạn văn, số danh sách, số ảnh, số tiêu đề mục giữ nguyên. Người đọc không thấy khác gì, ngoài việc bài không còn lặp.

Một chi tiết tôi kiểm sau và mừng vì đã kiểm: lỗi này có từ trước, không phải do thao tác của tôi hôm ấy. Dựng lại từng bản lưu cũ của bài rồi đo, một bài đã phình gấp 4 từ 24/06, một bài gấp 6,2 từ 10/07. Nếu không kiểm bản lưu cũ, tôi đã kết luận sai là mình vừa làm hỏng.

Vá xong mới lộ tầng thứ hai

Bỏ lớp nhân bản lúc hiển thị đi thì lộ ra lớp bên dưới: cả bốn bài còn khối hỏi đáp lặp nguyên văn hai đến năm lần ngay trong nội dung gốc. Đây đúng là loại lỗi tôi đã dọn một đợt trước đó và tưởng đã sạch — chuyện đó tôi kể riêng ở bài 43 bài tự chép lại chính mình, một bài lặp 5 lần. Bốn bài này lọt lưới vì lớp nhân bản lúc hiển thị che mất.

Dọn ba bài thì gọn: bớt lần lượt 3.725, 4.628 và 2.556 chữ. Bài thứ tư tôi dừng lại có chủ đích. Dọn xong thì nó chỉ còn khoảng 45% chữ so với trước, thành một bài mỏng dính. Cái nó cần không phải là cắt, mà là viết bù. Cắt cho sạch số liệu rồi để lại một bài rỗng thì là làm đẹp bảng thống kê, không phải làm tốt cho người đọc.

Đo lại hôm nay, và chỗ tôi còn nợ

Ngày 14/08/2026, trước khi viết bài này, tôi chạy lại phép đo trên toàn bộ 1.633 bài đã đăng:

  • Tỉ lệ trung bình: 1,144. Đúng như dự đoán về phần giao diện tự thêm.
  • Bốn bài đã vá: 1,06 đến 1,09. Bản vá giữ được sau bốn ngày.
  • Số bài vượt ngưỡng 1,6: đúng một bài, tỉ lệ 1,80. Là bài đăng ngày 12/08, cùng bài đang bị lặp nội dung mà tôi nhắc ở trên.

Và một con số tôi không thích: quét dấu đánh khối trong 1.633 bài đó, có 57 bài đang thiếu đúng một dấu mở, hầu hết ở phần nguồn tham khảo cuối bài, tất cả đều đăng từ 27/07 trở đi. Tức là quy trình tự động vẫn đang sinh ra nội dung lệch dấu, tôi mới chỉ dọn hậu quả chứ chưa chặn được đầu nguồn.

Điều thú vị là 57 bài đó đo ra 1,14 đến 1,19 — hiển thị vẫn bình thường. Nghĩa là lệch dấu là điều kiện cần chứ chưa phải điều kiện đủ để bài phình ra; phải lệch đúng kiểu, đúng chỗ thì mới nổ. Tôi chưa biết ranh giới đó nằm ở đâu, và ghi ra đây đúng như vậy thay vì đoán một câu kết luận nghe cho gọn.

Ba thứ tôi mang đi khỏi vụ này:

  • Kiểm ở đúng nơi người đọc nhìn. Kho dữ liệu sạch không có nghĩa là trang sạch.
  • Đừng đếm thứ mà giao diện có quyền tự thêm vào. Ba cách đo đầu của tôi hỏng vì đúng lý do đó.
  • Trước khi nhận lỗi do mình vừa gây ra, kiểm bản lưu cũ. Lần này lỗi có từ trước đó cả tháng rưỡi.

Số trong bài này đo trên marketing365.vn, ngày nào thì ghi ngay cạnh số. Con số 1.633 bài và tỉ lệ 1,144 là của ngày 14/08/2026 — đo lại vào lúc khác sẽ ra khác, vì site vẫn đăng bài mỗi ngày.

Có thể bạn thích

Để lại bình luận