Claude Skill

learndash-group-access

Build or audit LearnDash group membership, group-course access, group leaders, and hierarchical group behavior. Use when code mentions ld_update_group_access, ld_update_course_group_access, learndash_get_users_group_ids, learndash_get_groups_user_ids, learndash_group_enrolled_cou

LLM Mart · 0 points · 0 views 0 listing impressions 0 install-command copies
Virus-scanned Reviewed automatically before listing.

Full trust report

Download lonsdale201-wp-agent-skills-learndash_learndash-group-access-52f6020.zip · 3 KB
Part of lonsdale201/wp-agent-skills — 226 skills

Install

skills CLI npx skills add https://github.com/Lonsdale201/wp-agent-skills/tree/main/learndash/learndash-group-access
Claude Code claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install lonsdale201-wp-agent-skills@llmmart
Git git clone https://github.com/Lonsdale201/wp-agent-skills.git

The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole lonsdale201/wp-agent-skills collection as a plugin from our marketplace. Git is the plain clone.

Skill manifest

LearnDash group access

Use this when code needs to enroll users into groups, attach courses to groups, manage group leaders, or answer "does this user get course access through a group?"

LearnDash groups are not just taxonomy terms and not just post meta on a group. In 5.1.9 the access model is three separate relationships:

  • User -> group membership.
  • Group -> course access.
  • Group leader -> administrated group.

Course access through a group exists only when the user is in the group and the group is attached to the course, then the group product start/end rules allow access.

When to use this skill

Trigger when ANY of these appears:

  • ld_update_group_access(), ld_update_course_group_access(), ld_update_leader_group_access(), learndash_is_user_in_group(), learndash_user_group_enrolled_to_course(), or learndash_get_users_group_ids().
  • Usermeta keys learndash_group_users_{$group_id}, group_{$group_id}_access_from, learndash_group_{$group_id}_enrolled_at, or learndash_group_leaders_{$group_id}.
  • Course postmeta keys learndash_group_enrolled_{$group_id} or learndash_group_{$group_id}_enrolled_at.
  • Custom group dashboards, group leader portals, imports, CRMs, Woo bridges, memberships, cohort sync, or REST endpoints.

Relationship map

User -> group

The direct user-group relation is stored on the user:

  • learndash_group_users_{$group_id} stores the group ID.
  • group_{$group_id}_access_from stores the access start timestamp.
  • learndash_group_{$group_id}_enrolled_at is historical enrollment time.

Use:

ld_update_group_access( $user_id, $group_id );        // grant
ld_update_group_access( $user_id, $group_id, true );  // revoke

Or use the model wrapper:

use LearnDash\Core\Models\Product;

$group_product = Product::find( $group_id );

if ( $group_product ) {
    $group_product->enroll( $user_id );
}

ld_update_group_access() creates access activity for courses currently attached to the group, fires ld_added_group_access or ld_removed_group_access, and clears user group/course transients.

Group -> course

The group-course relation is stored on the course post:

  • learndash_group_enrolled_{$group_id} stores the timestamp when the course was added to the group.
  • learndash_group_{$group_id}_enrolled_at is a historical timestamp kept for reporting and should not be casually deleted.

Use:

ld_update_course_group_access( $course_id, $group_id );        // attach
ld_update_course_group_access( $course_id, $group_id, true );  // detach

For whole-list replacement, use the diff helpers:

  • learndash_set_group_enrolled_courses( $group_id, $course_ids )
  • learndash_set_course_groups( $course_id, $group_ids )

They compute additions/removals and call ld_update_course_group_access() for each delta.

Leader -> group

Group leaders are not the same as group members. A leader can administer a group without being enrolled as a learner.

Use:

ld_update_leader_group_access( $leader_user_id, $group_id );
ld_update_leader_group_access( $leader_user_id, $group_id, true );

Read with:

  • learndash_is_group_leader_user( $user_id )
  • learndash_get_administrators_group_ids( $leader_user_id )

Reading group access

Use the API that matches the question:

  • User belongs to group now: learndash_is_user_in_group( $user_id, $group_id ).
  • User's direct and inherited group IDs: learndash_get_users_group_ids( $user_id ).
  • Group's users: learndash_get_groups_user_ids( $group_id ) or learndash_get_groups_users( $group_id ).
  • Group's courses: learndash_group_enrolled_courses( $group_id ).
  • Course's groups: learndash_get_course_groups( $course_id ).
  • User gets a course through a group: learndash_user_group_enrolled_to_course( $user_id, $course_id ).
  • Effective group-course access timestamp: learndash_user_group_enrolled_to_course_from( $user_id, $course_id ).

