Siteβ―Builder
Editing:
modules-rss.php
writable 0666
<?php /************************************************************************** * RSSΒ MODULE (v9Β βΒ fileβcacheβ―+β―robust error handling) * ---------------------------------------------------------------------- * β’ First good build: fetch RSS/JSON β render <ul> β save to * /ph/<phone>/rss-cache.html or /social/<handle>/rss-cache.html * β’ Later builds: serve cached HTML (unless older than $ttlSecs) * β’ If feed is misβconfigured or unreachable we either * β fall back to last good cache, OR * β show a 1βline muted error (no empty card) * β’ Nothing is echoed to the page except valid markup. * Detailed reasons go to the PHP errorβlog. **************************************************************************/ if (!function_exists('get_profile')) return; // safety β helper missing $profile = get_profile(); /* βββ figure out the profile folder βββββββββββββββββββββββββββββββββ */ $root = rtrim($_SERVER['DOCUMENT_ROOT'], '/'); $isBiz = isset($profile['name']) && isset($profile['phone']); // crude test if ($isBiz) { // /ph/########## $slug = preg_replace('/\D/', '', $profile['phone'] ?? ''); if ($slug === '') return; $dir = "$root/ph/$slug"; } else { // /social/<handle>/ $slug = ltrim($profile['handle'] ?? '', '@'); if ($slug === '') return; $dir = "$root/social/$slug"; } /* βββ feed URL & basic validation ββββββββββββββββββββββββββββββββββ */ $feedUrl = trim($profile['website_rss'] ?? ''); if ($feedUrl === '') return; // feed not set at all if (!preg_match('#^https?://#i', $feedUrl)) { // bad scheme echo '<p style="text-align:center;color:#888;font-size:.87rem;margin:1.7rem 0;">' . 'Feedβ―URLβ―misβconfigured</p>'; error_log("RSSβmodule: feed URL missing scheme β '$feedUrl' in $dir"); return; } /* βββ cache paths & policy βββββββββββββββββββββββββββββββββββββββββ */ $htmlFile = "$dir/rss-cache.html"; $ttlSecs = 3600; // 1β―hour β adjust if desired $maxItems = 10; /* serve fresh cache if still young enough */ if (is_readable($htmlFile) && (time() - filemtime($htmlFile) < $ttlSecs)) { $cached = file_get_contents($htmlFile); if ($cached) output_card($cached); return; } /* βββ fetch + build helper βββββββββββββββββββββββββββββββββββββββββ */ function build_feed_html(string $url, int $limit): string { $opts = ['http'=>['timeout'=>6,'user_agent'=>'BestDealOn RSS fetcher']]; $ctx = stream_context_create($opts); $raw = @file_get_contents($url, false, $ctx); if (!$raw) { error_log("RSSβmodule: unable to fetch '$url'"); return ''; } $items = []; /* 1) RSS / Atom XML ------------------------------------------------*/ libxml_use_internal_errors(true); if ($xml = simplexml_load_string($raw, 'SimpleXMLElement', LIBXML_NOCDATA)) { /* RSSΒ 2.0 */ foreach ($xml->channel->item ?? [] as $it) { $items[] = [ 'title'=>(string)$it->title, 'link' =>(string)$it->link, 'date' =>(string)$it->pubDate ]; if (count($items) >= $limit) break; } /* Atom */ foreach ($xml->entry ?? [] as $it) { $items[] = [ 'title'=>(string)$it->title, 'link' =>(string)$it->link['href'], 'date' =>(string)($it->updated ?: $it->published) ]; if (count($items) >= $limit) break; } } /* 2) JSON Feed -----------------------------------------------------*/ if (!$items && ($json = json_decode($raw, true)) && isset($json['items'])) { foreach ($json['items'] as $it) { $items[] = [ 'title'=>$it['title'] ?? '', 'link' =>$it['url'] ?? $it['external_url'] ?? '', 'date' =>$it['date_published'] ?? '' ]; if (count($items) >= $limit) break; } } if (!$items) return ''; // nothing usable $out='<ul class="rs-list">'; foreach ($items as $it) { $t = htmlspecialchars($it['title'] ?: 'Untitled'); $l = htmlspecialchars($it['link'] ?: '#'); $d = $it['date'] ? date('M j, Y', strtotime($it['date'])) : ''; $out .= '<li><a class="rs-title" href="'.$l.'" target="_blank" rel="noopener">'.$t.'</a>'; if ($d) $out .= ' <span class="rs-date">'.$d.'</span>'; $out .= '</li>'; } return $out.'</ul>'; } /* βββ build (or try to) βββββββββββββββββββββββββββββββββββββββββββββ */ $html = build_feed_html($feedUrl, $maxItems); /* If we got items β cache & output If we got nothing but a previous cache exists β output that + muted notice Else β muted βfeed unavailableβ and quit */ if ($html) { @mkdir($dir, 0775, true); file_put_contents($htmlFile, $html, LOCK_EX); output_card($html); return; } if (is_readable($htmlFile) && ($cached=file_get_contents($htmlFile))) { output_card($cached, 'Feed temporarily unavailable β showing last copy'); return; } /* finally: nothing to render at all */ echo '<p style="text-align:center;color:#888;font-size:.87rem;margin:1.7rem 0;">' . 'Feed temporarily unavailable</p>'; return; /* βββ helper to wrap HTML in the card + optional notice βββββββββββββ */ function output_card(string $ul, string $notice=''): void { ?> <section class="rs-shell"> <div class="rs-card"> <h2>π° Latest Posts</h2> <?= $ul ?> <?php if($notice): ?> <p style="font-size:.83rem;color:#777;margin-top:1rem"><?= htmlspecialchars($notice) ?></p> <?php endif; ?> </div> </section> <style> .rs-shell{margin:2.4rem auto;max-width:clamp(480px,70vw,720px);width:100%; font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif; text-align:center} .rs-card{background:#fff;padding:1.6rem 1.4rem;border:3.5px solid #ffb63b; border-radius:27px;box-shadow:0 8px 22px rgba(0,0,0,.05)} .rs-card h2{margin:0 0 1.1rem;font-size:1.33rem;font-weight:700;color:#102a66} .rs-list{list-style:none;padding:0;margin:0 auto;max-width:430px;text-align:left} .rs-list li{margin:1.05em 0} .rs-title{font-size:1.04rem;color:#1a0dab;text-decoration:none} .rs-title:hover{text-decoration:underline} .rs-date{display:block;font-size:.82rem;color:#555;margin-top:.18em} @media(prefers-color-scheme:dark){ .rs-card{background:#1a1f2b;border-color:#ffb63b;box-shadow:0 6px 18px #0006} .rs-title{color:#96b5ff} .rs-date{color:#aaa} } </style> <?php } ?>
Save changes
Create folder
writable 0777
Create
Cancel