LMS Development on 1C-Bitrix: Building an Educational Platform
You already use 1C-Bitrix for your store or corporate portal, and now you need to launch partner training. A separate LMS means another admin panel, another login, and synchronization headaches. We solve it differently: we build the platform right inside your Bitrix. Single user database, shared orders, payment module—everything works out of the box. In 10+ years we have implemented 7 educational projects on Bitrix and know all the pitfalls.
A typical situation: a client already sells products through an online store on Bitrix and now wants to launch online courses. Implementing a separate LMS (e.g., Moodle) would require duplicating users, setting up SSO, and migrating data. All this can be solved with standard Bitrix tools—infoblocks, HL-blocks, and user groups. Time savings on integration—up to 40% compared to external solutions.
Why Bitrix Is Suitable for an LMS
Bitrix provides infoblocks for storing courses and lessons, user groups for access, agents for background tasks, and built-in payment systems. A ready-made LMS on Bitrix costs 2–3 times less than implementing a separate Moodle if the business already uses the 1C-Bitrix ecosystem. Everything is managed from a single admin panel, and for students—a unified personal account. Additionally, we use tagged caching for course pages: when content changes, only the cache of the specific lesson is cleared, not the entire section.
Data Storage Architecture
The LMS on Bitrix is built on a combination of infoblocks and HighLoad-blocks (HL-blocks, tables via ORM D7).
Infoblocks:
| Infoblock | Code | Purpose |
|---|---|---|
| Courses | lms_courses |
Main course entities |
| Lessons | lms_lessons |
Lessons within a course |
| Quizzes | lms_quizzes |
Assignments and tests |
HL-blocks (via ORM):
// User progress class UserProgressTable extends \Bitrix\Main\ORM\Data\DataManager { public static function getTableName(): string { return 'b_hl_lms_user_progress'; } public static function getMap(): array { return [ new IntegerField('ID', ['primary' => true, 'autocomplete' => true]), new IntegerField('USER_ID'), new IntegerField('COURSE_ID'), // ID of course infoblock element new IntegerField('LESSON_ID'), // ID of lesson infoblock element new EnumField('STATUS', ['values' => ['NOT_STARTED', 'IN_PROGRESS', 'COMPLETED']]), new IntegerField('PROGRESS_PERCENT'), // 0–100 new DatetimeField('STARTED_AT'), new DatetimeField('COMPLETED_AT'), new IntegerField('TIME_SPENT_SEC'), // Time spent on lesson ]; } } // Course enrollments class CourseEnrollmentTable extends \Bitrix\Main\ORM\Data\DataManager { public static function getTableName(): string { return 'b_hl_lms_enrollment'; } public static function getMap(): array { return [ new IntegerField('ID', ['primary' => true, 'autocomplete' => true]), new IntegerField('USER_ID'), new IntegerField('COURSE_ID'), new EnumField('STATUS', ['values' => ['ACTIVE', 'COMPLETED', 'EXPIRED', 'REFUNDED']]), new DatetimeField('ENROLLED_AT'), new DatetimeField('EXPIRES_AT'), // NULL = unlimited new FloatField('PAID_AMOUNT'), new IntegerField('ORDER_ID'), // Link to order from sale module ]; } } Course and Lesson Structure
A course is an infoblock element lms_courses with properties:
| Property | Code | Type |
|---|---|---|
| Category | CATEGORY |
List |
| Duration | DURATION_HOURS |
Number |
| Level | LEVEL |
List (Beginner/Intermediate/Expert) |
| Access type | ACCESS_TYPE |
List (Free/Paid/Subscription) |
| Access group | ACCESS_GROUP_ID |
Number (group ID b_group) |
| Certificate | HAS_CERTIFICATE |
Flag |
A lesson is an infoblock element lms_lessons, linked to a course via property COURSE_ID. Lesson order via SORT. Lesson content type (LESSON_TYPE): Video / Text / Test / Webinar.
How Is Course Access Managed?
Access is controlled via Bitrix user groups. Each course has its own group (b_group). After payment or enrollment, the user is added to the group:
class EnrollmentService { public function enroll(int $userId, int $courseId): void { $course = \CIBlockElement::GetByID($courseId)->GetNext(); $groupId = (int)$course['PROPERTY_ACCESS_GROUP_ID_VALUE']; if ($groupId) { $currentGroups = \CUser::GetUserGroup($userId); if (!in_array($groupId, $currentGroups)) { $currentGroups[] = $groupId; \CUser::SetUserGroup($userId, $currentGroups); } } CourseEnrollmentTable::add([ 'USER_ID' => $userId, 'COURSE_ID' => $courseId, 'STATUS' => 'ACTIVE', 'ENROLLED_AT' => new \Bitrix\Main\Type\DateTime(), ]); } } Access to course pages is checked similarly: if no enrollment record exists or status is not ACTIVE—redirect to the purchase page.
Progress Tracking
Progress is recorded under several conditions depending on lesson type:
- Video: tracking via player
timeupdateevent, marked as watched at 80% video. - Text: marked when scrolled to the end (IntersectionObserver on last paragraph).
- Test: on successful passing (score ≥ pass threshold).
// AJAX endpoint for progress saving // POST /local/ajax/lms_progress.php $lessonId = (int)$_POST['lesson_id']; $courseId = (int)$_POST['course_id']; $userId = $USER->GetID(); $percent = min(100, (int)$_POST['percent']); $existing = UserProgressTable::getList([ 'filter' => ['USER_ID' => $userId, 'LESSON_ID' => $lessonId], ])->fetch(); if ($existing) { if ($percent > $existing['PROGRESS_PERCENT']) { UserProgressTable::update($existing['ID'], [ 'PROGRESS_PERCENT' => $percent, 'STATUS' => $percent >= 100 ? 'COMPLETED' : 'IN_PROGRESS', 'COMPLETED_AT' => $percent >= 100 ? new \Bitrix\Main\Type\DateTime() : null, ]); } } else { UserProgressTable::add([ 'USER_ID' => $userId, 'COURSE_ID' => $courseId, 'LESSON_ID' => $lessonId, 'STATUS' => $percent >= 100 ? 'COMPLETED' : 'IN_PROGRESS', 'PROGRESS_PERCENT' => $percent, 'STARTED_AT' => new \Bitrix\Main\Type\DateTime(), 'COMPLETED_AT' => $percent >= 100 ? new \Bitrix\Main\Type\DateTime() : null, ]); } Testing and Quizzes
Test questions are infoblock elements lms_quizzes with properties: question type (single choice, multiple choice, text answer), answer options (JSON in string property), correct answer, question weight.
Test results—HL-block b_hl_lms_quiz_attempt:
CREATE TABLE b_hl_lms_quiz_attempt ( ID SERIAL PRIMARY KEY, USER_ID INTEGER, QUIZ_ID INTEGER, SCORE INTEGER, -- points earned MAX_SCORE INTEGER, -- maximum PASSED BOOLEAN, ANSWERS_JSON TEXT, -- JSON with user answers CREATED_AT TIMESTAMP ); Certificates
Upon course completion (all lessons COMPLETED)—generate a PDF certificate using the FPDF or TCPDF library:
class CertificateGenerator { public function generate(int $userId, int $courseId): string { $user = \CUser::GetByID($userId)->Fetch(); $course = \CIBlockElement::GetByID($courseId)->GetNext(); $pdf = new \TCPDF(); $pdf->AddPage('L'); // Landscape $pdf->setImageScale(1.25); // Certificate background image $pdf->Image('/local/templates/lms/img/certificate_bg.jpg', 0, 0, 297, 210); // Full name $pdf->SetFont('dejavusans', 'B', 32); $pdf->SetXY(50, 90); $pdf->Cell(200, 20, $user['LAST_NAME'] . ' ' . $user['NAME'], 0, 0, 'C'); // Course name $pdf->SetFont('dejavusans', '', 18); $pdf->SetXY(50, 120); $pdf->Cell(200, 10, $course['NAME'], 0, 0, 'C'); $filename = 'certificate_' . $userId . '_' . $courseId . '.pdf'; $path = '/upload/certificates/' . $filename; $pdf->Output($_SERVER['DOCUMENT_ROOT'] . $path, 'F'); return $path; } } Process of Work
- Analytics and design — agree on course structure, content types, access scheme.
- Component development — create 2.0 components for course list, detail page, progress.
- Integration — connect payment systems (YooKassa, Sber) and exchange with 1C via CommerceML.
- Testing — verify scenarios of purchase, enrollment, lesson completion, and certificate generation.
- Deployment and training — roll out to production server, train administrators (2–3 hours).
What Is Included in the Work
When ordering a turnkey LMS development, we deliver:
- analytics and data schema design (infoblocks, HL-blocks);
- development of 2.0 components (course list, detail, progress);
- integration with payment systems and 1C;
- testing and bug fixing;
- delivery of source code, documentation, and accesses;
- administrator training.
Development Timeline
| Variant | Scope | Duration |
|---|---|---|
| Basic LMS | Courses, lessons, progress, group access | 15–20 days |
| With tests and certificates | + Quizzes, PDF generation | 20–30 days |
| Full platform | + Payments, subscriptions, analytics, webinars | 35–50 days |
Want to discuss your project? Contact us—we'll evaluate your task and propose an optimal solution. Order an LMS development—and get a ready-made solution within agreed deadlines.