Do not decide group course access by checking one meta key. The user must be in the group, the group must be attached to the course, and the group Product model must allow access.

Hierarchical groups

When hierarchical groups are enabled, learndash_get_users_group_ids() expands the returned group IDs through validated child groups. That means:

  • A direct meta scan can miss inherited access.
  • learndash_is_user_in_group() can return true because the expanded group list contains the group.
  • Custom SQL that only checks learndash_group_users_{$group_id} is not enough for access decisions.

If the task is about reporting direct memberships, say so explicitly. If the task is about access, use LearnDash's group APIs.

Managed Groups auto-enrollment in 5.1.8+

When groups_autoenroll_managed is enabled, a Group Leader's effective group IDs are the union of:

  • explicit learner memberships stored under learndash_group_users_*; and
  • groups returned by learndash_get_administrators_group_ids() for that leader.

Before 5.1.8, the managed-group branch replaced the explicit memberships. Do not reproduce that old behavior in a custom portal or cache. Keep leader-to- group administration and learner-to-group membership as separate relations, then use learndash_get_users_group_ids() when effective access is required.

The effective list is cached for one minute in learndash_user_groups_{$user_id}. Pass true as the second argument to learndash_get_users_group_ids() when the caller requires a fresh result. ld_update_group_access() clears this cache, but in 5.1.9 ld_update_leader_group_access() does not. After changing a leader assignment, hierarchy, or the Managed Groups setting, explicitly invalidate the transient with LDLMS_Transients::delete( 'learndash_user_groups_' . $user_id ) or use the bypass until LearnDash's one-minute entry expires.

Cache and transient caveats

Some older function signatures still expose $bypass_transient, but LearnDash 5.x has removed or narrowed transient behavior in several group helpers:

  • learndash_group_enrolled_courses() no longer uses its old transient.
  • learndash_get_course_groups() no longer uses its old transient.
  • learndash_get_groups_user_ids() keeps the parameter for compatibility, but the current implementation does not rely on the old cached query.
  • ld_update_group_access() clears learndash_user_groups_{$user_id} and learndash_user_courses_{$user_id}.

Do not add custom long-lived caches unless the invalidation story covers user membership changes, group-course changes, hierarchy changes, and group leader changes.

Common mistakes to reject

  • Writing learndash_group_users_* or learndash_group_enrolled_* meta directly instead of using the LearnDash helpers.
  • Storing course IDs on the group post instead of attaching the group on the course postmeta.
  • Assuming group leaders are enrolled learners.
  • Removing historical learndash_group_{$group_id}_enrolled_at.
  • Checking only direct membership when hierarchical groups can grant inherited access.
  • Forgetting that group access can make sfwd_lms_has_access() true even when the user has no direct course_{$course_id}_access_from.

Cross-references

  • Use learndash-course-access for final course access decisions, expiration, direct course enrollment, and access-from dates.
  • Use learndash-woocommerce-access when Woo products/orders/subscriptions grant LearnDash group access.
  • Use learndash-rest-api for REST routes that manage group users, group courses, or user groups.
  • Use learndash-course-progress for learner completion and group-course progress synchronization.

References

Validated against LearnDash LMS 5.1.9 local source:

  • includes/ld-groups.php
  • includes/course/ld-course-user-functions.php
  • src/Core/Models/Product.php
  • includes/rest-api/v2/class-ld-rest-groups-courses-controller.php
  • includes/rest-api/v2/class-ld-rest-groups-users-controller.php
  • includes/rest-api/v2/class-ld-rest-users-groups-controller.php
  • Official documentation: https://developers.learndash.com/
