name: lw-lms-wp-cli-operations
description: Use the LW LMS v1.5.1 operational WP-CLI commands added in v1.4.0. Covers wp lw-lms course create|list|delete|set-section, wp lw-lms lesson create|list|assign, wp lw-lms enroll, wp lw-lms revoke, wp lw-lms force-complete, argument resolution by ID/slug/login/email, enrollment hook side effects, progress hook side effects, and common CLI footguns.
author: Soczó Kristóf
contact: mailto:lonsdale201@hotmail.com
plugin: lw-lms
plugin-version-tested: "1.5.1"
php-min: "8.1"
last-updated: "2026-06-15"
docs:
- https://github.com/lwplugins/lw-lms
source-refs:
- wp-content/plugins/lw-lms/includes/Plugin.php
- wp-content/plugins/lw-lms/includes/CLI/CliResolver.php
- wp-content/plugins/lw-lms/includes/CLI/CourseCreateCommand.php
- wp-content/plugins/lw-lms/includes/CLI/CourseListCommand.php
- wp-content/plugins/lw-lms/includes/CLI/CourseDeleteCommand.php
- wp-content/plugins/lw-lms/includes/CLI/CourseSetSectionCommand.php
- wp-content/plugins/lw-lms/includes/CLI/LessonCreateCommand.php
- wp-content/plugins/lw-lms/includes/CLI/LessonListCommand.php
- wp-content/plugins/lw-lms/includes/CLI/LessonAssignCommand.php
- wp-content/plugins/lw-lms/includes/CLI/EnrollCommand.php
- wp-content/plugins/lw-lms/includes/CLI/RevokeCommand.php
- wp-content/plugins/lw-lms/includes/CLI/ForceCompleteCommand.php
- wp-content/plugins/lw-lms/includes/Access/AccessRepository.php
- wp-content/plugins/lw-lms/includes/Progress/ProgressRepository.php
- wp-content/plugins/lw-lms/CHANGELOG.md
LW LMS: WP-CLI operations
Use this for the day-to-day LW LMS WP-CLI commands introduced in v1.4.0 and verified against local lw-lms v1.5.1. This is not the LearnDash migration command; use lw-lms-learndash-migration for wp lw-lms migrate-learndash.
When to use this skill
Trigger this skill when any of the following is true:
- A task mentions
wp lw-lms course,wp lw-lms lesson,wp lw-lms enroll,wp lw-lms revoke, orwp lw-lms force-complete. - You need to create/list/delete courses or lessons from CLI.
- You need to enroll/revoke a user or force-complete a course from CLI.
- A diff touches files under
includes/CLI/*Command.phpexceptMigrateLearnDashCommand.phpandincludes/CLI/Migration/.
Command catalog
Registered in Plugin::register_cli_commands() only when WP_CLI is defined and truthy.
| Command | Purpose |
|---|---|
wp lw-lms course create |
Create a course post and set selected course meta |
wp lw-lms course list |
List courses, optionally filtered by access type/status |
wp lw-lms course delete |
Trash or permanently delete a course |
wp lw-lms course set-section |
Create or update one course section in _lw_lms_course_sections |
wp lw-lms lesson create |
Create a lesson post and assign it to a course |
wp lw-lms lesson list |
List lessons for one course, optionally filtered by section |
wp lw-lms lesson assign |
Assign/reassign an existing lesson to a course/section/order |
wp lw-lms enroll |
Grant stored access through AccessRepository::grant() |
wp lw-lms revoke |
Revoke stored access through AccessRepository::revoke() |
wp lw-lms force-complete |
Mark every published lesson in a course completed through ProgressRepository::mark_course_completed() |
Reference resolution
CliResolver resolves:
- course references by numeric post ID or course slug;
- lesson references by numeric post ID or lesson slug;
- user references by numeric user ID, login, or email.
Resolver failures call WP_CLI::error() and halt the command. Callers can treat returned IDs as valid.
Course commands
Create
wp lw-lms course create --title="My Course" --access-type=paid --duration="8h"
wp lw-lms course create --title="Draft Course" --status=draft --porcelain
Options:
| Option | Notes |
|---|---|
--title=<title> |
Required |
| `--access-type=<open | free |
--duration=<duration> |
Stored as _lw_lms_duration |
--status=<status> |
Default publish |
--excerpt=<excerpt> |
Saved to post_excerpt |
--content=<content> |
Saved to post_content |
--porcelain |
Outputs only the new course ID |
This command does not configure WooCommerce products, subscriptions, membership plans, preview lessons, or attachments.
List
wp lw-lms course list
wp lw-lms course list --access-type=paid --format=json
wp lw-lms course list --format=ids
Options:
--access-type=<type>filters by_lw_lms_access_type;--status=<status>defaults toany;--per-page=<n>defaults to100;--format=<table|csv|json|yaml|count|ids>defaults totable.
Delete
wp lw-lms course delete 42
wp lw-lms course delete my-course --force
Without --force, WordPress trash behavior is used. The command does not clean orphaned lesson meta, access rows, progress rows, or completion snapshots. If you need full cleanup, build that explicitly.
Set section
wp lw-lms course set-section 42 --id=sec_intro --title="Intro" --order=0
wp lw-lms course set-section my-course --id=sec_extra --description="Bonus material"
Re-running with the same --id updates the existing section. This command only mutates the course's _lw_lms_course_sections array. It does not move lessons into that section; use lesson assign for lesson assignment.
Lesson commands
Create
wp lw-lms lesson create --title="Intro" --course=42 --section=sec_intro --order=1
wp lw-lms lesson create --title="Intro" --course=my-course --content="<p>Body</p>" --porcelain
Options:
| Option | Notes |
|---|---|
--title=<title> |
Required |
--course=<course> |
Required; course ID or slug |
--section=<section-id> |
Optional; sanitized with sanitize_key() |
--order=<order> |
Default 0 |
--duration=<duration> |
Stored as _lw_lms_duration |
--status=<status> |
Default publish |
--content=<content> |
Saved to post_content |
--porcelain |
Outputs only the new lesson ID |
The command does not create the section. Create/update the section first with course set-section if the section should exist in the course outline.
List
wp lw-lms lesson list --course=42
wp lw-lms lesson list --course=my-course --section=sec_intro --format=json
wp lw-lms lesson list --course=42 --format=ids
--course is required. Rows are ordered by _lw_lms_lesson_order.
Assign
wp lw-lms lesson assign 99 --course=42 --section=sec_intro --order=2
wp lw-lms lesson assign intro-lesson --course=my-course --section=""
This sets _lw_lms_lesson_course_id, optionally _lw_lms_lesson_section_id, and optionally _lw_lms_lesson_order. Passing an empty string to --section clears the section.
Enrollment commands
Enroll
wp lw-lms enroll alice 42
wp lw-lms enroll alice@example.com my-course --expires-at="2027-01-01"
wp lw-lms enroll 7 my-course --source=my_integration
This command calls:
AccessRepository::grant( $user_id, $course_id, $source, null, $expires_at );
Side effects:
lw_lms_pre_grantcan abort the command; the CLI reports an error if the grant returns false.lw_lms_after_grantfires on success with 5 args.- Re-running can update an existing row's
granted_atandexpires_at.
Footgun: the command always passes source_id = null. The access table unique key is (user_id, course_id, source_id), so changing --source alone does not guarantee a separate row. If your integration needs stable distinct rows, use PHP and pass a meaningful source_id.
--expires-at is parsed through strtotime() and stored as Y-m-d H:i:s using gmdate(). Prefer explicit full datetimes in automation.
Revoke
wp lw-lms revoke alice 42
This calls AccessRepository::revoke( $user_id, $course_id ). It flips the first matching active row to status='revoked' and fires lw_lms_after_revoke only when a row was changed. If there is no active row, the command warns and exits without an error.
Runtime subscription, membership, or legacy purchase access has no stored row to revoke. Revoke the upstream WooCommerce entitlement or change course meta if access comes from those live checks.
Force-complete
wp lw-lms force-complete alice 42
wp lw-lms force-complete alice@example.com my-course
This calls ProgressRepository::mark_course_completed( $user_id, $course_id ).
Side effects:
- published lessons assigned to the course are upserted to
completed; lw_lms_lesson_completedfires for lessons that transition to completed;CompletionTracker::maybe_record()can write the completion snapshot and firelw_lms_course_completed;- if no published lessons are found, the command warns.
This command does not enroll the user. It only writes progress.
Critical rules
- These commands are registered only in WP-CLI.
- This skill does not cover
wp lw-lms migrate-learndash; uselw-lms-learndash-migration. course set-sectionandlesson assignare separate operations. A section existing on the course does not automatically move lessons.enrollwrites an access row and fires access hooks; subscription/membership live access does not.revokeonly revokes stored access rows, not live subscription or membership entitlement.force-completewrites progress, not access.- There is no dry-run flag for these operational commands.
- Use
--format=jsonor--format=idsfor scripts instead of parsing table output.
Common mistakes
# WRONG: assumes set-section moves lessons.
wp lw-lms course set-section 42 --id=sec_intro --title="Intro"
# RIGHT.
wp lw-lms course set-section 42 --id=sec_intro --title="Intro"
wp lw-lms lesson assign 99 --course=42 --section=sec_intro --order=1
# WRONG: assumes source creates a distinct row.
wp lw-lms enroll alice 42 --source=free
wp lw-lms enroll alice 42 --source=manual
# RIGHT for distinct external rows: call AccessRepository::grant() in PHP with
# a non-null source_id from the external system.
# WRONG: assumes force-complete grants course access.
wp lw-lms force-complete alice 42
# RIGHT when both are needed.
wp lw-lms enroll alice 42
wp lw-lms force-complete alice 42
Cross-references
- Use
lw-lms-backend-extendfor hook contracts and repository semantics. - Use
lw-lms-learndash-migrationforwp lw-lms migrate-learndash. - Use
lw-lms-rest-frontendto validate how CLI changes appear in/wp-json/lms/v1responses. - Use
lw-lms-abilitiesfor admin/agent Abilities API calls.
References
- Command registration:
includes/Plugin.php. - Reference resolution:
includes/CLI/CliResolver.php. - Course commands:
CourseCreateCommand.php,CourseListCommand.php,CourseDeleteCommand.php,CourseSetSectionCommand.php. - Lesson commands:
LessonCreateCommand.php,LessonListCommand.php,LessonAssignCommand.php. - Access commands:
EnrollCommand.php,RevokeCommand.php. - Progress command:
ForceCompleteCommand.php. - Access hook side effects:
includes/Access/AccessRepository.php. - Progress hook side effects:
includes/Progress/ProgressRepository.php.