Skip to main content
This page covers all backend functions for courses and shows how to use them in .ef page templates. See Courses — Overview for setup and enrollment.

Backend functions

All functions are available in <script scope="backend"> blocks and in .ef files.

getCourses(opts?)

Returns all courses for the brand, each with is_assigned and started for the current customer.
sort supports:
  • enrollment_oldest_unfinished_first (default)
  • title_asc
  • title_desc
  • preferred (when used, pass preferredOrder: ['slug-or-title', ...])

getCategoriesWithCourses(opts?)

Same as getCourses but grouped by category. Returns an array of { category_slug, category_name, courses[] }.

getCoursesByCategorySlug(opts)

Returns courses in a single category. Useful for “Daily practices” or “Advanced” sections on a dashboard.

getCoursesForCustomer(opts?)

Returns only courses the current customer is enrolled in (same as getCourses({ assignedOnly: true })). Returns [] if no session or no enrollments.

getCourseForCustomer(opts)

Returns a single course with enrollment check — is_assigned and started are set for the current customer. Also returns the full modules[] and contents[] tree, plus progress_percent and completed_content_ids. Use this on the course detail page.
Returns null if no course with that slug exists.

getCourseBySlug(slug)

Returns a single course without enrollment check. is_assigned and started will not be set. Use when you only need course metadata and don’t need to gate content.

getCourseLesson(opts)

Returns the resolved current lesson payload for lesson-player pages, including currentLesson, prevLessonUrl, nextLessonUrl, and progress stats.

getCompletedLessonsCount(opts?)

Returns the total number of completed lessons across all enrolled courses, or for a specific course when a slug is provided.
Returns 0 if the customer has no enrollments or no completed lessons.

getCourseProgress(opts?)

Returns a structured progress summary with completed/total lesson counts per course and an overall total. Useful for dashboards.

request.route_params

For dynamic slug pages (e.g. guided-course/{course}.ef), the slug is available via request.route_params.course.

Course list page

Show all courses, sorted so enrolled courses appear first. Use is_assigned and started to drive the CTA label.

With category tabs


Course detail page

Resolve the slug from the URL, check enrollment with getCourseForCustomer, and gate content.

Auth wrapper for course pages

Use the auth wrapper pattern (@extends) so the login check and common data load happen once across all course pages:
Then each course page:

Checking access to a specific product

If you want to gate course access by checking whether the customer bought a specific product (rather than relying on enrollment), you can cross-reference with getOrders():
Prefer the enrollment-based check (getCourseForCustomer) — it is more reliable and does not require iterating order history. Use the order-history fallback only if enrollment is not being set up via product linking.

Lesson types and content

Each lesson in mod.contents has a type field: Additional fields on each lesson:

Progress API

All progress routes are prefixed with /api/course/courses/:courseId/. Authentication is via the active course session (cookie). courseId, moduleId, and contentId are numeric IDs.

Mark a lesson complete

Returns { success: true, message, stats: { completed_lessons, total_lessons, completion_percent } }.

Save general progress

courseId, moduleId, and contentId go in the URL for the lesson-specific routes. The general saveProgress route keeps them in the body — useful when you want to upsert a progress record with a specific completed value (e.g. un-completing).

Save video position

Get all progress for a course

Get progress for a single lesson

Get course stats

The page receives the initial completed IDs via course.completed_content_ids. Use this array to mark lessons visually on load, then update the UI optimistically when the API call succeeds.