Giới thiệu

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.


Giải pháp: Tắt hoàn toàn truy vấn trong 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.

🔧 Cách thực hiện

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ả:

  • Truy vấn SQL nặng sẽ không bao giờ chạy nữa.
  • Trang admin “Users” và “Dashboard” load nhanh hơn rõ rệt.
  • Không ảnh hưởng đến đăng nhập, quyền hạn, hay thao tác khác của user.

Khi nào nên dùng cách này?

Bạn nên tắt hàm count_users() trong các trường hợp sau:

  • Website có nhiều user (trên 5.000 tài khoản).
  • Bảng wp_usermeta có kích thước vài trăm MB.
  • Bạn không cần hiển thị số lượng người dùng theo vai trò trong Dashboard.
  • Bạn muốn giảm tải cho MySQL và tăng tốc độ phản hồi trong admin.

Tùy chọn nâng cao: Cache kết quả đếm user

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ờ.


Kết luận

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.


💡 Tóm tắt nhanh

Mục tiêuCách làmCode
Tắt hoàn toàn truy vấn count_users()Hook pre_count_usersadd_filter('pre_count_users', '__return_empty_array');
Ghi đè kết quả trả về (0 user)Trả về mảng trốngreturn ['total_users'=>0,'avail_roles'=>[]];
Cache kết quả thật 1 lần/ngàyDùng set_transient()Xem ví dụ trên