Startseiten-Prototyp unter Dev-Link

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Kevin Adametz 2026-05-28 08:21:40 +00:00
parent 086ba968f7
commit 754aa699a1
4 changed files with 390 additions and 0 deletions

View file

@ -0,0 +1,95 @@
{% form_theme search_form 'default/form/theme.html.twig' %}
<section class="section fullscreen background start-slider dev-start-slider">
<div class="absolute-section">
<div class="container-fluid">
<div class="row">
<div class="col-md-12 col-xs-12">
<div class="home-message text-center">
<div class="home-info-box">
<div id="eKomiSeal_default" class="eKomi-header" style="padding-top: 5px;padding-left: 2px;">
<img class="lozad" border="0" src="{{ asset('images/dummy.png') }}" data-src="{{ asset('images/logo-qualitaet.png') }}" alt="Top Kundenservice" height="78">
</div>
<ul class="c4">
<li>Spezialist für Kulturreisen</li>
<li>Reiseexperte seit 1998</li>
<li>Beratung für individuelle Reisen</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="myCarousel" class="carousel slide">
<div class="carousel-inner">
<div class="item active">
<div class="fill lozad" style="background-image:url(images/placeholder-image.png)" data-background-image="{{ image('bundles/app/images/travel/slider_aegypten.jpg') }}"></div>
<noscript>
<div class="fill" style="background-image:url({{ image('bundles/app/images/travel/slider_aegypten.jpg').cropResize(1024).guess(70) }})"></div>
</noscript>
</div>
</div>
</div>
</section>
<section class="nopadding">
<div class="container-full absolute">
<div class="container-fluid container-form">
<div class="home-form">
<div class="tab-content">
<div role="tabpanel" class="tab-pane active" id="tab_01">
<form class="bookform form-inline row st-search-form" style="margin-right: -5px; margin-left: -5px;" action="/suche" method="get">
<div class="form-group col-lg-2 col-md-2 col-sm-3 col-xs-6" style="padding-right: 5px;padding-left: 5px;">
{{ form_field_pho(search_form.b, 'Anreise am') }}
</div>
<div class="form-group col-lg-2 col-md-2 col-sm-3 col-xs-6" style="padding-right: 5px;padding-left: 5px;">
{{ form_field_pho(search_form.e, 'Abreise am') }}
</div>
<div class="form-group col-lg-2 col-md-3 col-sm-3 col-xs-6" style="padding-right: 5px;padding-left: 5px;">
{{ form_field_pho(search_form.c) }}
</div>
<div class="form-group col-lg-2 col-md-3 col-sm-3 col-xs-6" style="padding-right: 5px;padding-left: 5px;">
<label class="sr-only" for="departure">Abfahrtsort</label>
<div class="dropdown form-bottom">
<select id="departure" class="selectpicker" data-style="btn-white" data-dropup-auto="false">
<option>Abfahrtsort beliebig</option>
<option>Basel</option>
<option>Berlin</option>
<option>Berlin Schönefeld</option>
<option>Berlin Tegel</option>
<option>Bonn</option>
<option>Bremen</option>
<option>Dresden</option>
<option>Düsseldorf</option>
<option>Eigenanreise</option>
<option>Erfurt</option>
<option>Frankfurt</option>
<option>Friedrichshafen</option>
<option>Genf</option>
<option>Graz</option>
<option>Hamburg</option>
<option>Hannover</option>
<option>Köln</option>
<option>Leipzig</option>
<option>Linz</option>
<option>München</option>
<option>Nürnberg</option>
<option>Saarbrücken</option>
<option>Salzburg</option>
<option>Stuttgart</option>
<option>Wien</option>
<option>Zürich</option>
</select>
</div>
</div>
<div class="form-group col-lg-4 col-md-2 col-sm-12 col-xs-12" style="padding-right: 5px;padding-left: 5px;">
<button type="submit" class="btn btn-primary btn-block text-center"><i class="fa fa-search" style="font-size: 1.1em"></i> &nbsp;<span class="hidden-md">Kulturreisen</span> suchen</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</section>

View file

