Von Drupal zu TYPO3: Ein No-Nonsense Migrations Playbook

Von Drupal zu TYPO3: Ein No-Nonsense Migrations Playbook

Kontrollieren Sie Ihr Datenmodell und Ihre URLs, und die Migration bleibt einfach. Dieses Handbuch bietet einen praktischen Weg von Drupal 11 zu TYPO3 13, saubere JSON/CSV-Exporte, präzise Zuordnungen, Twig→Fluid-Anleitungen, sichere 301-Weiterleitungen und wiederholbare Importe, denen Sie vertrauen können.

Schnelle Checkliste (konzeptionell)

  • Drupal-Entitäten → TYPO3-Datensätze und endgültige Slugs zuordnen.
  • TYPO3 13 Setup auswählen (Sites, Sprachen, Seitenbaum).
  • Export über JSON:API (oder CSV über Views); Dateien kopieren.
  • HTML/Assets normalisieren; Templates angleichen (Twig→Fluid).
  • Kategorien, Seiten/Datensätze, Medien und 301er importieren.
  • Anzahl, Links, SEO überprüfen; live gehen.
  • Quelle: Drupal 11 (gleicher Ablauf funktioniert für 9/10).
  • Ziel: TYPO3 13 LTS (empfohlen).
  • Einmal entscheiden: Seiten & Sprachen, Seitenbaum-Wurzeln und ob große Inhaltstypen zu Datensätzen (z.B. News/benutzerdefinierte TCA) oder Seiten werden. Alles andere folgt.
