2026年6月19日

2026年6月19日

LearnDashのエラーを解決する方法

はじめに

LearnDashでレッスンを完了しても進捗率が更新されない・クイズを送信しても採点結果が表示されずフリーズする・コース修了条件をすべて満たしているのに修了証が発行されない・コースへのアクセス制限が機能せず未購入ユーザーがコンテンツを閲覧できるといった問題は、データベースの進捗テーブル・クイズ設定・アクセス制限フックの設定が原因です。

症状・原因

  • レッスンの「完了」ボタンを押しても翌日には進捗がリセットされている
  • クイズ送信ボタンを押すとぐるぐるローディングのまま何も起きない
  • すべてのレッスン・クイズを完了したが「コースを修了する」ボタンが表示されない
  • WooCommerceで購入済みのコースに「アクセスが制限されています」と表示されてしまう

解決手順

ステップ1:LearnDashの状態を確認する

# LearnDashの設定確認
wp eval "
if (defined('LEARNDASH_VERSION')) {
    echo 'LearnDash version: ' . LEARNDASH_VERSION . PHP_EOL;
}

// コース一覧を確認
\$courses = get_posts([
    'post_type'      => 'sfwd-courses',
    'post_status'    => 'publish',
    'posts_per_page' => 10,
]);

echo 'Published courses: ' . count(\$courses) . PHP_EOL;

foreach (\$courses as \$course) {
    \$lessons = learndash_get_course_lessons_list(\$course->ID);
    \$quizzes = learndash_get_course_quiz_list(\$course->ID);
    printf('  #%d: %s | Lessons: %d | Quizzes: %d' . PHP_EOL,
        \$course->ID,
        \$course->post_title,
        count(\$lessons),
        count(\$quizzes)
    );
}

// ユーザー進捗確認
\$user_id = 2; // 確認するユーザーID
\$course_id = 10; // 確認するコースID
\$progress = learndash_user_get_course_progress(\$user_id, \$course_id);
echo 'User #' . \$user_id . ' progress on course #' . \$course_id . ':' . PHP_EOL;
echo '  Completed steps: '    . (\$progress['completed'] ?? 0) . PHP_EOL;
echo '  Total steps: '        . (\$progress['total'] ?? 0) . PHP_EOL;
echo '  Status: '             . (\$progress['status'] ?? 'not started') . PHP_EOL;
"

ステップ2:コース進捗管理をカスタマイズする

// functions.php: LearnDash進捗管理

// ① レッスン完了時にカスタム処理を実行
add_action('learndash_lesson_completed', function(array $data): void {
    $user_id   = $data['user']->ID;
    $lesson_id = $data['lesson']->ID;
    $course_id = $data['course']->ID;

    // 完了時刻を記録
    update_user_meta($user_id, '_ld_lesson_' . $lesson_id . '_completed_at', current_time('mysql'));

    // 進捗率を計算してメタ更新
    $progress = learndash_user_get_course_progress($user_id, $course_id);
    $pct = $progress['total'] > 0
        ? round($progress['completed'] / $progress['total'] * 100)
        : 0;
    update_user_meta($user_id, '_ld_course_' . $course_id . '_progress_pct', $pct);

    error_log(sprintf('[LD] User #%d completed lesson #%d (%d%% of course #%d)',
        $user_id, $lesson_id, $pct, $course_id));
});

// ② コース修了時の処理
add_action('learndash_course_completed', function(array $data): void {
    $user_id   = $data['user']->ID;
    $course_id = $data['course']->ID;

    // 修了証メールを送信
    $user = get_userdata($user_id);
    wp_mail(
        $user->user_email,
        sprintf('[%s] コース修了おめでとうございます!', get_bloginfo('name')),
        sprintf("こんにちは %s さん、\n\n「%s」の修了おめでとうございます!\n\n修了証はこちらからダウンロードできます。",
            $user->display_name,
            get_the_title($course_id)
        )
    );

    // 修了証に関連するカスタムロールを付与
    $wp_user = new WP_User($user_id);
    $wp_user->add_role('course_graduate');

    error_log(sprintf('[LD] User #%d completed course #%d', $user_id, $course_id));
});

// ③ 進捗が保存されない問題のデバッグ
add_action('learndash_user_course_status_changed', function(int $user_id, int $course_id, string $old, string $new): void {
    error_log(sprintf('[LD] Status change: user #%d course #%d: %s -> %s', $user_id, $course_id, $old, $new));
}, 10, 4);

ステップ3:クイズ設定を修正する

// functions.php: クイズ設定

// ① クイズ完了時の処理
add_action('learndash_quiz_completed', function(array $data, WP_User $user): void {
    $quiz_id    = $data['quiz']->ID;
    $course_id  = $data['course']->ID;
    $score      = $data['pass'] ? '合格' : '不合格';
    $percentage = round($data['percentage'] ?? 0);

    error_log(sprintf('[LD] Quiz #%d: user #%d scored %d%% (%s)',
        $quiz_id, $user->ID, $percentage, $score));

    // 不合格の場合はリトライメールを送信
    if (!$data['pass']) {
        wp_mail(
            $user->user_email,
            sprintf('[%s] クイズ再挑戦のご案内', get_bloginfo('name')),
            sprintf("今回は%d%%でした(合格ライン未達)。\n\n再度挑戦して合格を目指しましょう!", $percentage)
        );
    }
}, 10, 2);

