From 2150d4b7aec68eed4c940cda8219279ae96c1248 Mon Sep 17 00:00:00 2001 From: Kevin Adametz Date: Tue, 13 Oct 2026 10:16:21 +0000 Subject: [PATCH] =?UTF-8?q?web:=20Boost=20als=20=E2=80=9EGebuchte=20Platzi?= =?UTF-8?q?erung=E2=80=9C=20mit=20Erkl=C3=A4rung=20gekennzeichnet?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Label „Gebuchte Platzierung“ (en „Booked placement“) statt „Top-Platzierung“ auf Start- und Branchenseite. Die Erklärung „Das Unternehmen hat diesen Platz gebucht …“ erscheint am Desktop beim Überfahren und auf Mobil per Tipp, ohne den umgebenden Link zu öffnen; Screenreader lesen sie mit. Kopfzeile über dem Aufmacher „Aktuell“ statt „Top-Auswahl“ (automatische Auswahl, keine Redaktion). Preisseite nennt die Kennzeichnung (Rechtspaket U10). Co-Authored-By: Claude Opus 5.5 --- .../anwaltspaket-datenschutz-2026-10.md | 0 ...nteressenabwaegung-beweisarchiv-2026-10.md | 0 lang/de/pricing.php | 2 +- lang/de/web.php | 5 ++- lang/en/pricing.php | 2 +- lang/en/web.php | 5 ++- .../components/web/boosted-label.blade.php | 27 +++++++++++++ .../views/components/web/focus-hero.blade.php | 6 +-- .../components/web/focus-side-item.blade.php | 4 +- resources/views/web/kategorie.blade.php | 8 ++-- tests/Feature/Web/BoostPlacementTest.php | 39 ++++++++++++++----- tests/Feature/Web/PreisePageTest.php | 1 + 12 files changed, 72 insertions(+), 27 deletions(-) rename dev/{rechtliches => archive/rechtliches-2026-10}/anwaltspaket-datenschutz-2026-10.md (100%) rename dev/{rechtliches => archive/rechtliches-2026-10}/interessenabwaegung-beweisarchiv-2026-10.md (100%) create mode 100644 resources/views/components/web/boosted-label.blade.php diff --git a/dev/rechtliches/anwaltspaket-datenschutz-2026-10.md b/dev/archive/rechtliches-2026-10/anwaltspaket-datenschutz-2026-10.md similarity index 100% rename from dev/rechtliches/anwaltspaket-datenschutz-2026-10.md rename to dev/archive/rechtliches-2026-10/anwaltspaket-datenschutz-2026-10.md diff --git a/dev/rechtliches/interessenabwaegung-beweisarchiv-2026-10.md b/dev/archive/rechtliches-2026-10/interessenabwaegung-beweisarchiv-2026-10.md similarity index 100% rename from dev/rechtliches/interessenabwaegung-beweisarchiv-2026-10.md rename to dev/archive/rechtliches-2026-10/interessenabwaegung-beweisarchiv-2026-10.md diff --git a/lang/de/pricing.php b/lang/de/pricing.php index e8686830..ca33b0e1 100644 --- a/lang/de/pricing.php +++ b/lang/de/pricing.php @@ -126,7 +126,7 @@ return [ ], 'boost' => [ 'title' => 'Boost — was Sie bekommen und was nicht', - 'text' => 'Geschuldet ist die Platzierung während der gebuchten Laufzeit — beim Startseiten-Boost auf Startseite und Kategorieseite, beim Kategorie-Boost auf der Kategorieseite der jeweiligen Rubrik. Die Zahl gleichzeitiger Boosts je Seite ist begrenzt; sind alle Plätze belegt, ist eine neue Buchung erst möglich, sobald ein Platz frei wird — verkauft wird also nur, was auch sichtbar ist. Eine bestimmte Reichweite oder Zugriffszahl versprechen wir nicht — das wäre unseriös. Buchbar nur für Mitteilungen mit Prüfergebnis Grün. Ist das Portal während eines aktiven Boosts aus von uns zu vertretenden Gründen länger als 60 Minuten am Stück nicht erreichbar, verlängert sich die Boost-Laufzeit entsprechend.', + 'text' => 'Geschuldet ist die Platzierung während der gebuchten Laufzeit — beim Startseiten-Boost auf Startseite und Kategorieseite, beim Kategorie-Boost auf der Kategorieseite der jeweiligen Rubrik. Geboostete Meldungen sind als gebuchte Platzierung gekennzeichnet. Die Zahl gleichzeitiger Boosts je Seite ist begrenzt; sind alle Plätze belegt, ist eine neue Buchung erst möglich, sobald ein Platz frei wird — verkauft wird also nur, was auch sichtbar ist. Eine bestimmte Reichweite oder Zugriffszahl versprechen wir nicht — das wäre unseriös. Buchbar nur für Mitteilungen mit Prüfergebnis Grün. Ist das Portal während eines aktiven Boosts aus von uns zu vertretenden Gründen länger als 60 Minuten am Stück nicht erreichbar, verlängert sich die Boost-Laufzeit entsprechend.', ], 'partners' => [ 'title' => 'Partnerportale', diff --git a/lang/de/web.php b/lang/de/web.php index 6e6b92bf..6a813c43 100644 --- a/lang/de/web.php +++ b/lang/de/web.php @@ -23,7 +23,8 @@ return [ 'read_time' => ':minutes Min. Lesezeit', 'minutes_short' => ':minutes Min.', 'recommendation' => 'Empfehlung', - 'boosted_placement' => 'Top-Platzierung', + 'boosted_placement' => 'Gebuchte Platzierung', + 'boosted_placement_hint' => 'Das Unternehmen hat diesen Platz gebucht. Der Inhalt ist eine Pressemitteilung des Unternehmens.', ], 'countries' => [ @@ -76,7 +77,7 @@ return [ 'hero' => [ 'title' => 'Im Fokus', 'clock_format' => 'dddd, HH:mm [Uhr]', - 'editorial_pick' => 'Top-Auswahl', + 'latest' => 'Aktuell', 'top_story' => 'Top-Meldung', 'sidebar_title' => 'Was sonst zählt', ], diff --git a/lang/en/pricing.php b/lang/en/pricing.php index bc5594c1..df338ad3 100644 --- a/lang/en/pricing.php +++ b/lang/en/pricing.php @@ -119,7 +119,7 @@ return [ ], 'boost' => [ 'title' => 'Boost — what you get and what you do not', - 'text' => 'What is owed is the placement during the booked period — on the homepage and category page for a homepage boost, on the category page of the respective industry for a category boost. The number of simultaneous boosts per page is limited; once all slots are taken, a new booking is only possible when a slot becomes free — we only sell what is actually visible. We do not promise a specific reach or number of hits — that would be dishonest. Bookable only for releases with a green review result. If the portal is unavailable for more than 60 consecutive minutes during an active boost for reasons within our responsibility, the boost period is extended accordingly.', + 'text' => 'What is owed is the placement during the booked period — on the homepage and category page for a homepage boost, on the category page of the respective industry for a category boost. Boosted releases are labelled as a booked placement. The number of simultaneous boosts per page is limited; once all slots are taken, a new booking is only possible when a slot becomes free — we only sell what is actually visible. We do not promise a specific reach or number of hits — that would be dishonest. Bookable only for releases with a green review result. If the portal is unavailable for more than 60 consecutive minutes during an active boost for reasons within our responsibility, the boost period is extended accordingly.', ], 'partners' => [ 'title' => 'Partner portals', diff --git a/lang/en/web.php b/lang/en/web.php index ba4eef3a..49c0b156 100644 --- a/lang/en/web.php +++ b/lang/en/web.php @@ -18,7 +18,8 @@ return [ 'read_time' => ':minutes min read', 'minutes_short' => ':minutes min', 'recommendation' => 'Recommended', - 'boosted_placement' => 'Featured', + 'boosted_placement' => 'Booked placement', + 'boosted_placement_hint' => 'The company booked this spot. The content is a press release issued by the company.', ], 'countries' => [ @@ -71,7 +72,7 @@ return [ 'hero' => [ 'title' => 'In Focus', 'clock_format' => 'dddd, HH:mm', - 'editorial_pick' => 'Top selection', + 'latest' => 'Latest', 'top_story' => 'Top story', 'sidebar_title' => 'Also worth noting', ], diff --git a/resources/views/components/web/boosted-label.blade.php b/resources/views/components/web/boosted-label.blade.php new file mode 100644 index 00000000..5b41c0c1 --- /dev/null +++ b/resources/views/components/web/boosted-label.blade.php @@ -0,0 +1,27 @@ +@props([ + // tag = Schild auf dem Aufmacher-Bild, inline = kleiner Rahmen hinter der Überschrift in Listen + 'variant' => 'inline', +]) + +{{-- Kennzeichnung gebuchter Platzierungen (Rechtspaket 10/2026, U10): das + Label allein sagt, dass der Platz gebucht wurde; die Erklärung erscheint + am Desktop beim Überfahren und auf Mobil per Tipp, ohne dass der Tipp den + umgebenden Link öffnet. Screenreader lesen die Erklärung als Teil des + Linktexts mit. --}} + + @if ($variant === 'tag') + {{ __('web.shared.boosted_placement') }} + @else + {{ __('web.shared.boosted_placement') }} + @endif + : {{ __('web.shared.boosted_placement_hint') }} + + diff --git a/resources/views/components/web/focus-hero.blade.php b/resources/views/components/web/focus-hero.blade.php index 9e027f1e..c825e411 100644 --- a/resources/views/components/web/focus-hero.blade.php +++ b/resources/views/components/web/focus-hero.blade.php @@ -28,7 +28,7 @@

{{ __('web.hero.title') }}

-
{{ ucfirst(now()->isoFormat(__('web.hero.clock_format'))) }} · {{ __('web.hero.editorial_pick') }}
+
{{ ucfirst(now()->isoFormat(__('web.hero.clock_format'))) }} · {{ __('web.hero.latest') }}

@@ -52,10 +52,10 @@ @endif -
+
{{ __('web.hero.top_story') }} @if (in_array($leadRelease->id, $boostedIds, true)) - {{ __('web.shared.boosted_placement') }} + @endif
diff --git a/resources/views/components/web/focus-side-item.blade.php b/resources/views/components/web/focus-side-item.blade.php index 0f091ff5..7d417e2f 100644 --- a/resources/views/components/web/focus-side-item.blade.php +++ b/resources/views/components/web/focus-side-item.blade.php @@ -47,9 +47,7 @@

{{ $title }} @if ($boosted) - - {{ __('web.shared.boosted_placement') }} - + @endif

diff --git a/resources/views/web/kategorie.blade.php b/resources/views/web/kategorie.blade.php index d29161b9..5f1ebb05 100644 --- a/resources/views/web/kategorie.blade.php +++ b/resources/views/web/kategorie.blade.php @@ -183,10 +183,10 @@ @else @endif -
+
{{ __('web.hero.top_story') }} @if (in_array($leadRelease->id, $boostedIds ?? [], true)) - {{ __('web.shared.boosted_placement') }} + @endif
@@ -233,9 +233,7 @@

{{ $top->title }} @if (in_array($top->id, $boostedIds ?? [], true)) - - {{ __('web.shared.boosted_placement') }} - + @endif

@if ($top->company?->name) diff --git a/tests/Feature/Web/BoostPlacementTest.php b/tests/Feature/Web/BoostPlacementTest.php index 158394dd..b1bb0f1c 100644 --- a/tests/Feature/Web/BoostPlacementTest.php +++ b/tests/Feature/Web/BoostPlacementTest.php @@ -17,7 +17,7 @@ use Tests\TestCase; /** * Boost-Platzierung (Decision-Update §2.2): geboostete PMs besetzen die * Top-Positionen auf Start- und Branchenseite vor der Chronologie und werden - * als „Top-Platzierung" markiert. + * als „Gebuchte Platzierung" markiert. */ function boostPlacementFixture(): array { @@ -69,10 +69,10 @@ test('a boosted release takes the homepage lead ahead of newer releases and is l // Die verdrängte neueste Meldung rückt in die Seitenleiste nach. ->and($data['sideReleases']->modelKeys())->toContain($newest->id); - // Badge „Top-Platzierung" hängt am Hero-Lead (nach dem Ticker-Vorkommen). + // Badge „Gebuchte Platzierung" hängt am Hero-Lead (nach dem Ticker-Vorkommen). $this->get('https://presseecho.test/de') ->assertSuccessful() - ->assertSeeTextInOrder(['Top-Platzierung', 'Geboostete aeltere Meldung']); + ->assertSeeTextInOrder(['Gebuchte Platzierung', 'Geboostete aeltere Meldung']); }); test('an expired boost does not influence the homepage placement', function () { @@ -87,7 +87,7 @@ test('an expired boost does not influence the homepage placement', function () { $this->get('https://presseecho.test/de') ->assertSuccessful() - ->assertDontSeeText('Top-Platzierung'); + ->assertDontSeeText('Gebuchte Platzierung'); }); test('booking a boost invalidates the cached start and category pages immediately', function () { @@ -101,7 +101,7 @@ test('booking a boost invalidates the cached start and category pages immediatel expect(app(HomePageData::class)->build(Portal::Presseecho)['leadRelease']->id)->toBe($newest->id); $this->get('https://presseecho.test/de/category/energie-klima') ->assertSuccessful() - ->assertDontSeeText('Top-Platzierung'); + ->assertDontSeeText('Gebuchte Platzierung'); app(BoostService::class)->boost($owner, $boosted, 7); @@ -109,7 +109,7 @@ test('booking a boost invalidates the cached start and category pages immediatel expect(app(HomePageData::class)->build(Portal::Presseecho)['leadRelease']->id)->toBe($boosted->id); $this->get('https://presseecho.test/de/category/energie-klima') ->assertSuccessful() - ->assertSeeText('Top-Platzierung'); + ->assertSeeText('Gebuchte Platzierung'); }); test('a boosted release leads its category page and is labelled', function () { @@ -123,7 +123,7 @@ test('a boosted release leads its category page and is labelled', function () { $this->get('https://presseecho.test/de/category/energie-klima') ->assertSuccessful() ->assertSeeTextInOrder([ - 'Top-Platzierung', + 'Gebuchte Platzierung', 'Geboostete aeltere Meldung', 'Neueste unbezahlte Meldung', ]); @@ -138,7 +138,7 @@ test('a category boost leads its category page but never the homepage', function // Branchenseite: Kategorie-Boost besetzt den Lead-Slot. $this->get('https://presseecho.test/de/category/energie-klima') ->assertSuccessful() - ->assertSeeTextInOrder(['Top-Platzierung', 'Geboostete aeltere Meldung']); + ->assertSeeTextInOrder(['Gebuchte Platzierung', 'Geboostete aeltere Meldung']); // Startseite: bleibt bei der Chronologie — der Kategorie-Boost kauft // sie nicht mit (Entscheidung 13.07.). @@ -189,7 +189,7 @@ test('booking a category boost invalidates the category page but keeps the homep expect(app(HomePageData::class)->build(Portal::Presseecho)['leadRelease']->id)->toBe($newest->id); $this->get('https://presseecho.test/de/category/energie-klima') ->assertSuccessful() - ->assertDontSeeText('Top-Platzierung'); + ->assertDontSeeText('Gebuchte Platzierung'); app(BoostService::class)->boost($owner, $boosted, 7, BoostPlacement::Category); @@ -198,5 +198,24 @@ test('booking a category boost invalidates the category page but keeps the homep expect(Cache::has(webPageCacheKey('web.home.presseecho.de')))->toBeTrue(); $this->get('https://presseecho.test/de/category/energie-klima') ->assertSuccessful() - ->assertSeeText('Top-Platzierung'); + ->assertSeeText('Gebuchte Platzierung'); +}); + +test('the booked placement label explains itself and the hero no longer claims an editorial pick', function () { + /** @var TestCase $this */ + ['boosted' => $boosted] = boostPlacementFixture(); + + Boost::factory()->for($boosted)->create(); + + // Erklärung am Label (Tooltip/Tipp) und als Screenreader-Text; die + // Kopfzeile des Aufmachers nennt keine Auswahl mehr, sondern „Aktuell". + $this->get('https://presseecho.test/de') + ->assertSuccessful() + ->assertSee('data-boosted-label', false) + ->assertSeeText('Das Unternehmen hat diesen Platz gebucht. Der Inhalt ist eine Pressemitteilung des Unternehmens.') + ->assertSeeText('Aktuell') + ->assertDontSeeText('Top-Auswahl'); + + expect(__('web.shared.boosted_placement', [], 'en'))->toBe('Booked placement') + ->and(__('web.hero.latest', [], 'en'))->toBe('Latest'); }); diff --git a/tests/Feature/Web/PreisePageTest.php b/tests/Feature/Web/PreisePageTest.php index 07c6f085..a251507d 100644 --- a/tests/Feature/Web/PreisePageTest.php +++ b/tests/Feature/Web/PreisePageTest.php @@ -25,6 +25,7 @@ test('the pricing page renders the editorial shell with real plans, single pm an ->assertSeeText('Add-ons & Einzelkosten') ->assertSeeText('Extra-Pressemitteilung') ->assertSeeText('Boost-Platzierung') + ->assertSeeText('Geboostete Meldungen sind als gebuchte Platzierung gekennzeichnet.') ->assertSeeText('Veröffentlichungsnachweis (PDF)') ->assertSeeText('Credit-Pakete') ->assertSeeText('7 Tage') // boost 7d aus config