在 LearnDash 課程列表新增已報名學生數欄位並優化查詢效能

前言

這段程式碼主要解決 LearnDash 後台課程列表無法直接查看每門課程已報名學生數的問題。對於管理大量課程與學員的教學平台管理員來說,快速掌握報名狀況非常重要。本文適合熟悉 WordPress 與 LearnDash 且想自訂後台介面與效能優化的工程師或自學者。

新增自訂欄位到課程列表

透過 WordPress 提供的 manage_edit-{$post_type}_columns 過濾器,我們在 sfwd-courses(LearnDash 課程)後台列表中插入一個「已報名學生」欄位。此欄位被放置在標題欄位後面,方便管理者一目了然。

add_filter('manage_edit-sfwd-courses_columns', function ($columns) {
    $new = [];
    foreach ($columns as $k => $v) {
        $new[$k] = $v;
        if ($k === 'title') {
            $new['ld_enrolled_count'] = '已報名學生';
        }
    }
    if (!isset($new['ld_enrolled_count'])) {
        $new['ld_enrolled_count'] = '已報名學生';
    }
    return $new;
}, 20);

顯示欄位內容與計數邏輯

使用 manage_sfwd-courses_posts_custom_column 動作鉤子,根據課程 ID 呼叫自訂函式取得報名學生數並輸出。計數邏輯透過 WP_UserQuery 查詢所有有 usermeta 中 `course{course_id}_access_from` 欄位存在的使用者數量,這是 LearnDash 判斷學員是否有課程存取權的標準做法。

add_action('manage_sfwd-courses_posts_custom_column', function ($column, $post_id) {
    if ($column !== 'ld_enrolled_count')
        return;

    $count = vs_ld_get_enrolled_count($post_id);

    echo esc_html((string) $count);
}, 10, 2);

快取機制提升效能

為避免課程列表頁面每筆課程都執行重複且昂貴的資料庫查詢,使用 WordPress 內建快取(wp_cache)暫存結果 10 分鐘。這樣可以大幅減少對資料庫的負擔,避免後台卡頓。

function vs_ld_get_enrolled_count($course_id)
{
    $course_id = (int) $course_id;
    if ($course_id <= 0)
        return 0;

    $cache_key = 'course_enrolled_' . $course_id;
    $cached = wp_cache_get($cache_key, 'ld_course_enroll_count');
    if ($cached !== false) {
        return (int) $cached;
    }

    $meta_key = 'course_' . $course_id . '_access_from';

    $uq = new WP_User_Query([
        'fields' => 'ID',
        'number' => 1,
        'paged' => 1,
        'count_total' => true,
        'meta_query' => [
            [
                'key' => $meta_key,
                'compare' => 'EXISTS',
            ],
        ],
    ]);

    $count = (int) $uq->get_total();

    wp_cache_set($cache_key, $count, 'ld_course_enroll_count', 10 * MINUTE_IN_SECONDS);

    return $count;
}

課程更新時清除快取

為確保報名數字不會因快取而過時,當課程內容被更新時,會自動刪除對應快取,讓下一次查詢能取得最新資料。

add_action('save_post_sfwd-courses', function ($post_id) {
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)
        return;
    $post_id = (int) $post_id;
    wp_cache_delete('course_enrolled_' . $post_id, 'ld_course_enroll_count');
}, 20);

實務應用與延伸

這種方式適合需要在 LearnDash 後台快速掌握各課程報名狀況的管理者,尤其是課程數量龐大時,快取機制可有效減少資料庫負擔。未來可延伸加入排序功能,或結合 AJAX 即時更新報名數,提升使用體驗。

常見問題與注意事項

  • 快取時間設定過短會增加資料庫查詢頻率,過長可能導致數據不即時,需依實際需求調整。
  • 使用 WP_User_Query 查詢大量用戶時,仍需注意資料庫效能,建議搭配適當索引。
  • 本範例假設 LearnDash 使用標準 usermeta key,若有自訂存取邏輯需調整查詢條件。

完整程式碼

<?php
if (!defined('ABSPATH'))
    exit;

/**
 * LearnDash:後台課程清單新增「已報名學生數」欄位
 * - post_type: sfwd-courses
 * - 計數依據:usermeta key = course_{course_id}_access_from EXISTS
 * - 有短暫快取,避免清單頁卡爆
 */

/** 1) 加欄位 */
add_filter('manage_edit-sfwd-courses_columns', function ($columns) {
    // 插在標題後面(你也可以改位置)
    $new = [];
    foreach ($columns as $k => $v) {
        $new[$k] = $v;
        if ($k === 'title') {
            $new['ld_enrolled_count'] = '已報名學生';
        }
    }
    if (!isset($new['ld_enrolled_count'])) {
        $new['ld_enrolled_count'] = '已報名學生';
    }
    return $new;
}, 20);

/** 2) 顯示欄位內容 */
add_action('manage_sfwd-courses_posts_custom_column', function ($column, $post_id) {
    if ($column !== 'ld_enrolled_count')
        return;

    $count = vs_ld_get_enrolled_count($post_id);

    echo esc_html((string) $count);
}, 10, 2);

/** 3) 計數函式(含快取) */
function vs_ld_get_enrolled_count($course_id)
{
    $course_id = (int) $course_id;
    if ($course_id <= 0)
        return 0;

    // 快取 10 分鐘(避免列表頁每一列都打一次 users table)
    $cache_key = 'course_enrolled_' . $course_id;
    $cached = wp_cache_get($cache_key, 'ld_course_enroll_count');
    if ($cached !== false) {
        return (int) $cached;
    }

    // LearnDash 最常用的課程存取 key
    $meta_key = 'course_' . $course_id . '_access_from';

    // 用 WP_User_Query 計數 meta_key EXISTS 的使用者
    $uq = new WP_User_Query([
        'fields' => 'ID',
        'number' => 1,        // 只要 count_total,不要真的撈一堆 ID
        'paged' => 1,
        'count_total' => true,
        'meta_query' => [
            [
                'key' => $meta_key,
                'compare' => 'EXISTS',
            ],
        ],
    ]);

    $count = (int) $uq->get_total();

    wp_cache_set($cache_key, $count, 'ld_course_enroll_count', 10 * MINUTE_IN_SECONDS);

    return $count;
}

/** 4) 當課程更新時,清掉該課程快取(避免顯示太久舊數字) */
add_action('save_post_sfwd-courses', function ($post_id) {
    if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE)
        return;
    $post_id = (int) $post_id;
    wp_cache_delete('course_enrolled_' . $post_id, 'ld_course_enroll_count');
}, 20);