site_title; // PHP 8+ Nullsafe Operator
* $logo = settings()?->site_logo;
*/
if(!function_exists("settings")) {
function settings() {
$settings = GeneralSetting::take(1)->first();
if(!is_null($settings)) { return $settings; }
}
}
/**
* Seiten Social Link
* Lädt die Social-Media-Links der Website aus der Datenbank.
*
* Hinweis:
* - Die Funktion gibt nur dann einen Wert zurück, wenn Einträge existieren.
* Andernfalls endet sie ohne expliziten Return (entspricht in PHP: null).
*
* @example
* $facebook = site_social_links()?->facebook;
* $twitter = site_social_links()?->twitter;
*/
if(!function_exists('site_social_links')) {
function site_social_links() {
$links = SiteSocialLink::take(1)->first();
if(!is_null($links)) { return $links; }
}
}
/**
* Dynamisches Navigations Menu
* Generiert die HTML-Navigation basierend auf Kategorien mit Beiträgen.
*
* Hinweis:
* - Es werden nur Kategorien berücksichtigt, die mindestens einen Beitrag haben.
* - Parent-Kategorien werden als Dropdown dargestellt, sofern Kinder mit Beiträgen existieren.
* - Kategorien ohne Parent werden als normale Navigationslinks ausgegeben.
*
* @return string HTML-Markup der Navigationsliste
*
* @example
* {!! navigations() !!}
*/
if(!function_exists('navigations')) {
function navigations() {
$navigations_html = '';
$pcategories = ParentCategory::whereHas('children', function($q) {
$q->whereHas('posts');
})->orderBy('name', 'asc')->get();
$categories = Category::whereHas('posts')->where('parent', 0)->orderBy('name', 'asc')->get();
if(count($pcategories) > 0) {
foreach($pcategories as $item) {
$navigations_html.='
'.$item->name.'
';
}
}
if(count($categories) > 0) {
foreach($categories as $item) {
$navigations_html.='
'.$item->name.'
';
}
}
return $navigations_html;
}
}
/**
* DATE FORMAT January 12, 2024
* Formatiert ein Datum in ein lesbares, lokalisiertes Format.
*
* Hinweis:
* - Erwartet ein Datum im Format `Y-m-d H:i:s`.
* - Die Ausgabe erfolgt im ISO-Format `LL` (z. B. „14. September 2025“).
*
* @param string $value Datum/Zeit im Format `Y-m-d H:i:s`
* @return string Formatiertes Datum
*
* @example
* {{ date_formatter($post->created_at) }}
*/
if(!function_exists('date_formatter')) {
function date_formatter($value) {
return Carbon::createFromFormat('Y-m-d H:i:s', $value)->isoFormat('LL');
}
}
/**
* Kürzt Wörter
* Kürzt einen Text auf eine bestimmte Anzahl von Wörtern.
*
* Hinweis:
* - HTML-Tags werden vor der Kürzung entfernt.
* - Am Ende des Textes wird optional ein Abschlusszeichen angehängt.
*
* @param string $value Ausgangstext
* @param int $words Maximale Anzahl an Wörtern (Standard: 15)
* @param string $end Angehängter Text am Ende (Standard: "...")
* @return string Gekürzter Text
*
* @example
* {{ words($post->content, 30) }}
*/
if(!function_exists('words')) {
function words($value, $words = 15, $end = '...') {
return Str::words(strip_tags($value), $words, $end);
}
}
/**
* Lesezeit
* Berechnet die geschätzte Lesezeit eines Textes.
*
* Hinweis:
* - Die Berechnung basiert auf ca. 200 Wörtern pro Minute.
* - Die minimale Rückgabe beträgt immer 1 Minute.
* - Mehrere Textteile können als Argumente übergeben werden.
*
* @param string ...$text Ein oder mehrere Textinhalte
* @return int Geschätzte Lesezeit in Minuten
*
* @example
* {{ readDuration($post->title, $post->content) }} Min. Lesezeit
*/
if (!function_exists('readDuration')) {
function readDuration(...$text): int
{
// Alles zu einem String zusammenfügen
$content = implode(' ', $text);
// HTML-Tags entfernen
$content = strip_tags($content);
// Wörter zählen (für DE ausreichend gut)
$totalWords = str_word_count($content);
// Lesegeschwindigkeit (Wörter pro Minute) – nach Bedarf anpassen
$wordsPerMinute = 220;
// Minuten berechnen und immer aufrunden
$minutesToRead = (int) ceil($totalWords / max(1, $wordsPerMinute));
// Mindestens 1 Minute zurückgeben
return max(1, $minutesToRead);
}
}
/**
* Zeigt letzten Post an
* Gibt die neuesten sichtbaren Blogbeiträge zurück.
*
* Hinweis:
* - Es werden nur veröffentlichte Beiträge berücksichtigt (`visibility = 1`).
* - Über `$skip` können Einträge übersprungen werden (z. B. für Slider oder Pagination).
*
* @param int $skip Anzahl der zu überspringenden Beiträge (Standard: 0)
* @param int $limit Maximale Anzahl der zurückgegebenen Beiträge (Standard: 5)
* @return \Illuminate\Support\Collection Sammlung von Blogbeiträgen
*
* @example
* @foreach(latest_posts(0, 3) as $post)
* {{ $post->title }}
* @endforeach
*/
if(!function_exists('latest_posts')) {
function latest_posts($skip = 0, $limit = 5) {
return Post::skip($skip)->limit($limit)->where('visibility', 1)->orderBy('created_at', 'desc')->get();
}
}
/**
* Listing Categories With Number of Posts on Sidebar
* Gibt Kategorien für die Sidebar zurück, sortiert nach Beitragsanzahl.
*
* Hinweis:
* - Es werden nur Kategorien mit mindestens einem Beitrag berücksichtigt.
* - Die Sortierung erfolgt absteigend nach Anzahl der Beiträge.
*
* @param int $limit Maximale Anzahl der Kategorien (Standard: 8)
* @return \Illuminate\Support\Collection Sammlung von Kategorien
*
* @example
* @foreach(sidebar_categories() as $category)
* {{ $category->name }} ({{ $category->posts_count }})
* @endforeach
*/
if(!function_exists('sidebar_categories')) {
function sidebar_categories($limit = 8) {
return Category::withCount('posts')->having('posts_count', '>', 0)->limit($limit)->orderBy('posts_count', 'desc')->get();
}
}
/**
* FETCH ALL TAGS FROM THE 'POSTS' TABLE
* Gibt eine eindeutige Liste aller verwendeten Tags zurück.
*
* Hinweis:
* - Tags werden aus dem `tags`-Feld der Beiträge gelesen (kommasepariert).
* - Leere Tag-Felder werden ignoriert.
* - Die Rückgabe ist alphabetisch sortiert und eindeutig.
*
* @param int|null $limit Maximale Anzahl der Tags (optional)
* @return array Liste der Tags
*
* @example
* @foreach(getTags() as $tag)
* {{ $tag }}
* @endforeach
*/
if (!function_exists('getTags')) {
function getTags($limit = null) {
$tags = Post::whereNotNull('tags')
->where('tags', '!=', '')
->pluck('tags');
$uniqueTags = $tags->flatMap(function ($tagsString) {
return explode(',', $tagsString);
})
->map(fn($tag) => normalizeTag($tag))
->filter()
->unique()
->sort()
->values();
if ($limit) {
$uniqueTags = $uniqueTags->take($limit);
}
return $uniqueTags->all();
}
}
function normalizeTag(string $tag): string
{
// urldecode: wandelt %20 und auch + -> Leerzeichen (wichtig!)
$tag = urldecode($tag);
// Whitespace vereinheitlichen
$tag = preg_replace('/\s+/u', ' ', trim($tag));
return $tag;
}
/**
* Listing Sidebar Latest posts
* Gibt die neuesten sichtbaren Blogbeiträge für die Sidebar zurück.
*
* Hinweis:
* - Es werden nur veröffentlichte Beiträge berücksichtigt (`visibility = 1`).
* - Optional kann ein bestimmter Beitrag ausgeschlossen werden.
* - Die Sortierung erfolgt nach Erstellungsdatum (neueste zuerst).
*
* @param int $limit Maximale Anzahl der Beiträge (Standard: 5)
* @param int|null $except ID eines auszuschließenden Beitrags (optional)
* @return \Illuminate\Support\Collection Sammlung von Blogbeiträgen
*
* @example
* @foreach(sidebar_latest_posts(5, $post->id) as $item)
* {{ $item->title }}
* @endforeach
*/
if(!function_exists('sidebar_latest_posts')) {
function sidebar_latest_posts($limit = 5, $except = null) {
$posts = Post::limit($limit);
if($except) {
$posts = $posts->where('id', '!=', $except);
}
return $posts->where('visibility', 1)->orderBy('created_at', 'desc')->get();
}
}
/**
* Home Slider
* Gibt aktive Slider-Einträge für den Home-Slider zurück.
*
* Hinweis:
* - Es werden nur Slides mit aktivem Status (`status = 1`) berücksichtigt.
* - Die Sortierung erfolgt nach der definierten Reihenfolge (`ordering`).
*
* @param int $limit Maximale Anzahl der Slides (Standard: 5)
* @return \Illuminate\Support\Collection Sammlung von Slides
*
* @example
* @foreach(get_slides() as $slide)
* {{ $slide->title }}
* @endforeach
*/
if(!function_exists('get_slides')) {
function get_slides($limit = 5) {
return Slide::where('status', 1)->limit($limit)->orderBy('ordering', 'asc')->get();
}
}
?>