diff --git a/packages/ep_theme/Classes/Command/MigrateGridelementsCommand.php b/packages/ep_theme/Classes/Command/MigrateGridelementsCommand.php
deleted file mode 100644
index 4781b46..0000000
--- a/packages/ep_theme/Classes/Command/MigrateGridelementsCommand.php
+++ /dev/null
@@ -1,218 +0,0 @@
- [container CType, first container colPos - 1, valid gridelements columns]
- */
- private const LAYOUTS = [
- 'halves' => ['ep_container_halves', 200, [21, 22]],
- 'thirds' => ['ep_container_thirds', 210, [31, 32, 33]],
- 'quarters' => ['ep_container_columns_quarters', 220, [41, 42, 43, 44]],
- 'halfAndTwoQuarters' => ['ep_container_half_and_two_quarters', 230, [51, 52, 53]],
- 'twoQuartersAndHalf' => ['ep_container_two_quarters_and_half', 240, [61, 62, 63]],
- ];
-
- /**
- * Content types whose template renders the header with settings.defaultHeaderType for layout 0
- */
- private const DEFAULT_HEADER_TYPES = ['text', 'textmedia', 'textpic'];
-
- private const RESET = [
- 'tx_gridelements_container' => 0,
- 'tx_gridelements_columns' => 0,
- 'tx_gridelements_children' => 0,
- 'tx_gridelements_backend_layout' => '',
- ];
-
- public function __construct(
- private readonly ConnectionPool $connectionPool,
- ) {
- parent::__construct();
- }
-
- protected function configure(): void
- {
- $this
- ->addOption('dry-run', null, InputOption::VALUE_NONE, 'Only show what would change')
- ->addOption('report', null, InputOption::VALUE_REQUIRED, 'Write every row that is not migrated 1:1 to this CSV file');
- }
-
- protected function execute(InputInterface $input, OutputInterface $output): int
- {
- $connection = $this->connectionPool->getConnectionForTable('tt_content');
- if (!$this->hasGridelementsColumns($connection)) {
- $output->writeln('No tx_gridelements_* columns in tt_content, nothing to do.');
- return Command::SUCCESS;
- }
-
- // Plain SQL on purpose: Connection::select() would apply the frontend restrictions (deleted, hidden, …)
- $grids = [];
- foreach ($connection->executeQuery('SELECT * FROM tt_content WHERE CType = ?', ['gridelements_pi1'])->iterateAssociative() as $row) {
- $grids[(int)$row['uid']] = $row;
- }
- $children = $connection->executeQuery(
- 'SELECT * FROM tt_content WHERE tx_gridelements_container > 0 AND CType <> ? ORDER BY uid',
- ['gridelements_pi1']
- )->fetchAllAssociative();
-
- if ((int)$connection->executeQuery('SELECT COUNT(*) FROM tt_content WHERE CType = ? AND sys_language_uid > 0', ['gridelements_pi1'])->fetchOne() > 0) {
- $output->writeln('Translated grids found; translations are not handled by this command.');
- return Command::FAILURE;
- }
-
- $updates = [];
- $counts = [];
- $report = [];
- $count = static function (string $key) use (&$counts): void {
- $counts[$key] = ($counts[$key] ?? 0) + 1;
- };
-
- foreach ($grids as $uid => $grid) {
- $layout = (string)$grid['tx_gridelements_backend_layout'];
- if (isset(self::LAYOUTS[$layout])) {
- $updates[$uid] = ['CType' => self::LAYOUTS[$layout][0], 'pi_flexform' => ''] + self::RESET;
- $count('grid ' . $layout . ((int)$grid['deleted'] ? ' (deleted)' : ''));
- continue;
- }
- // A grid without layout renders nothing; keep it restorable as an empty container
- $updates[$uid] = ['CType' => 'ep_container_halves', 'pi_flexform' => '', 'deleted' => 1] + self::RESET;
- $count('grid without layout → deleted');
- if (!(int)$grid['deleted']) {
- $report[] = [$grid, 'grid', 'grid without layout', 'deleted'];
- }
- }
-
- foreach ($children as $child) {
- $uid = (int)$child['uid'];
- $parent = $grids[(int)$child['tx_gridelements_container']] ?? null;
- $column = (int)$child['tx_gridelements_columns'];
-
- if ((int)$child['colPos'] >= 0) {
- // Rendered in its page column, not by the grid (gridelements only queries colPos -1)
- $updates[$uid] = self::RESET;
- $count('child outside the grid (colPos ' . $child['colPos'] . '), stays');
- if (!(int)$child['deleted']) {
- $report[] = [$child, 'page column', 'colPos ' . $child['colPos'] . ' instead of -1', 'unchanged, grid fields cleared'];
- }
- continue;
- }
- if ($parent !== null && (int)$child['pid'] !== (int)$parent['pid']) {
- // A container only renders children of its own page
- $parent = null;
- }
- $config = self::LAYOUTS[(string)($parent['tx_gridelements_backend_layout'] ?? '')] ?? null;
- if ($parent !== null && $config !== null && (int)$child['colPos'] === -1 && in_array($column, $config[2], true)) {
- $updates[$uid] = [
- 'tx_container_parent' => (int)$parent['uid'],
- 'colPos' => $config[1] + $column % 10,
- ] + self::RESET;
- $count('A: child migrated' . ((int)$child['deleted'] ? ' (deleted)' : ''));
- // Inside a grid, TYPO3 10 did not apply settings.defaultHeaderType, so the header of these
- // types stayed invisible with layout "default". Keep it invisible, and visible as such to editors.
- if ((int)$child['header_layout'] === 0 && trim((string)$child['header']) !== '' && in_array($child['CType'], self::DEFAULT_HEADER_TYPES, true)) {
- $updates[$uid]['header_layout'] = 100;
- $count('A: header layout default → hidden');
- }
- continue;
- }
- // B (column not in the layout) and C (parent is no grid): invisible in TYPO3 10, soft deleted
- $group = $parent === null ? 'C' : 'B';
- $reason = $parent === null
- ? 'parent ' . $child['tx_gridelements_container'] . ' is not a grid on the same page'
- : 'column ' . $column . ' (colPos ' . $child['colPos'] . ') not in layout ' . $parent['tx_gridelements_backend_layout'];
- $updates[$uid] = ['deleted' => 1] + self::RESET;
- $count($group . ': child deleted' . ((int)$child['deleted'] ? ' (was deleted already)' : ''));
- if (!(int)$child['deleted']) {
- $report[] = [$child, $group, $reason, 'deleted'];
- }
- }
-
- // Other rows still carrying grid values (e.g. a former grid whose CType was changed by hand)
- $leftovers = (int)$connection->executeQuery(
- 'SELECT COUNT(*) FROM tt_content WHERE (tx_gridelements_children > 0 OR tx_gridelements_backend_layout NOT IN (\'\', \'0\')) AND CType <> ? AND tx_gridelements_container = 0',
- ['gridelements_pi1']
- )->fetchOne();
-
- ksort($counts);
- foreach ($counts as $label => $number) {
- $output->writeln(sprintf('%6d %s', $number, $label));
- }
- if ($leftovers > 0) {
- $output->writeln(sprintf('%6d other rows with grid values, cleared', $leftovers));
- }
- if ($input->getOption('report')) {
- if (!$this->writeReport((string)$input->getOption('report'), $report)) {
- $output->writeln(sprintf('Cannot write the report to %s, nothing migrated.', $input->getOption('report')));
- return Command::FAILURE;
- }
- $output->writeln(sprintf('Report: %d rows in %s', count($report), $input->getOption('report')));
- }
- if ($updates === [] && $leftovers === 0) {
- $output->writeln('Nothing to migrate.');
- return Command::SUCCESS;
- }
- if ($input->getOption('dry-run')) {
- $output->writeln('Dry run, nothing written.');
- return Command::SUCCESS;
- }
-
- $connection->transactional(function (Connection $connection) use ($updates): void {
- foreach ($updates as $uid => $values) {
- $connection->update('tt_content', $values, ['uid' => $uid]);
- }
- $connection->executeStatement(
- 'UPDATE tt_content SET tx_gridelements_children = 0, tx_gridelements_backend_layout = \'\' WHERE tx_gridelements_children > 0 OR tx_gridelements_backend_layout NOT IN (\'\', \'0\')'
- );
- });
-
- $output->writeln(sprintf('%d rows migrated. Next: referenceindex:update, container:integrity, cache:flush', count($updates)));
- return Command::SUCCESS;
- }
-
- private function hasGridelementsColumns(Connection $connection): bool
- {
- return array_key_exists('tx_gridelements_container', $connection->createSchemaManager()->listTableColumns('tt_content'));
- }
-
- /**
- * @param list, 1: string, 2: string, 3: string}> $rows
- */
- private function writeReport(string $file, array $rows): bool
- {
- $handle = @fopen($file, 'wb');
- if ($handle === false) {
- return false;
- }
- $titles = [];
- foreach ($this->connectionPool->getConnectionForTable('pages')->executeQuery('SELECT uid, title FROM pages WHERE sys_language_uid = 0')->iterateAssociative() as $page) {
- $titles[(int)$page['uid']] = $page['title'];
- }
- fputcsv($handle, ['uid', 'pid', 'page', 'CType', 'header', 'hidden', 'group', 'reason', 'action'], escape: '');
- foreach ($rows as [$row, $group, $reason, $action]) {
- fputcsv($handle, [
- $row['uid'], $row['pid'], $titles[(int)$row['pid']] ?? '', $row['CType'], $row['header'], $row['hidden'], $group, $reason, $action,
- ], escape: '');
- }
- return fclose($handle);
- }
-}
diff --git a/packages/ep_theme/Configuration/TCA/Overrides/tt_content_element_container.php b/packages/ep_theme/Configuration/TCA/Overrides/tt_content_element_container.php
index 5b4d438..ab5a8c3 100644
--- a/packages/ep_theme/Configuration/TCA/Overrides/tt_content_element_container.php
+++ b/packages/ep_theme/Configuration/TCA/Overrides/tt_content_element_container.php
@@ -31,7 +31,7 @@ call_user_func(function () {
)
);
- // Column layouts, migrated from gridelements (ep:migrate-gridelements). colPos = 200 + 10 × layout + column
+ // Column layouts, migrated from gridelements in 2026 (commit 4172ed9). colPos = 200 + 10 × layout + column
$menus = 'menu_abstract,menu_categorized_content,menu_categorized_pages,menu_recently_updated,menu_related_pages,menu_section_pages,menu_sitemap,menu_sitemap_pages';
$columnContainers = [
'ep_container_halves' => ['Spalten 50/50', 'Zwei gleich breite Spalten', 'halves', [[201], [202]]],
diff --git a/packages/ep_theme/ext_tables.sql b/packages/ep_theme/ext_tables.sql
index 98bb4f1..40379df 100644
--- a/packages/ep_theme/ext_tables.sql
+++ b/packages/ep_theme/ext_tables.sql
@@ -182,44 +182,3 @@ CREATE TABLE tx_eptheme_ttcontent_tx_eptheme_disrupter_mm
KEY uid_local (uid_local),
KEY uid_foreign (uid_foreign)
);
-
-CREATE TABLE tx_eptheme_domain_model_addresscheck
-(
- uid int(11) NOT NULL auto_increment,
- pid int(11) DEFAULT '0' NOT NULL,
- tstamp int(11) DEFAULT '0' NOT NULL,
- crdate int(11) DEFAULT '0' NOT NULL,
- cruser_id int(11) DEFAULT '0' NOT NULL,
- deleted tinyint(3) DEFAULT '0',
- hidden tinyint(4) DEFAULT '0' NOT NULL,
-
- name tinytext,
- first_name tinytext,
- last_name tinytext,
- customer_id varchar(255) DEFAULT '' NOT NULL,
- title varchar(255) DEFAULT '' NOT NULL,
- email varchar(255) DEFAULT '' NOT NULL,
- address tinytext,
- city varchar(255) DEFAULT '' NOT NULL,
- zip varchar(20) DEFAULT '' NOT NULL,
- country varchar(128) DEFAULT '' NOT NULL,
-
- no_postal tinyint(4) DEFAULT '0' NOT NULL,
- no_email tinyint(4) DEFAULT '0' NOT NULL,
- address_current tinyint(4) DEFAULT '0' NOT NULL,
-
- t3ver_oid int(11) DEFAULT '0' NOT NULL,
- t3ver_id int(11) DEFAULT '0' NOT NULL,
- t3ver_wsid int(11) DEFAULT '0' NOT NULL,
- t3ver_label varchar(30) DEFAULT '' NOT NULL,
- t3ver_state tinyint(4) DEFAULT '0' NOT NULL,
- t3ver_stage tinyint(4) DEFAULT '0' NOT NULL,
- t3ver_count int(11) DEFAULT '0' NOT NULL,
- t3ver_tstamp int(11) DEFAULT '0' NOT NULL,
- t3ver_move_id int(11) DEFAULT '0' NOT NULL,
- t3_origuid int(11) DEFAULT '0' NOT NULL,
-
- PRIMARY KEY (uid),
- KEY parent (pid),
- KEY pid (pid, email)
-);