Umut asked for a block that takes custom HTML, and for an iframe on a new DEEG offers page. Only one of those was missing. New core block "Eigenes HTML" (document schema v24): one property, the markup, up to 20.000 characters, written to the page unchanged. Changing it is reserved for administrators and compared against what is stored - on saving, on saving an area, and on restoring an older revision - exactly like an own script. <script> and <iframe> are refused with the way to the right place instead of being swallowed by the content security policy: scripts belong in the script field, frames in the "Externer Inhalt" block, because only that one asks for consent and puts the host into frame-src (ADR 106). DEEG: /angebote existed as a draft with placeholder text. It is now built like the legal pages - small caps line, large light heading, lead on the tinted band - with the IS24 result list below it and a line pointing to the portal and to the contact form. Navigation and the offers band on the home page point there. The consent question is switched on, so the frame loads only after the visitor agrees, and both the banner and the placeholder carry the site's own shapes and colours. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
178 lines
10 KiB
PHP
178 lines
10 KiB
PHP
<?php
|
||
|
||
/**
|
||
* Legt auf der bestehenden DEEG-Installation die Seite „Angebote“ an und verweist von der
|
||
* Navigation und vom Angebote-Band der Startseite dorthin.
|
||
*
|
||
* Die Seite zeigt die Ergebnisliste des DEEG-Portals bei ImmobilienScout24 als eingebetteten
|
||
* Rahmen – Baustein „Externer Inhalt“, nicht eigenes HTML: nur er fragt vorher um Einwilligung
|
||
* und trägt den Anbieter in die Sicherheitsrichtlinie der Seite ein. Kopfabschnitt, Schriftgrößen
|
||
* und Farben sind dieselben wie bei Impressum und Datenschutz (siehe seed-immobilien-deeg.php).
|
||
*
|
||
* Läuft nur gegen die DEEG-Datenbank und nur, solange es die Seite noch nicht gibt.
|
||
*/
|
||
require dirname(__DIR__).'/config/bootstrap.php';
|
||
|
||
use App\Content\DocumentValidator;
|
||
use App\Content\MediaLibrary;
|
||
use App\Content\MenuRepository;
|
||
use App\Content\PageRepository;
|
||
use App\Content\SiteSettings;
|
||
use App\Infrastructure\ConnectionFactory;
|
||
|
||
$root = dirname(__DIR__);
|
||
$url = str_replace('%kernel.project_dir%', str_replace('\\', '/', $root), (string) $_SERVER['DATABASE_URL']);
|
||
if (!str_contains($url, 'immobilien-deeg')) {
|
||
fwrite(STDERR, "Sicherung: DATABASE_URL muss auf die DEEG-Datenbank zeigen.\n");
|
||
exit(1);
|
||
}
|
||
$db = ConnectionFactory::create($url);
|
||
$media = new MediaLibrary($db, str_replace('%kernel.project_dir%', $root, (string) $_SERVER['MEDIA_DIRECTORY']));
|
||
$settings = new SiteSettings($db, $media);
|
||
$pages = new PageRepository($db, new DocumentValidator(), $settings);
|
||
$menus = new MenuRepository($db, $settings);
|
||
|
||
// Die Seite war im Editor schon angelegt (Starterabschnitt plus Rahmen mit Platzhaltertexten).
|
||
// Sie wird überschrieben, nicht verdoppelt; der bisherige Stand bleibt als Fassung erhalten und
|
||
// lässt sich im Editor unter „Fassungen“ zurückholen.
|
||
$vorhanden = $db->fetchOne('SELECT id FROM page WHERE path = ?', ['angebote']);
|
||
|
||
$SCHEMA = 24;
|
||
$portal = 'https://portal.immobilienscout24.de/ergebnisliste/16200281';
|
||
$nurUnten = static fn (string $w): array => ['top' => '0px', 'right' => '0px', 'bottom' => $w, 'left' => '0px'];
|
||
|
||
// Der Kopf wie auf Impressum und Datenschutz: helle Fläche, Kleinzeile, große leichte Überschrift.
|
||
$kopf = ['id' => 'angebote-kopf', 'type' => 'section', 'children' => [
|
||
['id' => 'angebote-label', 'type' => 'text', 'props' => ['text' => 'AKTUELLE OBJEKTE'], 'style' => [
|
||
'desktop' => ['fontSize' => '12px', 'fontWeight' => '700', 'letterSpacing' => '0.14em', 'lineHeight' => 1.6, 'color' => '@anthrazit', 'margin' => ['bottom' => '25px']],
|
||
'mobile' => ['fontSize' => '11px', 'margin' => ['bottom' => '18px']],
|
||
], 'layout' => ['effects' => ['entrance' => 'fade', 'delay' => 'none']]],
|
||
['id' => 'angebote-h1', 'type' => 'heading', 'props' => ['text' => 'Unsere Angebote', 'level' => 1], 'style' => [
|
||
'desktop' => ['fontWeight' => '400', 'fontSize' => '56px', 'lineHeight' => 1.1, 'letterSpacing' => '-0.05em', 'margin' => ['bottom' => '22px']],
|
||
'tablet' => ['fontSize' => '44px'],
|
||
'mobile' => ['fontSize' => '38px', 'margin' => ['bottom' => '16px']],
|
||
], 'layout' => ['effects' => ['entrance' => 'rise', 'delay' => 'short']]],
|
||
['id' => 'angebote-vorspann', 'type' => 'text', 'props' => ['text' => 'Wohnungen, Häuser und Grundstücke aus unserem Bestand in Freudenstadt und Umgebung. Die Liste wird laufend aktualisiert – sehen Sie sich um und sprechen Sie uns an.'], 'style' => [
|
||
'desktop' => ['maxWidth' => '640px', 'fontSize' => '18px', 'lineHeight' => 1.7, 'color' => '@text', 'margin' => ['bottom' => '0px']],
|
||
'mobile' => ['fontSize' => '16px'],
|
||
], 'layout' => ['effects' => ['entrance' => 'rise', 'delay' => 'medium']]],
|
||
], 'style' => [
|
||
'desktop' => ['backgroundColor' => '@hell', 'borderWidth' => $nurUnten('1px'), 'borderStyle' => 'solid', 'borderColor' => '@linie-hell', 'padding' => ['top' => '84px', 'bottom' => '72px']],
|
||
'tablet' => ['padding' => ['top' => '64px', 'bottom' => '56px']],
|
||
'mobile' => ['padding' => ['top' => '48px', 'bottom' => '40px']],
|
||
]];
|
||
|
||
// Die Liste selbst. Der Rahmen bleibt hoch genug, dass mehrere Objekte ohne Scrollen im Rahmen
|
||
// sichtbar sind; darunter der Weg zum Portal für alle, die lieber dort suchen.
|
||
$hinweisText = 'Nichts Passendes dabei? <a href="'.$portal.'" target="_blank" rel="noopener">Alle Objekte direkt bei ImmobilienScout24 ansehen ↗</a> oder <a href="/#kontakt">sprechen Sie uns an</a> – wir kennen den Markt vor Ort und wissen oft von Objekten, bevor sie inseriert sind.';
|
||
$liste = ['id' => 'angebote-liste', 'type' => 'section', 'children' => [
|
||
['id' => 'angebote-rahmen', 'type' => 'embed', 'props' => [
|
||
'group' => 'external',
|
||
'title' => 'Aktuelle Immobilienangebote der Deeg Hausverwaltung und Immobilien GmbH bei ImmobilienScout24',
|
||
'provider' => 'ImmobilienScout24',
|
||
'url' => $portal,
|
||
'hint' => 'Die Angebotsliste wird von ImmobilienScout24 geladen. Dabei erfährt der Anbieter Ihre IP-Adresse und welche Seite Sie ansehen.',
|
||
'height' => 1000,
|
||
], 'style' => ['desktop' => ['margin' => ['bottom' => '26px']]], 'layout' => ['effects' => ['entrance' => 'fade', 'delay' => 'none']],
|
||
// Der Rahmen selbst und der Platzhalter davor tragen den Zuschnitt der Vorlage: eckig,
|
||
// helle Fläche, Logo-Blau auf dem Knopf. Was IM Rahmen steht, gehört ImmobilienScout24 -
|
||
// daran kommt kein CSS dieser Website heran, und das ist keine Einstellung, sondern die
|
||
// Trennung zwischen zwei Herkünften im Browser.
|
||
'css' => "& iframe{border:1px solid #dbe1e3;border-radius:0;background:#f5fafd}
|
||
&.embed-blocked{border:1px solid #dbe1e3;border-radius:0;background:#f5fafd;padding:56px 24px;text-align:left}
|
||
& .embed-title{font-size:20px;font-weight:700;color:#343a40;margin-bottom:12px}
|
||
& .embed-hint{max-width:640px;font-size:15px;line-height:1.7;color:#58666d}
|
||
& .embed-provider{font-size:13px;color:#66747b}
|
||
& .consent-button{border-radius:0;background:#0076b6;border-color:#0076b6;color:#fff;flex:0 0 auto;padding:16px 24px}
|
||
& .consent-button:hover{background:#006aa3;border-color:#006aa3}",
|
||
],
|
||
['id' => 'angebote-hinweis', 'type' => 'text', 'props' => ['text' => $hinweisText], 'style' => [
|
||
'desktop' => ['maxWidth' => '760px', 'fontSize' => '16px', 'lineHeight' => 1.7, 'color' => '@text', 'margin' => ['bottom' => '0px']],
|
||
], 'css' => "& a{color:#006aa3;text-decoration:underline;text-underline-offset:3px}\n& a:hover{color:#343a40}",
|
||
'layout' => ['effects' => ['entrance' => 'rise', 'delay' => 'short']]],
|
||
], 'style' => [
|
||
'desktop' => ['padding' => ['top' => '72px', 'bottom' => '108px']],
|
||
'tablet' => ['padding' => ['top' => '56px', 'bottom' => '80px']],
|
||
'mobile' => ['padding' => ['top' => '40px', 'bottom' => '65px']],
|
||
]];
|
||
|
||
$dokumentAngebote = [
|
||
'schemaVersion' => $SCHEMA,
|
||
'title' => 'Angebote',
|
||
'description' => 'Aktuelle Wohnungen, Häuser und Grundstücke der Deeg Hausverwaltung und Immobilien GmbH in Freudenstadt und Umgebung.',
|
||
'blocks' => [$kopf, $liste],
|
||
];
|
||
if (false !== $vorhanden) {
|
||
$id = (string) $vorhanden;
|
||
$revision = $pages->saveDraft($id, $dokumentAngebote, (int) $pages->findForEditor($id)['version']);
|
||
$pages->publish($id, $revision, (int) $pages->findForEditor($id)['version']);
|
||
echo "Seite überarbeitet und veröffentlicht: /angebote\n";
|
||
} else {
|
||
$id = $pages->createPage('angebote', null, 'page', $dokumentAngebote);
|
||
$seite = $db->fetchAssociative('SELECT draft_revision_id, version FROM page WHERE id = ?', [$id]);
|
||
$pages->publish($id, $seite['draft_revision_id'], (int) $seite['version']);
|
||
echo "Seite angelegt und veröffentlicht: /angebote\n";
|
||
}
|
||
$db->executeStatement('UPDATE page SET seo_title = ? WHERE id = ?', ['Aktuelle Angebote | Deeg Hausverwaltung und Immobilien GmbH', $id]);
|
||
|
||
// „Immobilien“ in der Navigation zeigte auf den Sprungpunkt der Startseite; jetzt gibt es die
|
||
// Seite, auf die dieser Abschnitt ohnehin nur verwiesen hat.
|
||
$header = $menus->all()['header'];
|
||
$eintraege = [];
|
||
foreach ($header['items'] as $eintrag) {
|
||
if ('Immobilien' === $eintrag['label']) {
|
||
$eintrag['pageId'] = $id;
|
||
$eintrag['anchor'] = '';
|
||
}
|
||
$eintraege[] = $eintrag;
|
||
}
|
||
$menus->save('header', $header['name'], $eintraege, (int) $header['version']);
|
||
echo "Navigation: „Immobilien“ zeigt auf /angebote\n";
|
||
|
||
// Und der Knopf im Angebote-Band der Startseite, der bisher auf die alte Website führte.
|
||
$home = $db->fetchAssociative('SELECT id FROM page WHERE path = ?', ['home']);
|
||
$dokument = $pages->findForEditor($home['id'])['document'];
|
||
$getroffen = 0;
|
||
$walk = function (array &$blocks) use (&$walk, &$getroffen): void {
|
||
foreach ($blocks as &$block) {
|
||
// Der Knopf im Angebote-Band ist ein Textbaustein mit eigenem CSS, kein Button-Baustein -
|
||
// deshalb wird die Adresse im Text ersetzt, nicht in den Eigenschaften.
|
||
foreach (['href', 'text'] as $feld) {
|
||
$wert = (string) ($block['props'][$feld] ?? '');
|
||
if ('' !== $wert && str_contains($wert, 'immobiliendeeg.de/immobilien')) {
|
||
$block['props'][$feld] = str_replace(['https://www.immobiliendeeg.de/immobilien/', 'https://www.immobiliendeeg.de/immobilien'], '/angebote', $wert);
|
||
unset($block['props']['newTab']);
|
||
++$getroffen;
|
||
}
|
||
}
|
||
if (isset($block['children']) && is_array($block['children'])) {
|
||
$walk($block['children']);
|
||
}
|
||
}
|
||
};
|
||
$walk($dokument['blocks']);
|
||
if ($getroffen > 0) {
|
||
$stand = $pages->findForEditor($home['id']);
|
||
$revision = $pages->saveDraft($home['id'], $dokument, $stand['version']);
|
||
$pages->publish($home['id'], $revision, $pages->findForEditor($home['id'])['version']);
|
||
}
|
||
echo "Startseite: $getroffen Knopf/Knöpfe zeigen jetzt auf /angebote\n";
|
||
|
||
// Ein fremder Rahmen ohne Einwilligung lädt beim Seitenaufruf mit und gibt dabei IP-Adresse und
|
||
// Seite an den Anbieter weiter. Mit der Gruppe „Externe Inhalte“ steht davor der Platzhalter, und
|
||
// erst der Knopf lädt die Liste. Der Balken trägt die Farben der Website.
|
||
$aktuell = $settings->load();
|
||
$settings->save([
|
||
...$aktuell,
|
||
// Gespeichert als Liste, erwartet als Textfeld - wie es der Einstellungsbildschirm schickt.
|
||
'sameAs' => implode("\n", $aktuell['sameAs']),
|
||
'consentBanner' => true,
|
||
'consentGroups' => ['external'],
|
||
'consentShape' => 'eckig',
|
||
'consentAccent' => '@blau-tief',
|
||
'consentAccentInk' => '@papier',
|
||
'consentColor' => '@papier',
|
||
'consentInk' => '@anthrazit',
|
||
]);
|
||
echo "Einwilligung eingeschaltet: Gruppe „Externe Inhalte“, Balken eckig in Logo-Blau\n";
|