Migration from Tutor LMS
What exists today in the WordPress and Tutor LMS site and in MALYOMAR's own files, how clean it is, how it maps to the new records and the order in which it moves. Findings are computed from the same course data the prototype uses.
Source files received
70 files, February 2026| Source | What it holds | Size | Use in migration |
|---|---|---|---|
| Course export Course-Export-2026-Feb-16.csv / .xlsx | One row per Tutor LMS course: title, content, excerpt, duration, benefits, level, materials, requirements, audience, price, sale price, language, categories, tags, image, status, author, slug. | 58 rows 44 columns | Primary source for Course |
| Topics export Topics-Export-2026-Feb-16.csv | Curriculum sections. Parent course is held in the post parent field. | 365 rows 84 columns | Primary for curriculum topics |
| Lesson export Lesson-Export-2026-Feb-16.csv | Lessons with content, video settings, attachments, preview flag and the course they belong to. | 570 rows 101 columns | Primary for lessons |
| Quiz export Quiz-Export-2026-Feb-16.csv | Quiz shells and their options. Questions and answers are not in the file. | 42 rows 60 columns | Partial questions need a separate pull |
| Combined catalog Tutor_LMS_Complete_Course_Catalog.csv | Course, topic, content item, order and type flattened into one sheet. | 921 rows | Cross-check of the three exports |
| Field list Tutor-LMS courses fields list.xlsx | The Tutor LMS course fields as MALYOMAR listed them. | 1 file | Reference for mapping |
| MEDB 1.0 Access database MEDB 1.0.accdb and two backups | MALYOMAR's own course database with queries for catalog, topics, lessons and quizzes. | 3 files | To inspect may be more current than the site |
| Query outputs Courses_Q, Topics_Q, Lessons_Q, Quiz_Q, qry_CATA*, qry_CTLQ* | Spreadsheet and XML results of the Access queries, including single-course samples. | 14 files | Cross-check |
| Per-course workbooks ML501.xlsx … ML530.xlsx, PD184.xlsx … PD838.xlsx | One workbook per course code: 23 MALYOMAR programs and 21 ASME programs. | 44 files | Primary where richer than the export |
| Curriculum data entry template Curriculum Data Entry Template.xlsx | The sheet layout MALYOMAR uses to prepare a curriculum. | 1 file | Reference becomes the import template |
Row and column counts were measured on the files in the shared drive folder DB.
What is not in the files
- Learners and enrolments. No student, enrolment or progress export was provided. Needs a database pull from Tutor LMS.
- Orders and payments. Held by the shop plugin; not exported.
- Issued certificates. No list of past certificates or their codes.
- Quiz questions. Only quiz shells are present.
- Media. Lesson videos and attachments are referenced by link, not included.
- Batches and attendance. Never held in the site; if records exist they are in spreadsheets or email.
Opening data for the new modules
Separate collection taskThe modules added in revision 5 Oct 2026 have no source in the Tutor LMS export. Their opening data has to be collected from MALYOMAR's own files and from the accountant. Everything the prototype shows for them is sample data.
- Employees and employment documents for People and HR. What is held, and where payroll is calculated, depends on .
- Suppliers, open purchase orders and unpaid supplier bills for Purchasing and payables.
- Opening balances, open receivables, bank and wallet balances for Finance. Which system holds the books, and so where balances are loaded, depends on .
- Partner agreements, tender history and the annual plan for Partners, CRM and Planning and targets. Signed terms and approved targets are entered by management; none are assumed.
- Website pages, menus and SEO metadata. Whether WordPress content is migrated, kept in place or handed over through an integration depends on .
No cut-over date or load order is set for these. They follow the decisions listed on open decisions.
Three versions of the truth. The live site, the Access database and the per-course workbooks may disagree. Step 2 of the plan decides which one wins for each field.
Today's platform. WordPress with Tutor LMS, a shop plugin for checkout and a page builder theme. Courses are WordPress posts; instructors are WordPress users.
Findings in the course data
Computed live from the catalog data| Finding | Courses | Which | What to do |
|---|
Every course, with its gaps
| Course | Status | Hours | Price | Topics | Lessons | Issues |
|---|
Status in Tutor LMS
Only “publish” is visible on the live site.
Provider and academy
Provider and academy were assigned for the prototype from codes and categories; to be confirmed course by course.
Findings in the export itself
Measured on the files- Authorship is a login name. Of 58 exported courses, 29 are authored by a user called “MALYOMAR”, 18 by the owner's personal login, 9 by a user called “ASME”, and 2 by other accounts. This is the source of the “course author” entries in the instructor directory.
- Language is mostly empty. 39 of 58 courses have no language set.
- No currency field. Price is a bare number.
- Duplicate markers. Topics, lessons and quizzes carry dozens of “course duplicate” columns left by copying courses; they show which items were cloned and may be stale.
- Encoding damage. Some descriptions contain broken characters where non-breaking spaces were.
- Four exported courses are not in the prototype catalog. 58 rows in the export, in the catalog data; the four left out are a trashed test course, an empty “New Course” draft, a duplicate “(Copy 1)” of the Fitness-for-Service course and a private physics handbook. Confirm they should stay out.
Approach. Do not copy the WordPress structure. Map each source field to the new record, clean it on the way in, and let a person confirm every course on the import screen before it is published. The old site stays read-only until cut-over.
| Tutor LMS / WordPress field | New record and field | Rule on the way in | Check |
|---|---|---|---|
| ID | Course.legacyId | Kept for redirects and for linking topics and lessons | Automatic |
| Title | Course.courseCode + courseTitle | Split the code (PD643, ML513) from the title; items without a code get a temporary one and are held | Review |
| Slug, Permalink | Course.slug, redirect table | Old address redirects to the new course page | Automatic |
| Content | Course.fullDescription | Strip page-builder markup, fix encoding, keep paragraphs | Review |
| Excerpt | Course.shortDescription | Trim to card length; draft with AI where empty, marked as draft | Review |
| _tutor_course_benefits | Course.learningObjectives[] | One line becomes one outcome | Automatic |
| _tutor_course_target_audience | Course.targetAudience[] | Split lines; normalise to the persona list | Review |
| _tutor_course_requirements | Course.prerequisites[] | Split lines; link to courses where a code is mentioned | Review |
| _tutor_course_material_includes | Course.materialsIncluded[] | Split lines | Automatic |
| _tutor_course_level | Course.level | beginner, intermediate, expert become Foundation, Practitioner, Advanced | Automatic |
| _course_duration_in_seconds | Course.durationHours | Convert; empty stays empty and blocks publishing | Fix at source |
| tutor_course_price, tutor_course_sale_price | Course.price, currency | Currency set by decision; outliers held for confirmation | Fix at source |
| Course Language | Course.language | Empty in most rows; set per course | Fix at source |
| Course Categories | Course.school (Academy), category | Ten WordPress categories fold into five academies | Review |
| Course Tags | Course.standards[], software[] | Tags naming a code or a tool move to the right list | Review |
| Author Username | Course.providerType | “ASME” becomes provider ASME; “MALYOMAR” and personal logins become provider MALYOMAR unless the code is an ASME code. Never becomes an instructor | Review |
| (Tutor instructor assignment) | Course.instructorIds[] | Only real people; “Course Author” accounts are dropped | Review |
| Status | Course.status | publish becomes Published after checks; pending becomes In review; draft stays Draft; private becomes Internal | Automatic |
| Image URL | Course.heroImage | Download and store; replace where the image carries text | Review |
| Topics export: Title, Parent, Order | Course.curriculum[] topic | Linked by legacy course ID, ordered | Automatic |
| Lesson export: Title, Content, _video, _tutor_attachments, _is_preview | Lesson under its topic | Video and files re-hosted; preview flag kept | Review |
| Quiz export: Title, tutor_quiz_option | Quiz (settings only) | Questions pulled separately or re-entered | Fix at source |
| WordPress users with the student role | Contact, Learner | De-duplicate by email; ask for consent again where missing | Review |
| Tutor enrolments and completion | Enrolment (historic) | Imported as history without a batch; flagged “legacy” | Review |
| Shop orders | Order, Payment (historic) | Read-only archive; not re-invoiced | Automatic |
Target fields are defined on the data model.
Migration steps
Courses first, people second, history last- InventoryAgree the list of sources and get the missing pulls
- Decide the masterPer field: site, Access or workbook
- Clean at sourceHours, prices, language, codes
- Trial importAll courses into a test hub
- ReviewEach course confirmed by its owner
- People and historyLearners, enrolments, certificates
- Cut-overRedirects on, old site read-only
- RetireArchive Tutor LMS after a quiet period
What each step delivers
| Step | Who | Done when |
|---|---|---|
| 1. Inventory | Owner, developer | Learner, enrolment, order and certificate exports are in hand; Access database opened and described |
| 2. Decide the master | Owner | A one-page table: for each Course field, the winning source |
| 3. Clean at source | Operations, instructors | No published course lacks hours, price, currency, language or provider |
| 4. Trial import | Developer | Import runs end to end and reports every row it changed or held |
| 5. Review | Course owners | Every course on the import screen is confirmed or parked |
| 6. People and history | Developer, support | Learners can sign in and see past courses and certificates |
| 7. Cut-over | Developer, owner | Old addresses redirect; new enrolments go only to the hub |
| 8. Retire | Owner | Backup stored; plugins and hosting cancelled |
Risks
| Risk | Likelihood | Response |
|---|---|---|
| Sources disagree and nobody knows which is right | High | Step 2 before any import; one named owner per academy |
| Wrong prices or currency published | Medium | Outliers held; price approval by the owner before publish |
| ASME content altered during clean-up | Medium | ASME program text locked on import; only layout changes |
| Learner history incomplete or cannot be exported | Medium | Database-level pull early in phase 0; accept “legacy” records |
| Past certificates cannot be verified after cut-over | Medium | Import issued certificates with codes, or publish a legacy lookup |
| Search ranking lost when addresses change | Medium | Redirect table from every old slug; keep titles stable at launch |
| Learners must reset passwords | Certain | Announce ahead; one-click activation email |
| Opening data for HR, purchasing and accounting collected late or loaded twice | Medium | Treat as its own task with a named owner per module; load only after the accounting and payroll boundaries are decided (DEC-01, DEC-08) |
| Orders in flight during cut-over | Low | Freeze the old checkout for a short window; handle by hand |
Where AI helps in migration. Drafting missing short descriptions, proposing the academy and level for uncategorised courses, and spotting near-duplicate topics. Each proposal is shown beside the original on the import screen and needs a person to accept it. See AI layer.