Modernizing a Legacy Education Platform Without Letting the Old CMS Define the New Product
- Published
- by Vahagn Karamyan
- Industry
- Education
- Role
- Product Designer
- Company
- Business Development Group
- Views
- 1view
Intro
I worked on rebuilding and extending the Business Development Group education platform while preserving years of existing course content from its previous WordPress website.
The project was not simply a visual redesign.
We had to move an existing education business to a new platform while keeping old courses, translations, media and course-specific content working and at the same time give administrators the ability to create completely new courses directly inside the new system.
That created an architectural challenge that appears in many legacy migrations:
How do you preserve old content without allowing the structure of the old CMS to become the architecture of the new product?
We discovered the problem when a feature that worked perfectly for migrated courses completely disappeared on newly created ones.
Problem
One of the course-page sections was a cashback-related callout.
On courses imported from the old WordPress website, it appeared correctly.
But when an administrator created a new course directly in the new admin system, the cashback section did not appear at all.
At first, this looked like a normal frontend or admin-form bug.
The page existed.
The course itself was valid.
Other course information was displayed correctly.
There was no obvious reason why the section should behave differently depending on how the course had been created.
So we traced the feature through the system.
That investigation exposed the real problem.
The cashback section was not actually modeled as an independent feature of a course.
It was rendered inside a legacy profession course block and depended on two fields:
individual_title
and
individual_subtitle
Those fields had originally come from WordPress ACF data:
profession_block_individual_title
and
profession_block_individual_subtitle.
During migration, imported courses passed through the WordPress importer, which created the required CourseBlock records.
But manually created courses did not.
The new admin flow had no reason to create a WordPress-era profession block, so the cashback data structure simply did not exist for those courses.
The result was an accidental business rule:
Imported WordPress course → cashback section works
Course created in the new admin → cashback section disappears
Nobody had intentionally designed the product this way.
The behavior existed because the new platform had inherited an implementation detail from the old CMS.
Solution
The important realization was that this should not be fixed by adding another condition to the frontend.
The deeper issue was the product model.
We separated two concepts that had been treated as the same thing:
how the old WordPress site stored the information
and
what the information means in the new product.
The legacy profession block was an import format.
Cashback was a business capability.
Those should not have been permanently coupled.
Instead of forcing every newly created course to imitate the internal structure of an old WordPress course, we treated the cashback behavior as something that should belong to the current course experience.
Legacy courses still needed to preserve their imported data.
But new courses needed to be created using the new platform's own model.
This changed how we approached the broader migration as well.
For every inherited field or block, we started asking:
Is this part of the actual business domain, or is it only the way WordPress happened to represent the data?
If it was real business information, it should have a clear place in the new product.
If it was only migration scaffolding, it should remain an implementation detail rather than defining future functionality.
This allowed us to preserve historical content without requiring every future feature to reproduce the architecture of the previous CMS.
Lesson
The biggest lesson was that a successful data migration can still produce a poorly migrated product architecture.
It is possible to preserve every record correctly and still accidentally carry old structural assumptions into the new system.
Legacy systems contain two very different things:
business knowledge
and
implementation history.
Those need to be separated.
The business knowledge should survive the migration.
The implementation history usually should not.
Since this experience, I think about legacy modernization differently.
I no longer ask only:
“How do we migrate this field?”
I also ask:
“Why does this field exist, what business concept does it represent, and should the new product represent that concept in the same way?”
That question can prevent years of new development from being constrained by decisions made inside an old CMS.
Experience details
Context
We were rebuilding an existing education platform that had years of course content in WordPress while simultaneously introducing a new administration system for creating and managing courses directly in the new product. This meant the system had to support two realities at the same time: legacy imported content and newly created native content.
- Team size:
- 1
- Timeline:
- 1 week
- Company stage:
- Series A
- Project stage:
- Redesign
Constraints
Technical
We could not simply discard the legacy WordPress structures because existing courses still depended on migrated fields, translations and content blocks. At the same time, requiring every new course to reproduce the internal structure of WordPress would permanently couple the new platform to the CMS we were trying to replace.
Reflection
Lesson
If I approached a similar migration again, I would classify legacy fields much earlier into two groups: Domain data - information the new product genuinely needs. Migration structure - information that exists only because of the previous system.
What I'd do differently
I would make that distinction explicit before building new admin functionality.It would reduce the risk of discovering later that seemingly normal product features still depend on invisible assumptions from the legacy platform.
