Skip to content

Knowledge Presentation – Bilingual Template Migration

One of the greatest challenges during the Knowledge Presentation migration was not designing the new architecture—it was getting there safely.

The project contained dozens of presentation templates accumulated over years of development. These templates powered portals, search results, taxonomy archives, directory pages, featured content, and numerous custom page templates.

Replacing every template simultaneously would have required a risky “big bang” deployment where hundreds of files changed at once.

Instead, the migration adopted a bilingual architecture.


The Migration Problem

Before the migration, nearly every presentation template expected a WP_Query.

Template

↓

WP_Query

↓

while ($query->have_posts())

↓

Render HTML

The new Presentation Engine, however, no longer worked with raw queries.

Instead, it produced normalized cards.

Template

↓

Card Collection

↓

foreach ($items)

↓

Render HTML

This created an incompatibility.

If templates were converted immediately, every legacy page would fail.
If templates remained unchanged, the new Presentation Engine could not use them.


The Solution

Instead of choosing one architecture or the other, every template temporarily supported both.

Legacy Caller

↓

WP_Query

↓

Template

↑

↓

Normalized Cards

↑

Presentation Engine

Both pipelines remained functional while the migration progressed.


The Standard Contract

Every grid and list template adopted the same interface.

$query       = $args['query'] ?? null;
$items       = $args['items'] ?? [];
$info        = $args['info'] ?? [];
$search_term = $args['search_term'] ?? '';

This became the standard contract across the entire presentation system.


Automatic Conversion

When a legacy caller supplied a WP_Query, the template converted each post into a normalized card before rendering.

if ($query instanceof WP_Query) {

    while ($query->have_posts()) {

        $query->the_post();

        $items[] = kp_build_card(
            $type,
            get_the_ID(),
            $map
        );

    }

}

After conversion, the remainder of the template ignored the original query completely.


One Rendering Path

The most important design decision was that rendering always happened from the normalized cards.

Old Caller

↓

WP_Query

↓

Convert

↓

Cards

↓

Render


New Caller

↓

Cards

↓

Render

Regardless of where the data originated, there was only one rendering path.


Preserving Legacy Behaviour

Some templates had historically generated their own default queries when no data was supplied.

For example:

if (!$query) {

    $query = new WP_Query([
        'post_type' => 'book',
        ...
    ]);

}

These fallbacks were intentionally preserved.

As a result, existing page templates continued functioning without modification while newer systems gradually adopted the collector architecture.


Why Not Rewrite Everything?

Large migrations often fail because every subsystem changes simultaneously.

The bilingual approach intentionally avoided this.

  • Old pages continued working.
  • New architecture could be deployed immediately.
  • Templates were upgraded individually.
  • Regression testing became manageable.
  • Failures were isolated to a single content type.

Incremental Migration

Rather than converting every content type at once, each CPT followed the same process.

Choose CPT

↓

Create Card Builder

↓

Convert Template

↓

Verify Legacy Pages

↓

Verify Knowledge View

↓

Proceed to Next CPT

This dramatically reduced debugging complexity.


Testing Strategy

A dedicated Portal became the primary migration tool.

One representative object from each content type was assigned to a single testing taxonomy.

Portal

├── Book
├── Song
├── Movie
├── Artist
├── Quote
├── Fragment
├── Element
├── Game
├── Image
└── ...

Whenever a template was migrated, this Portal immediately revealed whether that content type rendered correctly.

If a section failed, the affected template could be identified within seconds.


Unexpected Benefits

The bilingual templates produced several benefits beyond compatibility.

  • Consistent template interfaces.
  • Simpler debugging.
  • Reusable rendering logic.
  • Cleaner separation between business logic and presentation.
  • Future migrations become significantly easier.

The Temporary Nature of the Design

Although bilingual templates became a critical migration tool, they were never intended to be permanent.

Once every caller uses the Knowledge Collector and Presentation Engine, support for legacy WP_Query inputs can eventually be removed.

At that point, every presentation template will accept exactly one input:

$items

The migration layer disappears, leaving behind a significantly simpler architecture.


A General Migration Pattern

The bilingual strategy illustrates a broader engineering principle:

Do not force old and new architectures to compete. Allow them to coexist behind a common interface until the migration is complete.

This approach minimizes risk, enables incremental testing, and keeps production systems functional throughout large refactoring efforts.

Although developed during the Knowledge Presentation migration, this pattern is applicable to many software projects where a mature codebase must transition to a fundamentally different architecture without sacrificing stability.