Show the own site icon to Google under every address, and the KANTARCI landing page

- Google kept showing the KantSites K for Elektro Bernhard after the site
  icon was changed. The own icon only existed at 32 and 180 px, and Google
  takes multiples of 48 only; /favicon.svg was a file in public/, so the web
  server always delivered the bundled K.
- The icon is now also cut at 48 and 192 px. The head links /favicon-192.png,
  /favicon.ico serves the 48 px PNG, and /favicon.svg is answered by the
  application: the bundled mark without an own icon (now in
  public/assets/favicon.svg), otherwise a 302 to the 192 px PNG. Sites that
  set their icon earlier get the new sizes on first request. A removed icon
  no longer counts even though its files remain.
- The archive update only adds files to public/, so it now deletes the old
  public/favicon.svg explicitly.
- Seventh local reference site: the KANTARCI Immobilien landing page with a
  three-step rental request, own database, seed and reset scripts.

Tests: 582 PHPUnit on PHP 8.2 and 8.4, 35 node, test:editor and
test:browser green (test:browser reports only the known editor colour
contrast on /grundlagen).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
kantarciandClaude Opus 5 committed 2026-09-21 07:37:04 +02:00
1 parent 42e74af052
commit 45d1141951
14 files changed
+1057 -12

No files matched your search

+46
View File
@@ -1626,6 +1626,52 @@ final class CmsTest extends TestCase
self::assertSame($kleines['id'], $this->site->load()['faviconMediaId']);
}
public function testGoogleGetsTheOwnSiteIconUnderEveryAddress(): void
{
// Umut: Google zeigte bei Elektro Bernhard nach dem Wechsel weiter das KantSites-K. Das
// eigene Symbol gab es nur in 32 px (Google will Vielfache von 48), und /favicon.svg lag
// als Datei in public/ und lieferte immer das mitgelieferte Zeichen.
self::assertFileDoesNotExist(__DIR__.'/../public/favicon.svg');
$ohne = $this->request('/favicon.svg');
self::assertSame(200, $ohne->getStatusCode());
self::assertSame('image/svg+xml', $ohne->headers->get('Content-Type'));
self::assertSame('/favicon.svg', $this->request('/favicon.ico')->headers->get('Location'));
self::assertSame(404, $this->request('/favicon-192.png')->getStatusCode());
$media = new MediaLibrary($this->db, $this->path.'-media');
$file = tempnam(sys_get_temp_dir(), 'kant-symbol-');
$image = imagecreatetruecolor(300, 300);
imagepng($image, $file);
imagedestroy($image);
$item = $media->upload(new UploadedFile($file, 'zeichen.png', test: true));
@unlink($file);
$this->site->save(['country' => 'DE', 'homePath' => 'home', 'faviconMediaId' => $item['id']]);
$version = substr($item['id'], 0, 8);
self::assertStringContainsString('<link rel="icon" href="/favicon-192.png?v='.$version.'" type="image/png" sizes="192x192">', $this->request('/')->getContent());
foreach (['/favicon-192.png' => 192, '/favicon.ico' => 48] as $adresse => $kante) {
$antwort = $this->request($adresse);
self::assertSame(200, $antwort->getStatusCode(), $adresse);
self::assertSame('image/png', $antwort->headers->get('Content-Type'));
$size = getimagesizefromstring((string) file_get_contents($this->path.'-media/favicon-'.$kante.'.png'));
self::assertSame([$kante, $kante], [$size[0], $size[1]]);
}
$svg = $this->request('/favicon.svg');
self::assertSame(302, $svg->getStatusCode());
self::assertSame('/favicon-192.png?v='.$version, $svg->headers->get('Location'));
// Wer sein Symbol vor den neuen Größen gesetzt hat, bekommt sie beim ersten Abruf.
unlink($this->path.'-media/favicon-48.png');
unlink($this->path.'-media/favicon-192.png');
self::assertSame(200, $this->request('/favicon-192.png')->getStatusCode());
self::assertFileExists($this->path.'-media/favicon-48.png');
// Symbol entfernt: die Dateien liegen noch da, gelten aber nicht mehr.
$this->site->save(['country' => 'DE', 'homePath' => 'home', 'faviconMediaId' => '']);
self::assertSame(200, $this->request('/favicon.svg')->getStatusCode());
self::assertSame(404, $this->request('/favicon.png')->getStatusCode());
}
public function testUnderlinedLinksAreAChoiceAndOnlyApplyToRunningText(): void
{
// Umut: „links haben alle underlined“. Im Menü, auf Karten und über Bildern hat ein