Changing the LearnDash redirect no access users hit takes one filter: learndash_access_redirect. When someone without access opens a lesson, topic or quiz, LearnDash sends them to the course page by default; your callback receives that URL and the post ID and returns a different one, such as a sales page or the login screen. For logged-out visitors who submit a free course's enrolment form, the separate learndash_course_join_redirect filter controls where they go instead of the WordPress login page.
This snippet guide shows both filters, when each one fires and what trips people up. Checked against the LearnDash 4.18.0.1 source and the LearnDash developer hook reference (October 2026). LearnDash 5.x is current; both filters date from the 2.x era and are still listed in the official hook reference, but test on your own version.
When LearnDash redirects users without access
On the template_redirect action, LearnDash checks single lesson, topic and quiz pages (the "course steps" post types). If sfwd_lms_has_access() returns false for the current user, sfwd_lms_access_redirect() builds the course permalink, passes it through learndash_access_redirect and redirects with learndash_safe_redirect(), which uses wp_safe_redirect() by default and exits.
Some users never hit the redirect because the access check passes for them:
- Lessons marked as a sample lesson.
- Courses with the Open access mode, and Buy now courses with no price set.
- Administrators, and Group Leaders, when auto-enrolment is enabled for them in LearnDash settings.
The course page itself is never redirected by this filter; it shows the enrolment button instead. So always test as a non-enrolled subscriber in a private window, not as an admin.
Snippet 1: send users without access somewhere else
This version sends logged-out visitors to the login screen and back to the step they asked for, and sends logged-in but non-enrolled users to a sales page you map per course. Anything not mapped keeps LearnDash's default. Add it to a small site plugin or your child theme's functions.php. Not run on a live site; test on staging first.
<?php
/**
* Change where LearnDash sends users without course access.
*/
add_filter( 'learndash_access_redirect', 'aiol_ld_no_access_redirect', 10, 2 );
function aiol_ld_no_access_redirect( $link, $post_id ) {
$post_id = absint( $post_id );
// Logged out: log in, then return to the requested lesson, topic or quiz.
if ( ! is_user_logged_in() ) {
return wp_login_url( get_permalink( $post_id ) );
}
// Logged in but not enrolled: per-course sales page.
$course_id = absint( learndash_get_course_id( $post_id ) );
$sales_pages = array(
123 => 456, // Course ID => sales page ID. Replace with your own.
);
if ( isset( $sales_pages[ $course_id ] ) ) {
$url = get_permalink( $sales_pages[ $course_id ] );
if ( $url ) {
return add_query_arg( 'ld_course', $course_id, $url );
}
}
return $link; // Default: the course page.
}
A few notes on the code:
learndash_get_course_id()resolves the course from the lesson, topic or quiz, which is the same call LearnDash uses to build its default link.- The
ld_coursequery argument lets the sales page show "You need to enrol in this course" text. Sanitise it withabsint()wherever you read it. - Returning an empty string skips the redirect entirely, because LearnDash only redirects when the link is not empty. The user then stays on the step page and LearnDash's normal content handling applies. Check what your theme shows before relying on it.
Redirecting to another domain
Because the redirect goes through wp_safe_redirect(), a URL on an external host (a separate shop or marketing site) is replaced with the admin URL unless the host is allowed. Allow it with the core allowed_redirect_hosts filter:
add_filter( 'allowed_redirect_hosts', 'aiol_allow_shop_host' );
function aiol_allow_shop_host( $hosts ) {
$hosts[] = 'shop.example.com';
return $hosts;
}
Keep the list to hosts you control. Not run on a live site; test on staging first.
Snippet 2: logged-out users who click Join
A different flow covers free courses. When a logged-out visitor submits the enrolment form, learndash_process_course_join() sends them to wp_login_url() with the course as the return address. The URL passes through learndash_course_join_redirect (groups use learndash_group_join_redirect; both come from the dynamic learndash_{$post_label_prefix}_join_redirect). This sends them to a custom registration page instead:
add_filter( 'learndash_course_join_redirect', 'aiol_ld_join_redirect', 10, 2 );
function aiol_ld_join_redirect( $login_url, $course_id ) {
$register = get_page_by_path( 'register' ); // Your registration page slug.
if ( ! $register ) {
return $login_url;
}
return add_query_arg(
'redirect_to',
rawurlencode( get_permalink( absint( $course_id ) ) ),
get_permalink( $register )
);
}
Your registration form has to honour redirect_to and validate it, for example with wp_validate_redirect(), so it cannot be abused as an open redirect. Not run on a live site; test on staging first.
Why the join filter may never fire
With the LearnDash 3.0 (LD30) template, logged-out visitors on an Open or Free course usually see a Log In to Enroll link rather than the enrolment form. That link is filtered by learndash_login_url, and points to #login when the login and registration modal is enabled, or to wp_login_url() otherwise. The join filter only fires when a logged-out visitor actually submits the form, for example when the learndash_login_modal filter returns false or when the button comes from the [learndash_payment_buttons] shortcode. If your change has no effect, check which of the two paths your template uses.
Closed courses: use the setting first
For a course with the Closed access mode, you may not need code at all. The course's access settings include a Button URL field that points the enrolment button at any URL, such as a checkout or enquiry form. Combine it with Snippet 1 so that deep links to lessons land on the same page.
Related reading
Our LearnDash guide covers access modes and enrolment in depth, and creating a LearnDash group explains how group access interacts with course access. For the wider picture of extending WordPress LMS plugins safely, see our WordPress LMS development guide.
How we can help
If your access rules go beyond a redirect, such as per-customer sales pages, membership plugins or a headless storefront, our LMS plugin development team builds and tests them as a maintainable plugin rather than a stack of snippets.
Frequently asked questions
Why does LearnDash redirect lessons to the course page?
When a user without access opens a lesson, topic or quiz, LearnDash runs sfwd_lms_access_redirect() on template_redirect and sends them to the course page so they can enrol. The learndash_access_redirect filter changes the destination.
How do I stop LearnDash redirecting at all?
Return an empty string from learndash_access_redirect. LearnDash only redirects when the link is not empty, so the user stays on the step page and sees whatever your template shows for locked content.
Why is my LearnDash redirect to another site ignored?
LearnDash redirects with wp_safe_redirect() by default, which rejects hosts that are not on the allowed list. Add the host with the allowed_redirect_hosts filter.
Does learndash_access_redirect work for groups?
It runs for lessons, topics and quizzes whenever course access fails, including when access would normally come from a group. Logged-out Join clicks on a group use learndash_group_join_redirect.
Free 30-minute consultation
Not sure where to start? Talk to an LMS engineer.
Tell us what platform you run and what you need. You’ll get honest, practical advice - even if the answer is that you don’t need us.
Sources & references
- learndash_access_redirect - LearnDash developer documentation
- learndash_{$post_label_prefix}_join_redirect - LearnDash developer documentation
- wp_safe_redirect() - WordPress.org
- allowed_redirect_hosts hook - WordPress.org
Learn more about this topic with AI
Gemini opens with the prompt copied - paste it into the chat to start.