The access control contract
The single rule every integration must follow.
The rule
Never render course or lesson content without asking POM LMS whether the current user may see it.
if ( ! pom_lms_user_can_access_lesson( $lesson_id ) ) {
return '';
}
That applies to shortcodes, widgets, blocks, page-builder modules, REST responses, feeds, search results that include content, exports, and anything that puts lesson text or video URLs into an email.
Why it cannot be reimplemented
Access is not a flag. It is a precedence:
- If the course requires login and the visitor is signed out — no.
- Otherwise, if a permission rule applies — the rule decides, and nothing else is consulted.
- Otherwise, if the course is paid — the purchase decides.
- Otherwise — yes.
Lessons add their own layer on top, with preview lessons as a deliberate exception.
Any integration that checks "is this course paid, and did they buy it?" gets the rule case wrong, and any that checks the rule first gets the login gate wrong. The helpers exist so that there is one implementation of this order.
If the precedence changes in a future release, code that calls the helpers follows it. Code that reimplements it silently starts leaking content.
The two helpers
| Call | For |
|---|---|
pom_lms_user_can_access_course( $course_id ) |
Course content |
pom_lms_user_can_access_lesson( $lesson_id, $course_id = 0 ) |
Lesson content |
Both return a boolean, both concern the current user, and both are safe to call for signed-out visitors.
Use the lesson helper for lesson content even when you already know the course is accessible — lessons carry overrides and preview flags the course helper knows nothing about.
They answer for the current user only
Neither helper takes a user ID. They evaluate the current request.
That has a practical consequence: you cannot use them in a background job, a cron task or an email send to ask whether some other user has access. There is no supported way to answer that question for an arbitrary user, and constructing one by reading the underlying data reimplements the precedence — the thing this contract exists to prevent.
Design integrations to check access at render time, in the visitor's own request.
Guard the function itself
POM LMS may not be active. Fail closed:
if ( ! function_exists( 'pom_lms_user_can_access_course' ) ) {
return '';
}
Returning content because the helper is missing is the worst possible failure mode.
What a blocked response should be
Do not invent your own message. If you are replacing content that the plugin would have blocked, either:
- return nothing, and let the page's own no-access handling apply; or
- render the course's configured no-access text, which is the message the site owner wrote for exactly this situation.
Inventing a third message means site owners have text they cannot find and cannot change.
Previews are content, not tests
A lesson marked as a preview is accessible to everyone, including signed-out visitors. If your integration surfaces lessons, expect preview lessons to pass the access check for anonymous requests — that is correct behavior, not a bug to work around.