@ -0,0 +1,120 @@
{% extends 'base.html.twig' %}
{% block meta_description %}
<meta name="description" content="STERN TOURS Testversion der Startseite fuer die Abstimmung.">
{% endblock %}
{% block meta_keywords %}
<meta name="keywords" content="STERN TOURS, Kulturreisen, Ferienwohnungen Usedom">
{% endblock %}
{% block meta_robots %}
<meta name="robots" content="noindex,nofollow" />
{% endblock %}
{% block canonical_tag %}{% endblock %}
{% block stylesheets %}
{{ parent() }}
<style>
.dev-home-note {
margin-bottom: 25px;
padding: 14px 18px;
border-left: 4px solid #648859;
background: #f4f7f2;
color: #3f4a3a;
}
.dev-usedom-teaser {
margin: 35px 0;
padding: 30px;
background: #f6f1e8;
border-radius: 4px;
}
.dev-usedom-teaser .lead {
margin-bottom: 20px;
}
.dev-usedom-teaser .btn {
margin-top: 5px;
}
</style>
{% endblock %}
{% block header2 %}
{% include 'default/components/home/dev_slider.html.twig' %}
{% endblock %}
{% block breadcrumb %}{% endblock %}
{% block body %}
<div id="section_orders">
<div class="dev-home-note">
<strong>Interne Abstimmungsversion:</strong>
Diese Startseite ist nur unter dem Testlink sichtbar und nicht fuer Suchmaschinen freigegeben.
</div>
<h1>Unsere beliebtesten Kulturreisen</h1>
<section id="dev-home-offers">
{% if homepage_offer_pages is not empty %}
{% include 'default/components/multiPageBoxCarousel.html.twig' with {pages: homepage_offer_pages} %}
{% else %}
<p>Aktuell konnten keine kuratierten Reiseangebote geladen werden.</p>
{% endif %}
</section>
<section class="clearfix dev-usedom-teaser" id="dev-home-usedom">
<div class="row">
<div class="col-md-8">
<h2 class="h3 h3l">Lieber näher zuhause? Ferienwohnungen auf Usedom</h2>
<p class="lead">
Neben unseren Kulturreisen bieten wir acht Ferienwohnungen in zwei Häusern auf Usedom.
Ideal für alle, die kurzfristig, individuell und nah an der Ostsee Urlaub machen möchten.
</p>
<a class="btn btn-primary" href="/ferienwohnungen" title="Ferienwohnungen auf Usedom ansehen">
Ferienwohnungen ansehen
</a>
</div>
<div class="col-md-4">
<p>
Der Block macht Usedom als zweites Standbein sichtbar, ohne die Kulturreisen zu verdrängen.
Bilder und Reihenfolge können nach Sichtung des vorhandenen Bildpools noch feinjustiert werden.
</p>
</div>
</div>
{% if fewo_lodgings is not empty %}
<div class="row">
{% for lodging in fewo_lodgings %}
{% include 'default/components/pageLodgingBox.html.twig' %}
{% endfor %}
</div>
{% endif %}
</section>
<section id="dev-home-countries">
<div class="clearfix">
<h2 class="h3 h3l">Alle Reisekategorien auf einen Blick</h2>
</div>
{% include 'default/components/multiPageBoxCarousel.html.twig' with {pages: country_pages} %}
</section>
<section class="clearfix" id="dev-home-copy">
<div class="content-copy">
<h1>STERN TOURS - Ihr Kulturreise-Spezialist aus Berlin</h1>
<p class="ft">
Herzlich willkommen bei STERN TOURS, Ihrem Reiseveranstalter für ausgewählte Kulturreisen.
In der aktuellen Startseitenfassung stehen besonders die Reiseziele im Vordergrund, die
derzeit gut planbar und verkaufbar sind: Ägypten, Marokko, Usbekistan und Oman.
</p>
<h2 class="h3 h3l">Kulturreisen mit Erfahrung und persönlicher Beratung</h2>
<p class="ft">
Seit 1998 beraten wir Reisende zu Kulturreisen in den Orient und angrenzende Regionen.
Die neue Frontseite soll Orientierung geben, buchbare Reisen sichtbar machen und zugleich
verantwortungsvoll mit Destinationen umgehen, bei denen die Lage eine vorsichtigere
Kommunikation erfordert.
</p>
</div>
</section>
</div>
{% endblock body %}

View file