// ② クイズの制限時間を動的に設定
add_filter('learndash_quiz_time_limit', function(int $time_limit, int $quiz_id): int {
    // 上級クイズは90分に設定
    if (get_post_meta($quiz_id, '_ld_quiz_level', true) === 'advanced') {
        return 5400; // 90分(秒)
    }
    return $time_limit;
}, 10, 2);

// ③ クイズのランダム出題を有効化
add_filter('learndash_quiz_questions_random', function(bool $random, int $quiz_id): bool {
    // 本番クイズは必ずランダム出題
    if (get_post_meta($quiz_id, '_ld_quiz_type', true) === 'final') {
        return true;
    }
    return $random;
}, 10, 2);

ステップ4:修了証の発行を修正する

# 修了証テンプレートと発行状況を確認
wp eval "
// 修了証テンプレートを確認
\$certificates = get_posts([
    'post_type'      => 'sfwd-certificates',
    'post_status'    => 'publish',
    'posts_per_page' => 10,
]);

echo 'Certificate templates: ' . count(\$certificates) . PHP_EOL;

foreach (\$certificates as \$cert) {
    printf('  #%d: %s' . PHP_EOL, \$cert->ID, \$cert->post_title);
}

// 特定ユーザーの修了証発行状況を確認
\$user_id = 2;
\$course_id = 10;

\$cert_link = learndash_get_course_certificate_link(\$course_id, \$user_id);
echo 'Certificate link for user #' . \$user_id . ': ' . (\$cert_link ?: 'not available') . PHP_EOL;

// コースの完了要件を確認
\$course_meta = get_post_meta(\$course_id, '_sfwd-courses', true);
echo 'Certificate ID: '         . (\$course_meta['sfwd-courses_certificate'] ?? 'not set') . PHP_EOL;
echo 'Completion button: '      . (\$course_meta['sfwd-courses_button_complete'] ?? 'default') . PHP_EOL;
echo 'Min percentage: '         . (\$course_meta['sfwd-courses_course_min_percentage'] ?? 0) . '%' . PHP_EOL;
"

ステップ5:コースアクセス制限を修正する

// functions.php: アクセス制限

// ① WooCommerce購入後のコースアクセスを設定
add_action('woocommerce_order_status_completed', function(int $order_id): void {
    $order = wc_get_order($order_id);
    if (!$order) return;

    foreach ($order->get_items() as $item) {
        $product_id = $item->get_product_id();
        // 商品に紐付いたコースIDを取得
        $course_ids = get_post_meta($product_id, '_ld_course_ids', true);
        if (empty($course_ids)) continue;

        $user_id = $order->get_customer_id();
        foreach ((array) $course_ids as $course_id) {
            // コースへのアクセスを付与
            ld_update_course_access($user_id, $course_id);
            error_log(sprintf('[LD] Course #%d access granted to user #%d via order #%d',
                $course_id, $user_id, $order_id));
        }
    }
});

// ② 期限付きコースアクセスを設定
add_filter('ld_course_access_expires_at', function(int $access_expires, int $user_id, int $course_id): int {
    // コースの標準アクセス期間は180日
    $enrolled_at = (int) get_user_meta($user_id, 'course_' . $course_id . '_access_from', true);
    if ($enrolled_at > 0) {
        return $enrolled_at + (180 * DAY_IN_SECONDS);
    }
    return $access_expires;
}, 10, 3);

注意事項

  • LearnDashの進捗データが保存されない場合はwp_usermetaテーブルのcourse_completedlearndash_course_progressメタキーを確認してください。データが重複または破損している場合はlearndash_user_get_course_progress()が誤った値を返すことがあります
  • クイズのフリーズはJavaScriptの競合が原因のことが多いです。ブラウザのコンソールでエラーを確認し、wp_dequeue_script()で競合スクリプトを特定してください。テーマのスクリプトと競合している場合はLearnDashのレッスンページではテーマのJSを無効化する設定が有効です
  • WooCommerceとLearnDashの連携には公式の「LearnDash WooCommerce Integration」プラグインが必要です。手動でコースアクセスを付与する場合はld_update_course_access()関数を使用してください

まとめ

LearnDash修復は①learndash_user_get_course_progress()でコース別進捗・完了ステップ数を確認、②learndash_lesson_completedフックで完了時刻記録・進捗率更新・learndash_course_completedフックで修了証メール送信・ロール付与、③learndash_quiz_completedフックでスコア記録・不合格時リマインダーメール・learndash_quiz_time_limitフィルターで制限時間設定、④learndash_get_course_certificate_link()で修了証発行状況確認・コース完了要件(修了証ID・最低点)を確認、⑤woocommerce_order_status_completedフックでld_update_course_access()によるコースアクセス付与・ld_course_access_expires_atフィルターで期限設定する手順で解決します。

お気軽にご相談ください

お見積りへ お問い合わせへ