Files (wp-agent-skills)
  • agents
    • openai.yaml 208 B
      interface:
        display_name: "LearnDash Group Access"
        short_description: "LearnDash group membership and course access"
        default_prompt: "Use $learndash-group-access to review LearnDash group access logic."
      
  • SKILL.md 8.7 KB
    ---
    name: learndash-group-access
    description: >-
      Build or audit LearnDash group membership, group-course access, group
      leaders, and hierarchical group behavior. Use when code mentions
      ld_update_group_access, ld_update_course_group_access,
      learndash_get_users_group_ids, learndash_get_groups_user_ids,
      learndash_group_enrolled_courses, learndash_user_group_enrolled_to_course,
      learndash_is_user_in_group, learndash_group_users_*,
      learndash_group_enrolled_*, group_*_access_from, or group leader access.
    metadata:
      wp-skills-author: "Soczó Kristóf"
      wp-skills-contact: "mailto:lonsdale201@hotmail.com"
      wp-skills-plugin: "sfwd-lms"
      wp-skills-plugin-version-tested: "5.1.9"
      wp-skills-php-min: "7.4"
      wp-skills-last-updated: "2026-08-06"
    ---
    
    # LearnDash group access
    
    Use this when code needs to enroll users into groups, attach courses to groups,
    manage group leaders, or answer "does this user get course access through a
    group?"
    
    LearnDash groups are not just taxonomy terms and not just post meta on a group.
    In 5.1.9 the access model is three separate relationships:
    
    - User -> group membership.
    - Group -> course access.
    - Group leader -> administrated group.
    
    Course access through a group exists only when the user is in the group and the
    group is attached to the course, then the group product start/end rules allow
    access.
    
    ## When to use this skill
    
    Trigger when ANY of these appears:
    
    - `ld_update_group_access()`, `ld_update_course_group_access()`,
      `ld_update_leader_group_access()`, `learndash_is_user_in_group()`,
      `learndash_user_group_enrolled_to_course()`, or
      `learndash_get_users_group_ids()`.
    - Usermeta keys `learndash_group_users_{$group_id}`,
      `group_{$group_id}_access_from`,
      `learndash_group_{$group_id}_enrolled_at`, or
      `learndash_group_leaders_{$group_id}`.
    - Course postmeta keys `learndash_group_enrolled_{$group_id}` or
      `learndash_group_{$group_id}_enrolled_at`.
    - Custom group dashboards, group leader portals, imports, CRMs, Woo bridges,
      memberships, cohort sync, or REST endpoints.
    
    ## Relationship map
    
    ### User -> group
    
    The direct user-group relation is stored on the user:
    
    - `learndash_group_users_{$group_id}` stores the group ID.
    - `group_{$group_id}_access_from` stores the access start timestamp.
    - `learndash_group_{$group_id}_enrolled_at` is historical enrollment time.
    
    Use:
    
    ```php
    ld_update_group_access( $user_id, $group_id );        // grant
    ld_update_group_access( $user_id, $group_id, true );  // revoke
    ```
    
    Or use the model wrapper:
    
    ```php
    use LearnDash\Core\Models\Product;
    
    $group_product = Product::find( $group_id );
    
    if ( $group_product ) {
        $group_product->enroll( $user_id );
    }
    ```
    
    `ld_update_group_access()` creates access activity for courses currently
    attached to the group, fires `ld_added_group_access` or
    `ld_removed_group_access`, and clears user group/course transients.
    
    ### Group -> course
    
    The group-course relation is stored on the course post:
    
    - `learndash_group_enrolled_{$group_id}` stores the timestamp when the course
      was added to the group.
    - `learndash_group_{$group_id}_enrolled_at` is a historical timestamp kept for
      reporting and should not be casually deleted.
    
    Use:
    
    ```php
    ld_update_course_group_access( $course_id, $group_id );        // attach
    ld_update_course_group_access( $course_id, $group_id, true );  // detach
    ```
    
    For whole-list replacement, use the diff helpers:
    
    - `learndash_set_group_enrolled_courses( $group_id, $course_ids )`
    - `learndash_set_course_groups( $course_id, $group_ids )`
    
    They compute additions/removals and call `ld_update_course_group_access()` for
    each delta.
    
    ### Leader -> group
    
    Group leaders are not the same as group members. A leader can administer a group
    without being enrolled as a learner.
    
    Use:
    
    ```php
    ld_update_leader_group_access( $leader_user_id, $group_id );
    ld_update_leader_group_access( $leader_user_id, $group_id, true );
    ```
    
    Read with:
    
    - `learndash_is_group_leader_user( $user_id )`
    - `learndash_get_administrators_group_ids( $leader_user_id )`
    
    ## Reading group access
    
    Use the API that matches the question:
    
    - User belongs to group now:
      `learndash_is_user_in_group( $user_id, $group_id )`.
    - User's direct and inherited group IDs:
      `learndash_get_users_group_ids( $user_id )`.
    - Group's users:
      `learndash_get_groups_user_ids( $group_id )` or
      `learndash_get_groups_users( $group_id )`.
    - Group's courses:
      `learndash_group_enrolled_courses( $group_id )`.
    - Course's groups:
      `learndash_get_course_groups( $course_id )`.
    - User gets a course through a group:
      `learndash_user_group_enrolled_to_course( $user_id, $course_id )`.
    - Effective group-course access timestamp:
      `learndash_user_group_enrolled_to_course_from( $user_id, $course_id )`.
    
    Do not decide group course access by checking one meta key. The user must be in
    the group, the group must be attached to the course, and the group `Product`
    model must allow access.
    
    ## Hierarchical groups
    
    When hierarchical groups are enabled, `learndash_get_users_group_ids()` expands
    the returned group IDs through validated child groups. That means:
    
    - A direct meta scan can miss inherited access.
    - `learndash_is_user_in_group()` can return true because the expanded group list
      contains the group.
    - Custom SQL that only checks `learndash_group_users_{$group_id}` is not enough
      for access decisions.
    
    If the task is about reporting direct memberships, say so explicitly. If the
    task is about access, use LearnDash's group APIs.
    
    ## Managed Groups auto-enrollment in 5.1.8+
    
    When `groups_autoenroll_managed` is enabled, a Group Leader's effective group
    IDs are the union of:
    
    - explicit learner memberships stored under `learndash_group_users_*`; and
    - groups returned by `learndash_get_administrators_group_ids()` for that
      leader.
    
    Before 5.1.8, the managed-group branch replaced the explicit memberships. Do
    not reproduce that old behavior in a custom portal or cache. Keep leader-to-
    group administration and learner-to-group membership as separate relations,
    then use `learndash_get_users_group_ids()` when effective access is required.
    
    The effective list is cached for one minute in
    `learndash_user_groups_{$user_id}`. Pass `true` as the second argument to
    `learndash_get_users_group_ids()` when the caller requires a fresh result.
    `ld_update_group_access()` clears this cache, but in 5.1.9
    `ld_update_leader_group_access()` does not. After changing a leader assignment,
    hierarchy, or the Managed Groups setting, explicitly invalidate the transient
    with `LDLMS_Transients::delete( 'learndash_user_groups_' . $user_id )` or use
    the bypass until LearnDash's one-minute entry expires.
    
    ## Cache and transient caveats
    
    Some older function signatures still expose `$bypass_transient`, but LearnDash
    5.x has removed or narrowed transient behavior in several group helpers:
    
    - `learndash_group_enrolled_courses()` no longer uses its old transient.
    - `learndash_get_course_groups()` no longer uses its old transient.
    - `learndash_get_groups_user_ids()` keeps the parameter for compatibility, but
      the current implementation does not rely on the old cached query.
    - `ld_update_group_access()` clears `learndash_user_groups_{$user_id}` and
      `learndash_user_courses_{$user_id}`.
    
    Do not add custom long-lived caches unless the invalidation story covers user
    membership changes, group-course changes, hierarchy changes, and group leader
    changes.
    
    ## Common mistakes to reject
    
    - Writing `learndash_group_users_*` or `learndash_group_enrolled_*` meta
      directly instead of using the LearnDash helpers.
    - Storing course IDs on the group post instead of attaching the group on the
      course postmeta.
    - Assuming group leaders are enrolled learners.
    - Removing historical `learndash_group_{$group_id}_enrolled_at`.
    - Checking only direct membership when hierarchical groups can grant inherited
      access.
    - Forgetting that group access can make `sfwd_lms_has_access()` true even when
      the user has no direct `course_{$course_id}_access_from`.
    
    ## Cross-references
    
    - Use `learndash-course-access` for final course access decisions, expiration,
      direct course enrollment, and access-from dates.
    - Use `learndash-woocommerce-access` when Woo products/orders/subscriptions
      grant LearnDash group access.
    - Use `learndash-rest-api` for REST routes that manage group users, group
      courses, or user groups.
    - Use `learndash-course-progress` for learner completion and group-course
      progress synchronization.
    
    ## References
    
    Validated against LearnDash LMS 5.1.9 local source:
    
    - `includes/ld-groups.php`
    - `includes/course/ld-course-user-functions.php`
    - `src/Core/Models/Product.php`
    - `includes/rest-api/v2/class-ld-rest-groups-courses-controller.php`
    - `includes/rest-api/v2/class-ld-rest-groups-users-controller.php`
    - `includes/rest-api/v2/class-ld-rest-users-groups-controller.php`
    - Official documentation: <https://developers.learndash.com/>
    

Comments (0)

Sign in to join the conversation.

No comments yet.

Reviews (0)

No reviews yet.

Related