@ -73,6 +73,60 @@ class DefaultController extends Controller
]); ]);
} }
/**
* @Route("/dev/seite/startseite")
*/
public function devHomepageAction()
{
$search_request_b = Util::getMySession('search_request_b');
$search_request_e = Util::getMySession('search_request_e');
$search_request_c = Util::getMySession('search_request_c');
if($search_request_b){
$timestap_b = strtotime($search_request_b);
$search_request_b = new \DateTime();
$search_request_b->setTimestamp($timestap_b);
}
if($search_request_e){
$timestap_e = strtotime($search_request_e);
$search_request_e = new \DateTime();
$search_request_e->setTimestamp($timestap_e);
}
if($search_request_c){
$repo = $this->getEntityManager()->getRepository('AppBundle:TravelCountry');
$search_request_c = $repo->find($search_request_c);
}
$pageRepo = $this->getEntityManager()->getRepository('AppBundle:Page');
$fewoLodgings = [];
$lodgingGroups = $this->getEntityManager()->getRepository('AppBundle:FewoLodgingGroup')->findAll();
foreach ($lodgingGroups as $lodgingGroup) {
foreach ($lodgingGroup->getLodgings() as $lodging) {
$fewoLodgings[] = $lodging;
if (count($fewoLodgings) >= 3) {
break 2;
}
}
}
return $this->render('default/pages/dev/home.html.twig', [
'base_dir' => realpath($this->getParameter('kernel.root_dir').'/..').DIRECTORY_SEPARATOR,
'site_loading' => 'home',
'show_search_sidebar_widget' => false,
'show_offers_sidebar_widget' => false,
'search_form' => $this->createForm(SearchRequestType::class, [
'c' => $search_request_c ? $search_request_c : null,
'b' => $search_request_b ? $search_request_b : null,
'e' => $search_request_e ? $search_request_e : null,
])->createView(),
'tt_search_form' => $this->createForm(TtSearchRequestType::class)->createView(),
'homepage_offer_pages' => $pageRepo->findHomepageOffers(),
'country_pages' => $pageRepo->findHomepageCountryPages(),
'fewo_lodgings' => $fewoLodgings,
]);
}
/** /**
* @Route("/suche") * @Route("/suche")
*/ */

View file

@ -84,6 +84,127 @@ class PageRepository extends NestedTreeRepository
return $ret; return $ret;
} }
/**
* Curated offer selection for the start page test version.
*
* The existing findOffers() intentionally shuffles results. For the crisis
* communication start page we need a stable order with currently sellable
* destinations first.
*
* @param int $limit
* @return Page[]
*/
public function findHomepageOffers($limit = 12)
{
$pages = $this->createQueryBuilder('node')
->distinct()
->innerJoin('node.travelProgram', 'tp')
->addSelect('tp')
->innerJoin('tp.countries', 'c')
->addSelect('c')
->where('node.status = 1')
->andWhere('tp.status = 1')
->orderBy('node.order')
->addOrderBy('tp.position')
->addOrderBy('node.title')
->getQuery()
->execute();
$pages = array_values(array_filter($pages, function (Page $page) {
return $this->getHomepagePriority($page) <= 4;
}));
usort($pages, function (Page $a, Page $b) {
$priorityA = $this->getHomepagePriority($a);
$priorityB = $this->getHomepagePriority($b);
if ($priorityA !== $priorityB) {
return $priorityA - $priorityB;
}
$orderA = $a->getOrder() ?: 9999;
$orderB = $b->getOrder() ?: 9999;
if ($orderA !== $orderB) {
return $orderA - $orderB;
}
return strcasecmp($a->getTitle(), $b->getTitle());
});
return array_slice($pages, 0, $limit);
}
/**
* @return Page[]
*/
public function findHomepageCountryPages()
{
$pages = $this->findCountryPages();
usort($pages, function (Page $a, Page $b) {
$priorityA = $this->getHomepagePriority($a);
$priorityB = $this->getHomepagePriority($b);
if ($priorityA !== $priorityB) {
return $priorityA - $priorityB;
}
return strcasecmp($a->getTitle(), $b->getTitle());
});
return $pages;
}
private function getHomepagePriority(Page $page)
{
$haystack = $this->buildHomepageSortHaystack($page);
$priorities = [
0 => ['aegypt', 'agypt', 'egypt'],
1 => ['marokko'],
2 => ['usbek', 'uzbek'],
3 => ['oman'],
4 => ['jordan'],
6 => ['israel'],
7 => ['tuerkei', 'turkei'],
8 => ['iran'],
];
foreach ($priorities as $priority => $needles) {
foreach ($needles as $needle) {
if (strpos($haystack, $needle) !== false) {
return $priority;
}
}
}
return 99;
}
private function buildHomepageSortHaystack(Page $page)
{
$parts = [
$page->getSlug(),
$page->getTitle(),
$page->getTitleShort(),
$page->getRealUrlPath(),
];
if ($page->getCountry()) {
$parts[] = $page->getCountry()->getName();
$parts[] = $page->getCountry()->getSlug();
}
if ($page->getTravelProgram()) {
foreach ($page->getTravelProgram()->getCountries() as $country) {
$parts[] = $country->getName();
$parts[] = $country->getSlug();
}
}
return strtolower(implode(' ', array_filter($parts)));
}
public function findCountryPages() public function findCountryPages()
{ {
return $this->createQueryBuilder('node') return $this->createQueryBuilder('node')