| Server IP : 188.114.97.3 / Your IP : 216.73.216.143 Web Server : Apache System : Linux sv058.home.net.pl 6.8.2 husak_dirty_pages_fix #1 SMP PREEMPT_DYNAMIC Tue Apr 2 22:06:51 CEST 2024 x86_64 User : ( 3194769) PHP Version : 8.5.12 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /includes/ |
Upload File : |
<?php
declare(strict_types=1);
/** Polana V16.4: dynamiczny indeks URL dla sitemap i panelu SEO. Tylko zatwierdzone publiczne strony. */
function p164_base(): string {
// Ta domena powinna być zgodna z <link rel="canonical"> generowanym przez site_url().
$base = rtrim((string)site_url(''), '/');
$p = parse_url($base);
if (!is_array($p) || ($p['scheme'] ?? '') !== 'https' || !in_array(strtolower((string)($p['host'] ?? '')), ['mojapolanasmakow.pl','polanasmakow.pl'], true)) {
throw new RuntimeException('Niepoprawny adres site_url; ustaw HTTPS i domenę Polany w panelu SEO.');
}
return $base;
}
function p164_xml(string $v): string {
return htmlspecialchars($v, ENT_XML1|ENT_QUOTES|ENT_SUBSTITUTE, 'UTF-8');
}
function p164_path(string $path, string $lang): string {
// Stosujemy te same publiczne aliasy, co flagi V11.
if (function_exists('p11_path')) return p11_path($path, $lang);
$parts=explode('?', $path, 2);
$aliases=['/andrzej-polan'=>'/chef','/kontakt'=>'/contact','/rezerwacja'=>'/reservation',
'/polityka-prywatnosci'=>'/privacy','/alergeny'=>'/allergens','/galeria'=>'/gallery',
'/wspolpraca'=>'/cooperation'];
$stem=($lang==='pl' ? $parts[0] : '/'.$lang.($aliases[$parts[0]] ?? $parts[0]));
if ($lang!=='pl' && $parts[0]==='/') $stem='/'.$lang.'/';
return $stem.(isset($parts[1])?'?'.$parts[1]:'');
}
function p164_ready_map(): array {
$ready=[];
try {
$sql="SELECT path,lang FROM polana_v11_page_locales WHERE ready=1 AND lang IN ('en','de','es')";
foreach(db()->query($sql)->fetchAll(PDO::FETCH_ASSOC) as $r) {
$ready[(string)$r['path'].'|'.(string)$r['lang']]=true;
}
}catch(Throwable $e) { error_log('Polana SEO V164 pages ready: '.$e->getMessage()); }
return $ready;
}
function p164_lastmod($value): ?string {
if(!is_string($value) || !preg_match('/^\d{4}-\d{2}-\d{2}/',$value)) return null;
$day=substr($value,0,10);
$dt=DateTimeImmutable::createFromFormat('!Y-m-d',$day);
return $dt && $dt->format('Y-m-d')===$day ? $day : null;
}
function p164_sitemap_data(): array {
$base=p164_base(); $root=dirname(__DIR__); $now=date('Y-m-d');
$ready=p164_ready_map(); $entries=[]; $skipped=['unapproved_language'=>0,'unpublished'=>0,'hidden'=>0];
if(setting('site_public_mode','normal')!=='normal') {
return ['urls'=>[], 'entries'=>[], 'skipped'=>$skipped, 'base'=>$base,'splash'=>true];
}
$add=static function(string $path,?string $modified=null,bool $allLanguages=true,array $langs=[])use(&$entries,$ready,$root,$base,&$skipped):void {
if($langs===[]) {
$langs=['pl'];
foreach(['en','de','es'] as $lang) {
$flag = $path==='/' ? '/' : explode('?', $path,2)[0];
// Strona /menu-seo odpowiada zatwierdzonej stronie /menu.
if($flag==='/menu-seo') $flag='/menu';
if($allLanguages && isset($ready[$flag.'|'.$lang])) $langs[]=$lang;
elseif($allLanguages) $skipped['unapproved_language']++;
}
}
$alternates=[];
foreach($langs as $lang) {
$alternates[$lang]=$base.p164_path($path,$lang);
}
foreach($alternates as $lang=>$url) {
$entries[]=['loc'=>$url,'lang'=>$lang,'path'=>$path,'lastmod'=>$modified,'alternates'=>$alternates];
}
};
$static=[
['/', 'index.php',true],
['/andrzej-polan','andrzej-polan.php',true],
['/kontakt','kontakt.php',true],
['/alergeny','alergeny.php',true],
['/polityka-prywatnosci','polityka-prywatnosci.php',true],
];
if(function_exists('reservations_enabled') && reservations_enabled()) $static[]=['/rezerwacja','rezerwacja.php',true];
if(setting('nav_gallery_enabled','0')==='1') $static[]=['/galeria','galeria.php',true];
if(setting('nav_collaboration_enabled','0')==='1') $static[]=['/wspolpraca','wspolpraca.php',true];
foreach($static as [$route,$file,$enabled]) {
if(!$enabled || !is_file($root.'/'.$file))continue;
$add($route);
}
// Menu graficzne /menu ma NOINDEX: do sitemap tylko osobne indeksowalne /menu-seo.
if(is_file($root.'/menu-seo.php')) {
$menuRows=[];
try {
$q=db()->prepare("SELECT menu_type,MAX(updated_at) lastmod FROM menus WHERE status='published' AND (valid_from IS NULL OR valid_from<=?) AND (valid_to IS NULL OR valid_to>=?) GROUP BY menu_type");
$q->execute([$now,$now]);
$menuRows=$q->fetchAll(PDO::FETCH_ASSOC);
}catch(Throwable $e){ error_log('Polana SEO V164 menu: '.$e->getMessage()); }
// Nie zgłaszamy nieaktywnych lub brakujących kart.
foreach($menuRows as $m) {
$kind=(string)($m['menu_type']??'');
if(!in_array($kind,['food','soft','wine'],true))continue;
$url='/menu-seo'.($kind==='food'?'':'?kind='.$kind);
$add($url,p164_lastmod($m['lastmod']??null));
}
}
$blogEnabled=function_exists('blog_public_enabled') && blog_public_enabled();
if($blogEnabled && is_file($root.'/blog.php')) {
// Publikacja zaplanowanych wpisów działa również przy wejściu na sitemap — bez crona.
if(function_exists('blog_promote_due_posts')) blog_promote_due_posts();
$posts=[];
try {
$posts=db()->query("SELECT slug,updated_at,
(NULLIF(TRIM(title_en),'') IS NOT NULL AND NULLIF(TRIM(content_en),'') IS NOT NULL) AS en_ready,
(NULLIF(TRIM(title_de),'') IS NOT NULL AND NULLIF(TRIM(content_de),'') IS NOT NULL) AS de_ready,
(NULLIF(TRIM(title_es),'') IS NOT NULL AND NULLIF(TRIM(content_es),'') IS NOT NULL) AS es_ready
FROM blog_posts WHERE status='published' AND publish_at IS NOT NULL AND publish_at<=NOW()
ORDER BY publish_at DESC,id DESC LIMIT 10000")->fetchAll(PDO::FETCH_ASSOC);
}catch(Throwable $e){throw new RuntimeException('Brak możliwości odczytu opublikowanych wpisów bloga.',0,$e);}
$blogLastmod=null;
foreach($posts as $one) {
$day=p164_lastmod($one['updated_at']??null);
if($day!==null && ($blogLastmod===null || $day>$blogLastmod)) $blogLastmod=$day;
}
$add('/blog',$blogLastmod);
foreach($posts as $post) {
$slug=(string)($post['slug']??'');
if(!preg_match('/^[a-z0-9-]{1,210}$/',$slug))continue;
$langs=['pl'];
foreach(['en','de','es'] as $lang) {
if((int)($post[$lang.'_ready']??0)===1) $langs[]=$lang;
else $skipped['unapproved_language']++;
}
$add('/blog/'.$slug,p164_lastmod($post['updated_at']??null),false,$langs);
}
}
return ['urls'=>$entries,'entries'=>$entries,'skipped'=>$skipped,'base'=>$base,'splash'=>false];
}
function p164_sitemap_xml(array $data): string {
$lines=['<?xml version="1.0" encoding="UTF-8"?>',
'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">'];
foreach($data['urls'] as $u) {
$lines[]=' <url>';
$lines[]=' <loc>'.p164_xml((string)$u['loc']).'</loc>';
foreach(($u['alternates']??[]) as $lang=>$href) {
$lines[]=' <xhtml:link rel="alternate" hreflang="'.p164_xml((string)$lang).'" href="'.p164_xml((string)$href).'" />';
}
if(!empty($u['lastmod']))$lines[]=' <lastmod>'.p164_xml((string)$u['lastmod']).'</lastmod>';
$lines[]=' </url>';
}
$lines[]='</urlset>';
return implode("\n",$lines)."\n";
}