Always open the event detail page instead of redirecting to the external URL

Events with a URL were saved with source "external", so Contao linked
lists straight to the external site and redirected the detail page.
The URL is now kept in the url field and only shown as a button on the
detail page.

- frontend form saves source "default" for every event
- backend: source option "external" removed, url field relabelled
  "Externer Link", obsolete target field dropped from the palette
- migration switches existing source="external" events to "default"

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
admin.juergenandClaude Opus 5.5 committed 2026-11-04 16:16:33 +01:00
1 parent ff8fa50360
commit bdc8988e28
5 files changed
+70 -2

No files matched your search

+17 -1
View File
@@ -6,6 +6,7 @@ use Contao\CoreBundle\DataContainer\PaletteManipulator;
use Contao\DataContainer; use Contao\DataContainer;
use Contao\Database; use Contao\Database;
use Contao\StringUtil; use Contao\StringUtil;
use Contao\System;
unset($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['location']); unset($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['location']);
unset($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['address']); unset($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['address']);
@@ -30,7 +31,7 @@ $GLOBALS['TL_DCA']['tl_calendar_events']['config']['onload_callback'][] = static
->applyToPalette((string) $paletteName, 'tl_calendar_events'); ->applyToPalette((string) $paletteName, 'tl_calendar_events');
PaletteManipulator::create() PaletteManipulator::create()
->addField(['source', 'url', 'target'], 'details_legend', PaletteManipulator::POSITION_APPEND) ->addField(['source', 'url'], 'details_legend', PaletteManipulator::POSITION_APPEND)
->addField(['termsAccepted', 'isSoldOut', 'isCanceled'], 'publish_legend', PaletteManipulator::POSITION_APPEND) ->addField(['termsAccepted', 'isSoldOut', 'isCanceled'], 'publish_legend', PaletteManipulator::POSITION_APPEND)
->applyToPalette((string) $paletteName, 'tl_calendar_events'); ->applyToPalette((string) $paletteName, 'tl_calendar_events');
} }
@@ -169,6 +170,20 @@ $GLOBALS['TL_DCA']['tl_calendar_events']['fields']['termsAccepted'] = [
if (isset($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['source']) && is_array($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['source'])) { if (isset($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['source']) && is_array($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['source'])) {
$GLOBALS['TL_DCA']['tl_calendar_events']['fields']['source']['eval'] ??= []; $GLOBALS['TL_DCA']['tl_calendar_events']['fields']['source']['eval'] ??= [];
$GLOBALS['TL_DCA']['tl_calendar_events']['fields']['source']['eval']['tl_class'] = 'w50'; $GLOBALS['TL_DCA']['tl_calendar_events']['fields']['source']['eval']['tl_class'] = 'w50';
// Keine Weiterleitung auf externe Seiten: Events öffnen immer die Detailseite,
// die externe URL (Feld "url") wird dort als Button ausgegeben.
$originalSourceOptionsCallback = $GLOBALS['TL_DCA']['tl_calendar_events']['fields']['source']['options_callback'] ?? null;
if (null !== $originalSourceOptionsCallback) {
$GLOBALS['TL_DCA']['tl_calendar_events']['fields']['source']['options_callback'] = static function (DataContainer $dc) use ($originalSourceOptionsCallback): array {
$options = \is_array($originalSourceOptionsCallback)
? System::importStatic($originalSourceOptionsCallback[0])->{$originalSourceOptionsCallback[1]}($dc)
: $originalSourceOptionsCallback($dc);
return array_values(array_diff((array) $options, ['external']));
};
}
} }
if (isset($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['target']) && is_array($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['target'])) { if (isset($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['target']) && is_array($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['target'])) {
@@ -179,6 +194,7 @@ if (isset($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['target']) && is_ar
if (isset($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['url']) && is_array($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['url'])) { if (isset($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['url']) && is_array($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['url'])) {
$GLOBALS['TL_DCA']['tl_calendar_events']['fields']['url']['eval'] ??= []; $GLOBALS['TL_DCA']['tl_calendar_events']['fields']['url']['eval'] ??= [];
$GLOBALS['TL_DCA']['tl_calendar_events']['fields']['url']['eval']['tl_class'] = 'clr'; $GLOBALS['TL_DCA']['tl_calendar_events']['fields']['url']['eval']['tl_class'] = 'clr';
$GLOBALS['TL_DCA']['tl_calendar_events']['fields']['url']['label'] = &$GLOBALS['TL_LANG']['tl_calendar_events']['url'];
$GLOBALS['TL_DCA']['tl_calendar_events']['fields']['url']['eval']['mandatory'] = false; $GLOBALS['TL_DCA']['tl_calendar_events']['fields']['url']['eval']['mandatory'] = false;
unset($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['url']['eval']['rgxp']); unset($GLOBALS['TL_DCA']['tl_calendar_events']['fields']['url']['eval']['rgxp']);
} }
@@ -10,3 +10,4 @@ $GLOBALS['TL_LANG']['tl_calendar_events']['photographer'] = ['Urheber/Fotograf',
$GLOBALS['TL_LANG']['tl_calendar_events']['isSoldOut'] = ['Ausverkauft', 'Diese Veranstaltung ist ausverkauft.']; $GLOBALS['TL_LANG']['tl_calendar_events']['isSoldOut'] = ['Ausverkauft', 'Diese Veranstaltung ist ausverkauft.'];
$GLOBALS['TL_LANG']['tl_calendar_events']['isCanceled'] = ['Abgesagt', 'Diese Veranstaltung wurde abgesagt.']; $GLOBALS['TL_LANG']['tl_calendar_events']['isCanceled'] = ['Abgesagt', 'Diese Veranstaltung wurde abgesagt.'];
$GLOBALS['TL_LANG']['tl_calendar_events']['termsAccepted'] = ['Nutzungsbedingungen akzeptiert', 'Die Nutzungsbedingungen wurden akzeptiert.']; $GLOBALS['TL_LANG']['tl_calendar_events']['termsAccepted'] = ['Nutzungsbedingungen akzeptiert', 'Die Nutzungsbedingungen wurden akzeptiert.'];
$GLOBALS['TL_LANG']['tl_calendar_events']['url'] = ['Externer Link', 'Weiterführende Seite zur Veranstaltung (z. B. Website des Veranstalters). Wird auf der Detailseite als Button ausgegeben; Listen verlinken immer auf die Detailseite.'];
@@ -10,3 +10,4 @@ $GLOBALS['TL_LANG']['tl_calendar_events']['photographer'] = ['Author/Photographe
$GLOBALS['TL_LANG']['tl_calendar_events']['isSoldOut'] = ['Sold out', 'This event is sold out.']; $GLOBALS['TL_LANG']['tl_calendar_events']['isSoldOut'] = ['Sold out', 'This event is sold out.'];
$GLOBALS['TL_LANG']['tl_calendar_events']['isCanceled'] = ['Canceled', 'This event has been canceled.']; $GLOBALS['TL_LANG']['tl_calendar_events']['isCanceled'] = ['Canceled', 'This event has been canceled.'];
$GLOBALS['TL_LANG']['tl_calendar_events']['termsAccepted'] = ['Terms accepted', 'The terms of use have been accepted.']; $GLOBALS['TL_LANG']['tl_calendar_events']['termsAccepted'] = ['Terms accepted', 'The terms of use have been accepted.'];
$GLOBALS['TL_LANG']['tl_calendar_events']['url'] = ['External link', 'Further page about the event (e.g. organiser website). Shown as a button on the event detail page; lists always link to the detail page.'];
@@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
namespace Mummert\EventManagerBundle\Migration;
use Contao\CoreBundle\Migration\AbstractMigration;
use Contao\CoreBundle\Migration\MigrationResult;
use Doctrine\DBAL\Connection;
/**
* Events mit externer URL öffnen künftig immer die Detailseite. Die URL bleibt im
* Feld "url" erhalten und wird auf der Detailseite als Button ausgegeben.
* Stellt dafür bestehende Events von source = "external" auf "default" um.
*/
class ExternalEventSourceMigration extends AbstractMigration
{
public function __construct(
private readonly Connection $connection,
) {
}
public function getName(): string
{
return 'Eventmanager: Events mit externer URL auf Detailseite umstellen';
}
public function shouldRun(): bool
{
$schemaManager = $this->connection->createSchemaManager();
if (!$schemaManager->tablesExist(['tl_calendar_events'])) {
return false;
}
return (int) $this->connection->fetchOne(
"SELECT COUNT(*) FROM tl_calendar_events WHERE source = 'external'",
) > 0;
}
public function run(): MigrationResult
{
$count = $this->connection->executeStatement(
"UPDATE tl_calendar_events SET source = 'default' WHERE source = 'external'",
);
return $this->createResult(true, sprintf('%d Events von externer Weiterleitung auf Detailseite umgestellt.', $count));
}
}
+2 -1
View File
@@ -651,7 +651,8 @@ class EventRepository
'teaser' => $data['teaser'] ?? null, 'teaser' => $data['teaser'] ?? null,
'description' => $data['description'] ?? null, 'description' => $data['description'] ?? null,
'url' => $url, 'url' => $url,
'source' => '' !== $url ? 'external' : 'default', // Externe URL wird nur als Link-Button auf der Detailseite ausgegeben, Listen verlinken immer auf die Detailseite
'source' => 'default',
'photographer' => $data['photographer'] ?? '', 'photographer' => $data['photographer'] ?? '',
'addImage' => !empty($data['addImage']) ? 1 : 0, 'addImage' => !empty($data['addImage']) ? 1 : 0,
'termsAccepted' => !empty($data['termsAccepted']) ? '1' : '', 'termsAccepted' => !empty($data['termsAccepted']) ? '1' : '',