Nếu website WordPress của bạn có hàng chục nghìn hoặc hàng trăm nghìn user, chắc chắn bạn sẽ gặp tình trạng trang quản trị (Admin) load chậm bất thường, đặc biệt ở khu vực “Người dùng” (Users) hoặc trang tổng quan (Dashboard).
Nguyên nhân chính đến từ hàm count_users()
– đây là hàm WordPress dùng để đếm số lượng người dùng theo vai trò (role).
Tuy nhiên, hàm này sinh ra một truy vấn SQL cực kỳ nặng, dùng nhiều biểu thức LIKE '%"role"%'
trên bảng wp_usermeta
.
Ví dụ một truy vấn mặc định của WordPress:
SELECT COUNT(NULLIF(`meta_value` LIKE '%\"administrator\"%', false)), COUNT(NULLIF(`meta_value` LIKE '%\"editor\"%', false)), COUNT(NULLIF(`meta_value` LIKE '%\"author\"%', false)), COUNT(NULLIF(`meta_value` LIKE '%\"contributor\"%', false)), COUNT(NULLIF(`meta_value` LIKE '%\"subscriber\"%', false)), COUNT(NULLIF(`meta_value` = 'a:0:{}', false)), COUNT(*) FROM wp_usermeta INNER JOIN wp_users ON user_id = ID WHERE meta_key = 'wp_capabilities';
Truy vấn này đọc toàn bộ bảng wp_usermeta
và so sánh chuỗi dạng serialize (ví dụ: "a:1:{s:13:\"administrator\";b:1;}"
), dẫn đến CPU cao, RAM tăng, và MySQL bị chậm rõ rệt.
count_users()
May mắn là WordPress đã cung cấp sẵn một filter nội bộ tên là pre_count_users
.
Nếu filter này trả về một giá trị khác null
, WordPress sẽ không chạy truy vấn SQL mặc định nữa.
Thêm đoạn code dưới đây vào file functions.php
(trong theme) hoặc plugin riêng của bạn:
add_filter('pre_count_users', function($result, $strategy) { return [ 'total_users' => 0, 'avail_roles' => [], ]; }, 10, 2);
Hoặc đơn giản hơn nếu bạn chỉ muốn tắt mà không quan tâm kết quả:
add_filter('pre_count_users', '__return_empty_array');
✅ Kết quả:
Bạn nên tắt hàm count_users()
trong các trường hợp sau:
wp_usermeta
có kích thước vài trăm MB.Nếu bạn vẫn muốn hiển thị số lượng user thật, nhưng không muốn query nặng mỗi lần load admin, bạn có thể cache kết quả đếm này 1 lần/ngày bằng transient
:
add_filter('pre_count_users', function() { $cache = get_transient('cached_count_users'); if ($cache !== false) { return $cache; } global $wpdb; $result = [ 'total_users' => (int) $wpdb->get_var("SELECT COUNT(ID) FROM {$wpdb->users}"), 'avail_roles' => [], ]; set_transient('cached_count_users', $result, DAY_IN_SECONDS); return $result; });
Cách này giúp bạn vẫn có số liệu thống kê cơ bản, nhưng chỉ đếm một lần mỗi 24 giờ.
Hàm count_users()
là một trong những “thủ phạm ẩn” khiến WordPress admin bị chậm khi có nhiều người dùng.
Bằng cách tắt hoặc ghi đè filter pre_count_users
, bạn có thể loại bỏ hoàn toàn truy vấn SQL nặng nề với LIKE '%"administrator"%'
, giúp hệ thống nhẹ hơn, mượt hơn và ổn định hơn nhiều.
Mục tiêu | Cách làm | Code |
---|---|---|
Tắt hoàn toàn truy vấn count_users() | Hook pre_count_users | add_filter('pre_count_users', '__return_empty_array'); |
Ghi đè kết quả trả về (0 user) | Trả về mảng trống | return ['total_users'=>0,'avail_roles'=>[]]; |
Cache kết quả thật 1 lần/ngày | Dùng set_transient() | Xem ví dụ trên |