DrupalBeispielTYPO3 ZielHinweise
Node: Basisseite/aboutSeite + tt_contentStatischer Inhalt als Text-/Bildelemente.
Node: Artikel/Blog/blog/fooDatensatz (z.B. EXT:news) oder SeiteBevorzugen Sie Datensätze für Listen/Filter.
Taxonomiebegriff„Veranstaltungen“sys_categoryBehalten Sie Slugs bei; beziehen Sie sich auf Seiten/Datensätze.
BenutzerRedakteurebe_users / be_groups (Redakteure); fe_users / fe_groups (Seitenbenutzer)Trennen Sie Back-Office und Front-Office.
Datei/sites/default/files/*FAL (sys_file + sys_file_reference)Behalten Sie Dateinamen/Ordner zur Rückverfolgbarkeit bei.

Verwenden Sie die Migration, um den Umfang zu reduzieren. Markieren Sie nur das, was Sie wirklich in TYPO3 benötigen.

FunktionPrüfenTYPO3-Fähigkeit
PersonalisierungÜber Erweiterungen/Integrationen
eCommerceext:aimeos oder ext:commerce
Multi-SiteNative Sites-Unterstützung
Rollen/BerechtigungenGranulare BE/FE-Gruppen
HeadlessEXT:headless/benutzerdefinierte APIs
MehrsprachigkeitNatives Mehrsprachensystem
WorkflowWorkspaces (Entwurf/Überprüfung/Versionierung)
MedienFAL mit Speicher/Metadaten
Formulareext:form mit Editor
BarrierefreiheitWCAG-freundliche Ausgabe (Templating)
CLIKern und helhum/typo3-console

A) JSON:API (empfohlen und wiederholbar)

 

  • Inhalt: /jsonapi/node/{bundle} (z.B. Seite, Artikel)
    • Verwenden Sie ?include=field_image,uid,field_tags, um Beziehungen abzurufen.
    • Verwenden Sie ?page[limit]=N für die Paginierung; exportieren Sie pro Sprache mit filter[langcode]=….
  • Taxonomie: /jsonapi/taxonomy_term/{vocabulary}
  • Dateien: /jsonapi/file/file → verwenden Sie attributes.uri.url für die Download-URL.
  • Aliase (für 301s): /jsonapi/path_alias/path_alias → behalten Sie Quelle, Alias, langcode.

B) Ansichten → CSV (abgestimmt auf Ihren Importeur in §6B)

  • Erstellen Sie eine Drupal-Ansicht pro Entität (Seiten, Artikel, Kategorien, Benutzer, Weiterleitungen, Dateien).
  • Fügen Sie stabile Spalten ein: external_id (UUID), Slugs, Titel, HTML-Felder, Daten, Autor-E-Mail, Kategorie-Slugs, Bild-URL(s), Alias-Quellen/Ziele.
  • Halten Sie die Spaltennamen konsistent mit Ihrem TYPO3 CSV-Importeur, um Upserts und Wiederholungen zu ermöglichen. (Kein Code hier—nur die Spezifikationsausrichtung.)
Drupal-RolleTYPO3-Äquivalent
AdministratorBackend-Admin-Benutzer
Authentifizierter BenutzerFrontend-Benutzer (fe_users)
AnonymAnonymer Frontend-Zugang
Benutzerdefinierte RollenBenutzerdefinierte BE/FE-Gruppen
  • HTML: Entfernen Sie Drupal-spezifische Filter; konvertieren Sie Einbettungen in reines HTML oder geplante Inhaltselemente.
  • Medien: Kopieren Sie Binärdateien nach fileadmin/migrated/...; behalten Sie die Originaldateinamen bei; bereiten Sie eine alte-URL → neuer-Pfad-Karte vor.
  • Taxonomien: Erstellen Sie sys_category aus dem Export vor; verwenden Sie Slugs, wo möglich.
  • Benutzer: Importieren Sie nur benötigte Redakteure/Seitenbenutzer; ordnen Sie sie BE/FE-Gruppen zu.

Drupal Twig → TYPO3 Fluid Grundlagen

  • Layouts/Partials: Twig {% include %} → Fluid .
  • Schleifen/Bedingungen: Twig {% for %} / {% if %} → Fluid / .
  • URLs/Assets: Ersetzen Sie file_url() und feste Pfade durch FAL-gesteuerte Helfer und -View-Helper.
  • Menüs: Drupal-Menüs → TYPO3-Menü-Rendering aus dem Seitenbaum (TypoScript DataProcessors + Fluid).
  • Übersetzungen: Halten Sie Sprachschlüssel konsistent; TYPO3 website Sprache muss existieren, bevor Übersetzungen importiert werden.

A) JSON → TYPO3 (kompaktes PHP, ausgerichtet auf Drupal JSON:API)

Beispiel Drupal JSON

{
  "data": [{
    "type": "node--article",
    "id": "b5c1-uuid",
    "attributes": {
      "title": "Mein Artikel",
      "body": { "value": "<p>HTML…</p>", "format": "basic_html" },
      "created": "2025-05-01T10:20:30+00:00",
      "langcode": "de",
      "path": { "alias": "/blog/mein-artikel" }
    },
    "relationships": {
      "field_image": { "data": [{ "type": "file--file", "id": "f-uuid" }] },
      "field_tags":  { "data": [{ "type": "taxonomy_term--tags", "id": "t-uuid" }] }
    }
  }],
  "included": [{
    "type": "file--file",
    "id": "f-uuid",
    "attributes": {
      "filename": "hero.jpg",
      "uri": { "url": "https://example.com/sites/default/files/hero.jpg" }
    }
  }]
}

Abrufen & paginieren (auf Festplatte zwischenspeichern)

funktion fetchDocuments(string $url): array {
  $out = [];
  while ($url) {
    $json = json_decode(file_get_contents($url), true);
    if (!is_array($json)) break;
    $out[] = $json;
    $url = $json['links']['next']['href'] ?? null; // JSON:API Paginierung
  }
  return $out;
}
// Beispiel: Artikel mit Includes
$docs = fetchDocuments('https://drupal.example/jsonapi/node/article?filter[langcode]=en&include=field_image,uid,field_tags&page[limit]=50');
file_put_contents('stage/articles_en.json', json_encode($docs, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES));

Import Mapping (Konzept-Ebene Helfer; in TYPO3 ausführen)

$docs = json_decode(file_get_contents('stage/articles_en.json'), true);

function indexIncluded(array $doc): array {
  $files = $terms = [];
  foreach (($doc['included'] ?? []) as $res) {
    if ($res['type'] === 'file--file') {
      $files[$res['id']] = [
        'uuid' => $res['id'],
        'filename' => $res['attributes']['filename'] ?? '',
        'url' => $res['attributes']['uri']['url'] ?? null,
      ];
    } elseif (str_starts_with($res['type'], 'taxonomy_term--')) {
      $terms[$res['id']] = [
        'uuid' => $res['id'],
        'name' => $res['attributes']['name'] ?? '',
        'slug' => $res['attributes']['path']['alias'] ?? null
      ];
    }
  }
  return [$files, $terms];
}

foreach ($docs as $doc) {
  [$fileIndex, $termIndex] = indexIncluded($doc);

  foreach ($termIndex as $t) {
    upsertCategory($t['uuid'], ['title' => $t['name'], 'slug' => $t['slug'] ?: slugify($t['name'])]);
  }

  foreach ($doc['data'] as $node) {
    if ($node['type'] !== 'node--article') continue;

    $uuid  = $node['id'];
    $attr  = $node['attributes'];
    $rels  = $node['relationships'] ?? [];

    $title = $attr['title'] ?? '';
    $body  = $attr['body']['value'] ?? '';
    $lang  = $attr['langcode'] ?? 'en';
    $alias = $attr['path']['alias'] ?? null;
    $slug  = $alias ?: '/'.slugify($title);

    $pageUid = upsertPage($uuid, [
      'pid' => 0,
      'title' => $title,
      'slug' => $slug,
      'sys_language_uid' => langUid($lang),
    ]);

    insertTextElement($pageUid, normalizeHtml($body), $title);

    foreach ((array)($rels['field_image']['data'] ?? []) as $imgRef) {
      $fileMeta = $fileIndex[$imgRef['id']] ?? null;
      if (!$fileMeta || empty($fileMeta['url'])) continue;
      $fileUid = ensureFalFromUrl($fileMeta['url'], $fileMeta['filename']);
      attachImageToPage($pageUid, $fileUid);
    }

    foreach ((array)($rels['field_tags']['data'] ?? []) as $ref) {
      relatePageToCategory($pageUid, externalIdToCategoryUid($ref['id']));
    }

    if ($alias) rememberRedirect($alias, $slug, 301);
  }
}

flushRememberedRedirects();

/* Helper-Signaturen, die Sie mit TYPO3-APIs implementieren werden (DataHandler + FAL):
upsertCategory($externalId, $data): int
upsertPage($externalId, $data): int
insertTextElement($pid, $html, $header): int
ensureFalFromUrl($url, $filename): int
attachImageToPage($pageUid, $fileUid): void
relatePageToCategory($pageUid, $categoryUid): void
externalIdToCategoryUid($externalId): ?int
langUid($langcode): int
slugify($text): string
normalizeHtml($html): string
rememberRedirect($source, $target, $status): void
flushRememberedRedirects(): void
*/

