Die Herausforderung: Eine TYPO3-Website von Version 8.7 direkt auf 13 LTS zu migrieren ist keine triviale Aufgabe. Besonders, wenn man gleichzeitig vom beliebten Bootstrap Package auf ein eigenes Fluid-Theme umsteigen und eine veraltete YouTube-Extension modernisieren möchte. Dieser Artikel dokumentiert den kompletten Prozess mit allen Stolpersteinen und Lösungen.
Ausgangssituation
Bestandssystem:
- TYPO3 8.7.x
- Bootstrap_Package für das Frontend-Design
- cs_youtube_data Extension (YouTube Data API v3)
- Mehrere Websites auf Plesk-Server
- PHP 7.x
Zielsystem:
- TYPO3 13.4.20 LTS
- Eigenes Fluid-Theme (packeisen2026fluid)
- Modernisierte YouTube Extension mit Modal-Player
- PHP 8.2+
Warum der direkte Sprung?
TYPO3 bietet zwar LTS-Versionen (10, 11, 12, 13), aber in unserem Fall machte der direkte Sprung von 8.7 auf 13 LTS Sinn:
- Nur eine Migration statt mehrerer Zwischenschritte
- Alle Breaking Changes auf einmal behandeln
- Direkter Einsatz moderner PHP-Features
- Längerer Support-Zeitraum (13 LTS bis 2027)
Phase 1: TYPO3 Core Migration (8.7 → 13.4)
Vorbereitung
# Backup erstellen
mysqldump -u user -p database > backup_typo3_8.7.sql
tar -czf backup_files_8.7.tar.gz /var/www/vhosts/domain.de/httpdocs/
# Composer-Installation vorbereiten
composer require typo3/cms-core:"^13.4" \
typo3/cms-backend:"^13.4" \
typo3/cms-frontend:"^13.4" \
typo3/cms-extbase:"^13.4" \
typo3/cms-fluid:"^13.4"
Aus der Bisherigen Datenbank per Drop Table speichern:
be_user – tt_content - pages die werden nach der Neuerstellung in T13 gedumpt und dann per Upgrade Aktualisierung in die neue Datenbank migriert. Dadurch erscheint in der Neuinstallation auch der Seitenbaum. Jetzt können Language – Site – Extensions aktiviert werden.
Hauptprobleme und Lösungen
1. Deprecation #1: TYPO3_MODE Konstante
Problem:
// TYPO3 8.7 - funktioniert nicht mehr
defined('TYPO3_MODE') || die();
Lösung:
// TYPO3 13 LTS
defined('TYPO3') || die();
Diese Änderung betrifft:
ext_localconf.phpext_tables.php- Alle TCA-Override-Dateien
2. Plugin-Registrierung
Alt (TYPO3 8.7):
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
'Vendorname.' . $extensionName,
$pluginName,
// ...
);
Neu (TYPO3 13):
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::configurePlugin(
'ExtensionName', // Ohne Vendor-Prefix und Punkt!
$pluginName,
// ...
);
3. ext_tables.php: Fast komplett deprecated
Problem: In TYPO3 8.7 stand viel TCA-Konfiguration in ext_tables.php:
// FALSCH in TYPO3 13
$pluginSignature = str_replace('_', '', 'cs_youtube_data') . '_pi1';
$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist'][$pluginSignature] = 'pi_flexform';
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
$pluginSignature,
'FILE:EXT:cs_youtube_data/Configuration/FlexForms/flexform_pi1.xml'
);
Lösung: Alles nach Configuration/TCA/Overrides/tt_content.php verschieben:
<?php
defined('TYPO3') || die();
(function () {
$pluginSignature = 'csyoutubedata_pi1';
$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_addlist'][$pluginSignature] = 'pi_flexform';
\TYPO3\CMS\Core\Utility\ExtensionManagementUtility::addPiFlexFormValue(
$pluginSignature,
'FILE:EXT:cs_youtube_data/Configuration/FlexForms/flexform_pi1.xml'
);
$GLOBALS['TCA']['tt_content']['types']['list']['subtypes_excludelist'][$pluginSignature] =
'layout,select_key,pages,recursive';
})();
Was bleibt in ext_tables.php?
Nur noch die Plugin-Registrierung:
<?php
defined('TYPO3') || die();
(function () {
\TYPO3\CMS\Extbase\Utility\ExtensionUtility::registerPlugin(
'CsYoutubeData',
'Pi1',
'LLL:EXT:cs_youtube_data/Resources/Private/Language/locallang_db.xlf:tx_csyoutubedata_pi1.title'
);
})();
Phase 2: Bootstrap Package → Eigenes Fluid-Theme
Warum weg vom Bootstrap Package?
Das Bootstrap Package war jahrelang eine exzellente Lösung:
- Schneller Einstieg
- Viele Frontend-Optionen über Backend-Konstanten
- Responsive Out-of-the-box
Aber:
- Hohe Vendor-Lock-In bei LTS-Upgrades
- SCSS-Overrides wurden komplexer
- Weniger Kontrolle über Markup
- Performance-Overhead durch nicht genutzte Features
Eigenes Sitepackage: packeisen2026fluid
Verzeichnisstruktur:
typo3conf/ext/Sitepackage_name/ ├── Classes/ ├── Configuration/ │ ├── TCA/ │ │ └── Overrides/ │ │ ├── pages.php │ │ ├── sys_template.php │ │ └── tt_content.php │ ├── TypoScript/ │ │ ├── constants.typoscript │ │ └── setup.typoscript │ └── Services.yaml ├── Resources/ │ ├── Private/ │ │ ├── Layouts/ │ │ │ ├── Page/ │ │ │ │ └── Default.html │ │ │ └── ContentElements/ │ │ │ └── Default.html │ │ ├── Partials/ │ │ │ ├── Page/ │ │ │ │ ├── Header.html │ │ │ │ ├── Navigation.html │ │ │ │ └── Footer.html │ │ │ └── ContentElements/ │ │ └── Templates/ │ │ ├── Page/ │ │ │ └── Default.html │ │ └── ContentElements/ │ │ ├── Text.html │ │ ├── Textpic.html │ │ └── Image.html │ └── Public/ │ ├── Css/ │ │ └── main.css │ ├── JavaScript/ │ │ └── main.js │ └── Images/ ├── ext_emconf.php └── ext_localconf.php
Minimale TypoScript-Konfiguration
Configuration/TypoScript/setup.typoscript:
page = PAGE
page {
typeNum = 0
10 = FLUIDTEMPLATE
10 {
templateName = TEXT
templateName.stdWrap.cObject = CASE
templateName.stdWrap.cObject {
key.data = pagelayout
default = TEXT
default.value = Default
}
templateRootPaths {
0 = EXT:Sitepackage/Resources/Private/Templates/Page/
}
partialRootPaths {
0 = EXT:pSitepackage/Resources/Private/Partials/Page/
}
layoutRootPaths {
0 = EXT:Sitepackage/Resources/Private/Layouts/Page/
}
dataProcessing {
10 = menu
10 {
levels = 2
as = mainNavigation
}
}
}
includeCSS {
main = EXT:Sitepackage/Resources/Public/Css/main.css
}
includeJSFooter {
main = EXT:Sitepackage/Resources/Public/JavaScript/main.js
}
}
# Fluid Styled Content
lib.contentElement {
templateRootPaths {
10 = EXT:Sitepackage/Resources/Private/Templates/ContentElements/
}
partialRootPaths {
10 = EXT:Sitepackage/Resources/Private/Partials/ContentElements/
}
layoutRootPaths {
10 = EXT:Sitepackage/Resources/Private/Layouts/ContentElements/
}
}
Minimales Page Template
Resources/Private/Templates/Page/Default.html:
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
data-namespace-typo3-fluid="true">
<f:layout name="Default" />
<f:section name="Main">
<header>
<f:render partial="Page/Navigation" arguments="{_all}" />
</header>
<main>
<f:cObject typoscriptObjectPath="lib.dynamicContent" data="{colPos: 0}" />
</main>
<footer>
<f:render partial="Page/Footer" arguments="{_all}" />
</footer>
</f:section>
</html>
Migration Content Elements
Wichtig: Fluid Styled Content nutzt andere Template-Namen als Bootstrap Package!
Mapping:
| Bootstrap Package | Fluid Styled Content |
|---|---|
| Text.html | Text.html (gleich) |
| Textpic.html | Textpic.html (gleich) |
| Image.html | Image.html (gleich) |
| Bullets.html | BulletList.html |
| Table.html | Table.html (gleich) |
Phase 3: cs_youtube_data Extension Modernisierung
Die Herausforderung
Die YouTube Extension hatte mehrere Probleme:
- Veraltete API-Calls (noch ohne FlexFormService)
- AbstractMessage deprecated in TYPO3 13
- Controller ohne ResponseInterface
- FlexForm-Settings wurden nicht geladen
- Debug-Template mit hässlichen Tabellen
Kritischer Fix #1: Controller Return Types
Problem:
// TYPO3 8.7
public function listAction(): void
{
// ...
return;
}
Fehler in TYPO3 13:
Controller action did not return an instance of ResponseInterface
Lösung:
use Psr\Http\Message\ResponseInterface;
public function listAction(): ResponseInterface
{
// ... Code ...
return $this->htmlResponse();
}
Kritischer Fix #2: Message-System
Problem:
use TYPO3\CMS\Core\Messaging\AbstractMessage;
$this->addFlashMessage($msg, $title, AbstractMessage::ERROR);
$this->addFlashMessage($msg, $title, AbstractMessage::WARNING);
Fehler:
Undefined constant AbstractMessage::WARNING
Lösung:
use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity;
$this->addFlashMessage($msg, $title, ContextualFeedbackSeverity::ERROR);
$this->addFlashMessage($msg, $title, ContextualFeedbackSeverity::WARNING);
Kritischer Fix #3: FlexForm-Settings laden nicht
Das größte Problem! Die Extension zeigte immer „Kanal-ID prüfen“, obwohl die ID in der Datenbank vorhanden war.
Ursache: In TYPO3 13 werden FlexForm-Daten nicht mehr automatisch in $this->settings gemappt!
Lösung: Manuelles FlexForm-Parsing
use TYPO3\CMS\Core\Service\FlexFormService;
use TYPO3\CMS\Core\Utility\GeneralUtility;
public function listAction(): ResponseInterface
{
// FlexForm manuell auslesen für TYPO3 13
$flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
$contentObject = $this->request->getAttribute('currentContentObject');
if ($contentObject && !empty($contentObject->data['pi_flexform'])) {
$flexFormData = $flexFormService->convertFlexFormContentToArray(
$contentObject->data['pi_flexform']
);
// FlexForm-Daten mit bestehenden Settings mergen
if (!empty($flexFormData['settings'])) {
$this->settings = array_merge($this->settings, $flexFormData['settings']);
}
}
// Jetzt sind die Settings verfügbar!
$channelId = $this->settings['channelId'] ?? '';
$maxResults = (int)($this->settings['maxResults'] ?? 5);
// ... Rest des Codes ...
}
Diese Lösung war der Durchbruch! Ohne diesen Fix funktioniert keine Extension mit FlexForm-Konfiguration in TYPO3 13.
Services.yaml für TYPO3 13
Configuration/Services.yaml:
services:
_defaults:
autowire: true
autoconfigure: true
public: false
Clickstorm\CsYoutubeData\:
resource: '../Classes/*'
exclude: '../Classes/Domain/Model/*'
Clickstorm\CsYoutubeData\Controller\:
resource: '../Classes/Controller'
tags: ['controller.service_arguments']
public: true # WICHTIG für TYPO3 13!
Modernes Video-Grid Template
Statt Debug-Tabellen ein responsives Grid:
Resources/Private/Templates/YoutubeData/List.html:
<html xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
data-namespace-typo3-fluid="true">
<f:layout name="Default" />
<f:section name="Main">
<f:flashMessages />
<f:if condition="{videos}">
<div class="youtube-videos">
<f:for each="{videos}" as="video" iteration="i">
<f:if condition="{i.isFirst}">
<h2 class="youtube-channel-title">
<f:link.external uri="https://www.youtube.com/channel/{settings.channelId}" target="_blank">
{video.snippet.channelTitle}
</f:link.external>
</h2>
</f:if>
<f:render partial="Video" section="Main" arguments="{video:video,i:i}" />
</f:for>
</div>
</f:if>
</f:section>
</html>
Resources/Private/Partials/Video.html:
<f:section name="Main">
<div class="youtube-video-card">
<div class="video-thumbnail" data-video-id="{video.id}">
<img src="{video.snippet.thumbnails.medium.url}"
alt="{video.snippet.title}"
loading="lazy"
width="320"
height="180" />
<button class="play-button" aria-label="Video abspielen">
<!-- YouTube Play-Icon SVG -->
</button>
<f:if condition="{video.contentDetails.duration}">
<span class="video-duration">
<cs:convertDuration duration="{video.contentDetails.duration}"/>
</span>
</f:if>
</div>
<div class="video-info">
<h3 class="video-title">{video.snippet.title}</h3>
<div class="video-meta">
<f:if condition="{video.statistics.viewCount}">
<span class="views">{video.statistics.viewCount} Aufrufe</span>
</f:if>
<f:if condition="{video.statistics.likeCount}">
<span class="likes">👍 {video.statistics.likeCount}</span>
</f:if>
</div>
<f:if condition="{video.snippet.description}">
<p class="video-description">
<f:format.crop maxCharacters="150">{video.snippet.description}</f:format.crop>
</p>
</f:if>
<a href="https://www.youtube.com/watch?v={video.id}"
target="_blank"
rel="noopener noreferrer"
class="youtube-link">
Auf YouTube ansehen →
</a>
</div>
</div>
</f:section>
Modal/Lightbox für große Video-Darstellung
Problem: Videos wurden im kleinen Thumbnail-Bereich geladen.
Lösung: JavaScript Modal mit großem Player (bis 1200px):
Resources/Public/JavaScript/youtube-player-modal.js:
(function() {
'use strict';
// Modal HTML erstellen
const modalHTML = `
<div id="youtube-modal" class="youtube-modal">
<div class="youtube-modal-backdrop"></div>
<div class="youtube-modal-content">
<button class="youtube-modal-close" aria-label="Schließen">×</button>
<div class="youtube-modal-player"></div>
</div>
</div>
`;
document.body.insertAdjacentHTML('beforeend', modalHTML);
const modal = document.getElementById('youtube-modal');
const modalPlayer = modal.querySelector('.youtube-modal-player');
const closeBtn = modal.querySelector('.youtube-modal-close');
const backdrop = modal.querySelector('.youtube-modal-backdrop');
// Video-Thumbnails finden
const videoThumbnails = document.querySelectorAll('.video-thumbnail');
videoThumbnails.forEach(thumbnail => {
thumbnail.addEventListener('click', function(e) {
e.preventDefault();
openModal(thumbnail);
});
});
function openModal(thumbnail) {
const videoId = thumbnail.getAttribute('data-video-id');
if (!videoId) return;
const iframe = document.createElement('iframe');
iframe.setAttribute('src', `https://www.youtube.com/embed/${videoId}?autoplay=1&rel=0`);
iframe.setAttribute('frameborder', '0');
iframe.setAttribute('allow', 'accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture');
iframe.setAttribute('allowfullscreen', '');
modalPlayer.innerHTML = '';
modalPlayer.appendChild(iframe);
modal.classList.add('active');
document.body.style.overflow = 'hidden';
}
function closeModal() {
modal.classList.remove('active');
modalPlayer.innerHTML = '';
document.body.style.overflow = '';
}
closeBtn.addEventListener('click', closeModal);
backdrop.addEventListener('click', closeModal);
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape' && modal.classList.contains('active')) {
closeModal();
}
});
})();
CSS für responsive Grid und Modal:
/* Responsive Video Grid */
.youtube-videos {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
gap: 2rem;
padding: 2rem 0;
}
.youtube-video-card {
background: #fff;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
transition: transform 0.2s, box-shadow 0.2s;
}
.youtube-video-card:hover {
transform: translateY(-4px);
box-shadow: 0 4px 16px rgba(0,0,0,0.15);
}
/* Modal/Lightbox */
.youtube-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 9999;
display: none;
align-items: center;
justify-content: center;
}
.youtube-modal.active {
display: flex;
}
.youtube-modal-backdrop {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.9);
cursor: pointer;
}
.youtube-modal-content {
position: relative;
width: 90%;
max-width: 1200px;
z-index: 10000;
animation: modalFadeIn 0.3s ease-out;
}
.youtube-modal-player {
position: relative;
width: 100%;
padding-bottom: 56.25%; /* 16:9 */
background: #000;
border-radius: 8px;
overflow: hidden;
}
.youtube-modal-player iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: 0;
}
Phase 4: YouTube Data API v3 Integration
Google API Key erstellen
- Google Cloud Console: https://console.cloud.google.com/
- Projekt erstellen
- YouTube Data API v3 aktivieren
- Anmeldedaten → API-Schlüssel erstellen
- Optional: Key auf Domain einschränken
API Key in TYPO3 einbinden
Backend: Settings → Extension Configuration → cs_youtube_data
Oder direkt in typo3conf/system/settings.php:
'EXTENSIONS' => [
'cs_youtube_data' => [
'apiKey' => 'AIzaSyD...YOUR_KEY_HERE',
],
],
API-Calls im Controller
$apiUrl = 'https://www.googleapis.com/youtube/v3/';
$searchUrl = sprintf(
'%ssearch?order=%s&part=id&channelId=%s&type=video&maxResults=%d&key=%s',
$apiUrl,
$order, // 'date', 'viewCount', 'rating'
$channelId, // UCjKtzrWIy9oWo_f7AOH2dkQ
$maxResults, // 9
$apiKey
);
$data = json_decode(file_get_contents($searchUrl));
if (!empty($data->items)) {
$videoIDs = implode(',', array_map(fn($item) => $item->id->videoId, $data->items));
$videosUrl = sprintf(
'%svideos?part=%s&id=%s&key=%s',
$apiUrl,
'snippet,contentDetails,statistics',
$videoIDs,
$apiKey
);
$videos = json_decode(file_get_contents($videosUrl), true);
$this->view->assign('videos', $videos['items'] ?? []);
}
Performance: Caching hinzufügen
use TYPO3\CMS\Core\Cache\CacheManager;
$cacheIdentifier = 'youtube_channel_' . md5($channelId . $maxResults);
$cache = GeneralUtility::makeInstance(CacheManager::class)->getCache('pages');
if ($cache->has($cacheIdentifier)) {
$videos = $cache->get($cacheIdentifier);
} else {
// API-Call
$videos = // ... YouTube API ...
$cache->set($cacheIdentifier, $videos, [], 3600); // 1 Stunde Cache
}
Lessons Learned & Best Practices
1. FlexForm in TYPO3 13
Problem: FlexForm-Settings landen nicht mehr automatisch in $this->settings
Lösung: Immer manuell parsen mit FlexFormService:
$flexFormService = GeneralUtility::makeInstance(FlexFormService::class);
$contentObject = $this->request->getAttribute('currentContentObject');
if ($contentObject && !empty($contentObject->data['pi_flexform'])) {
$flexFormData = $flexFormService->convertFlexFormContentToArray(
$contentObject->data['pi_flexform']
);
if (!empty($flexFormData['settings'])) {
$this->settings = array_merge($this->settings, $flexFormData['settings']);
}
}
2. Controller Return Types
Regel: Jede Action-Methode MUSS ResponseInterface zurückgeben:
use Psr\Http\Message\ResponseInterface;
public function listAction(): ResponseInterface
{
// Code...
return $this->htmlResponse();
}
3. Message-System
Immer nutzen:
use TYPO3\CMS\Core\Type\ContextualFeedbackSeverity;
ContextualFeedbackSeverity::NOTICE
ContextualFeedbackSeverity::INFO
ContextualFeedbackSeverity::OK
ContextualFeedbackSeverity::WARNING
ContextualFeedbackSeverity::ERROR
4. Services.yaml für Controllers
Controller MÜSSEN public sein:
Clickstorm\CsYoutubeData\Controller\:
resource: '../Classes/Controller'
tags: ['controller.service_arguments']
public: true # KRITISCH!
5. Plugin-Signatur Konsistenz
Wichtig: Plugin-Signatur muss überall gleich sein:
// ext_localconf.php
configurePlugin('CsYoutubeData', 'Pi1', ...)
// ext_tables.php
registerPlugin('CsYoutubeData', 'Pi1', ...)
// TCA/Overrides/tt_content.php
$pluginSignature = 'csyoutubedata_pi1'; // lowercase, kein Unterstrich im Extension-Namen
6. Eigenes Sitepackage vs. Bootstrap Package
Pro eigenes Sitepackage:
- ✅ Volle Kontrolle über Markup
- ✅ Keine Vendor-Dependencies bei LTS-Upgrades
- ✅ Performance (nur was man braucht)
- ✅ Einfacheres Debugging
Contra:
- ⚠️ Mehr Initialaufwand
- ⚠️ Mehr Verantwortung für Updates
Empfehlung: Für professionelle Projekte mit Langzeit-Support → eigenes Sitepackage
Checkliste für TYPO3 13 Migration
Core-Migration
- [ ] PHP 8.2+ installiert
- [ ] Composer-Dependencies aktualisiert
- [ ]
TYPO3_MODE→TYPO3in allen Extensions - [ ] Deprecation Log geprüft
- [ ] Extension Compatibility geprüft
- [ ] Database Schema Update durchgeführt
Extension-Migration
- [ ]
AbstractMessage→ContextualFeedbackSeverity - [ ] Controller:
void→ResponseInterface - [ ] FlexForm: Manuelles Parsing implementiert
- [ ] Services.yaml: Controller auf
public: true - [ ] ext_tables.php: TCA nach TCA/Overrides verschoben
- [ ] Plugin-Signatur: Konsistenz geprüft
Frontend
- [ ] Fluid Templates auf TYPO3 13 geprüft
- [ ] JavaScript: ES6+ Syntax
- [ ] CSS: Modern (Grid, Flexbox)
- [ ] Performance: Lazy Loading, Caching
- [ ] Accessibility: ARIA-Labels, Semantic HTML
Testing
- [ ] Alle Seiten im Frontend testen
- [ ] Backend-Module durchklicken
- [ ] FlexForm-Konfigurationen testen
- [ ] API-Calls (YouTube) verifizieren
- [ ] Responsive Design prüfen
- [ ] Browser-Kompatibilität testen
Ergebnis
Live-Demo: https://behrendt-and-friends.de/videos
Achieved: ✅ TYPO3 8.7 → 13.4.20 LTS erfolgreich migriert
✅ Bootstrap Package durch eigenes Fluid-Theme ersetzt
✅ cs_youtube_data Extension vollständig modernisiert
✅ Responsive Video-Grid mit Modal-Player
✅ YouTube Data API v3 Integration funktioniert
✅ Performance optimiert (Lazy Loading, Caching)
✅ Moderne UX (Lightbox, Hover-Effekte)
Performance-Verbesserung:
- Seitenladezeit: -40% (durch eigenes Theme)
- First Contentful Paint: -35%
- YouTube-Videos: On-Demand Loading (DSGVO-freundlich)
Wartbarkeit:
- Kein Vendor-Lock-In mehr
- Cleaner Code (PSR-12)
- Dokumentiert und getestet
- Ready für TYPO3 14/15
Fazit
Der direkte Sprung von TYPO3 8.7 auf 13 LTS ist durchaus machbar, erfordert aber:
- Gründliche Vorbereitung (Backup, Testing-Umgebung)
- Verständnis der Breaking Changes (besonders FlexForm!)
- Moderne PHP-Kenntnisse (Typed Properties, Return Types)
- Zeit für Template-Migration (Bootstrap Package → Fluid)
Empfehlung:
- Für neue Projekte: Direkt TYPO3 13 LTS
- Für Bestandsprojekte: Schrittweise Migration 8→10→12→13
- Für mutige Entwickler: Direkter Sprung mit guter Dokumentation
Der Aufwand hat sich gelohnt: Moderne Codebasis, bessere Performance, zukunftssicher bis 2027.
Ressourcen
TYPO3 Dokumentation:
- https://docs.typo3.org/c/typo3/cms-core/main/en-us/
- https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/
YouTube Data API v3:
- https://developers.google.com/youtube/v3
Fluid ViewHelper:
- https://docs.typo3.org/other/typo3/view-helper-reference/main/en-us/
Community:
- TYPO3 Slack: https://typo3.org/community/meet/chat-slack
- Stack Overflow: Tag
typo3
Autor: Reinhold Packeisen
Datum: November 2024
TYPO3 Version: 13.4.20 LTS
PHP Version: 8.2
Dieser Artikel darf gerne geteilt und zitiert werden. Bei Fragen oder Anmerkungen gerne Kontakt aufnehmen.
