or platform_render_footer(['use_i18n' => false]); * * Layout (each row omitted when empty): * [ top — full width ] * [ left | right ] — main row (copyright defaults on left when left unset) * [ bottom — full width ] */ function platform_footer_h(mixed $value): string { return htmlspecialchars((string) $value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); } /** @return array */ function platform_footer_config(): array { static $loaded = null; if ($loaded !== null) { return $loaded; } $path = __DIR__ . '/footer.config.php'; if (!is_file($path)) { $path = __DIR__ . '/footer.config.example.php'; } $loaded = require $path; return is_array($loaded) ? $loaded : []; } /** @param array $cfg */ function platform_footer_year_end(array $cfg): int { if (array_key_exists('year', $cfg) && $cfg['year'] !== null) { return (int) $cfg['year']; } return (int) date('Y'); } /** * Year label: single year or range (e.g. 2026–2026) when year_start is set. * * @param array $cfg */ function platform_footer_year_label(array $cfg): string { $end = platform_footer_year_end($cfg); $start = isset($cfg['year_start']) ? (int) $cfg['year_start'] : 0; if ($start > 0) { if (!empty($cfg['year_through_current'])) { return $start . ' - current'; } if ($start === $end) { return (string) $start; } return $start . "\u{2013}" . $end; } return (string) $end; } /** * Default left line: © holder[, year|year-range]. * * @param array $cfg */ function platform_footer_default_left(array $cfg): string { $symbol = trim((string) ($cfg['copyright_symbol'] ?? "\u{00A9}")); $holder = trim((string) ($cfg['holder'] ?? '')); $showYear = (bool) ($cfg['show_year'] ?? true); $parts = []; if ($symbol !== '') { $parts[] = $symbol; } if ($holder !== '') { $parts[] = $holder; } $line = implode(' ', $parts); if (!$showYear) { return $line; } $yearLabel = platform_footer_year_label($cfg); if ($line === '') { return $yearLabel; } return $line . ', ' . $yearLabel; } /** * Resolve optional row text (null/empty = omit row). Supports per-render overrides in $opts. * * @param array $cfg * @param array $opts */ function platform_footer_field(array $cfg, array $opts, string $key): ?string { if (array_key_exists($key, $opts)) { $v = $opts[$key]; if ($v === null || $v === false) { return null; } $t = trim((string) $v); return $t === '' ? null : $t; } if (!array_key_exists($key, $cfg)) { return null; } $v = $cfg[$key]; if ($v === null || $v === false) { return null; } $t = trim((string) $v); return $t === '' ? null : $t; } /** * @param array $cfg * @param array $opts */ function platform_footer_resolve_left(array $cfg, array $opts): ?string { $custom = platform_footer_field($cfg, $opts, 'left'); if ($custom !== null) { return $custom; } $built = platform_footer_default_left($cfg); return $built === '' ? null : $built; } /** @deprecated Use platform_footer_default_left(); kept for scripts/tests. */ function platform_footer_plain_text(array $cfg, int $year): string { $cfg = array_merge($cfg, ['year' => $year]); return platform_footer_default_left($cfg); } /** * @param array{use_i18n?: bool, extra_class?: string, top?: ?string, left?: ?string, right?: ?string, bottom?: ?string} $opts */ function platform_render_footer(array $opts = []): void { $cfg = platform_footer_config(); $top = platform_footer_field($cfg, $opts, 'top'); $left = platform_footer_resolve_left($cfg, $opts); $right = platform_footer_field($cfg, $opts, 'right'); $bottom = platform_footer_field($cfg, $opts, 'bottom'); $baseClass = (string) ($opts['extra_class'] ?? ($cfg['footer_class'] ?? 'bottom-bar')); $classes = trim($baseClass . ' platform-footer'); if ($top === null && $bottom === null && $right === null) { $classes .= ' platform-footer--single-row'; } $useI18n = $opts['use_i18n'] ?? (bool) ($cfg['use_i18n'] ?? true); $i18nKey = (string) ($cfg['i18n_key'] ?? 'footer.copyright'); $leftUsesDefault = platform_footer_field($cfg, $opts, 'left') === null; $yearEnd = platform_footer_year_end($cfg); echo ''; }