B) CSV-Pfad mit T3Planet Migration Extension

Wenn Sie Drupal in CSVs exportieren können, die dem von T3Planet’s „Migrate WordPress to TYPO3“ verwendeten WordPress-Schema ähneln, können Sie dieses Tool auch für Drupal verwenden. Es ist ideal für Nicht-Entwickler-Teams und wiederholbare Trockenläufe.

Drupal-FunktionTYPO3 ExtensionSchlüssel
Nachrichten/BlogNachrichtensystemext:news
SEO (Meta/Sitemap)On-page SEOext:seo (Kern)
FormulareFormular-Frameworkext:form
NewsletterDirektmail / Integrationenext:direct_mail
eCommerceAimeosext:aimeos
WorkflowArbeitsbereicheKern
Drush-ähnliche CLITYPO3-KonsoleKern helhum/typo3-console

Halten Sie es vorhersehbar: stabile UUIDs, sauberes JSON/CSV, FAL für Medien und 301s für jeden Alias. Entscheiden Sie sich frühzeitig für Datensätze vs. Seiten, spiegeln Sie Kategorieschnecken und führen Sie Importe idempotent aus, bis die Differenz null ist. Dann versenden.

Ja. Exportieren Sie über JSON:API oder CSV, kopieren Sie Dateien, importieren Sie in TYPO3 13 und bewahren Sie URLs mit 301s auf.

Speichern Sie Drupal UUIDs als external_id in TYPO3 und führen Sie ein Upsert auf diesem Schlüssel durch. Wiederholungen aktualisieren anstatt zu duplizieren.

Verwenden Sie Datensätze (z.B. EXT:news oder ein benutzerdefiniertes TCA) für hohes Volumen, Filterung und Feeds. Halten Sie statische Inhalte als Seiten.

Erstellen Sie die endgültigen Slugs in TYPO3 neu und importieren Sie Drupal-Aliase in sys_redirect als 301s. Validieren Sie die wichtigsten URLs, Sprachvarianten und vermeiden Sie Redirect-Ketten.

Kopieren Sie Binärdateien, registrieren Sie jede Datei in FAL (sys_file + Metadaten) und verknüpfen Sie sie über sys_file_reference. Bewahren Sie die ursprünglichen Dateinamen/Ordner zur Überprüfung auf.

Ja. Exportieren Sie CSVs über Drupal Views und verwenden Sie die T3Planet-Migrationserweiterung. Es ist einfach zu überprüfen und zu wiederholen.

Erstellen Sie in Fluid neu: Ordnen Sie Twig-Blöcke/-Teile Fluid-Layouts/-Teilen zu und verwenden Sie FAL + <f:uri></f:uri>-Helfer für URLs/Assets.

Your One-Stop Solutions for Custom TYPO3 Development

  • A Decade of TYPO3 Industry Experience
  • 350+ Successful TYPO3 Projects
  • 87% Repeat TYPO3 Customers
TYPO3 Service
wolfgang weber

Post a Comment

×