Added tag filtering and RSS feed
This commit is contained in:
41
posts/feed.php
Normal file
41
posts/feed.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
require __DIR__ . '/posts.php';
|
||||
|
||||
$siteUrl = 'https://hexstudios.co';
|
||||
$siteTitle = 'Hex Studios';
|
||||
$siteDesc = 'Developer, biker, musician, engineer, and an unapologetic centrist in the deep red south.';
|
||||
|
||||
$posts = getPosts(__DIR__);
|
||||
|
||||
function xmlEscape($str) {
|
||||
return htmlspecialchars($str, ENT_XML1 | ENT_QUOTES, 'UTF-8');
|
||||
}
|
||||
|
||||
header('Content-Type: application/rss+xml; charset=UTF-8');
|
||||
echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
|
||||
?>
|
||||
<rss version="2.0">
|
||||
<channel>
|
||||
<title><?= xmlEscape($siteTitle) ?></title>
|
||||
<link><?= xmlEscape($siteUrl) ?></link>
|
||||
<description><?= xmlEscape($siteDesc) ?></description>
|
||||
<language>en-us</language>
|
||||
<lastBuildDate><?= date(DATE_RSS) ?></lastBuildDate>
|
||||
<?php foreach ($posts as $post):
|
||||
$postUrl = $post['type'] === 'html'
|
||||
? $siteUrl . '/posts/' . $post['file']
|
||||
: $siteUrl . '/post.html?file=' . urlencode($post['file']);
|
||||
?>
|
||||
<item>
|
||||
<title><?= xmlEscape($post['title']) ?></title>
|
||||
<link><?= xmlEscape($postUrl) ?></link>
|
||||
<guid isPermaLink="true"><?= xmlEscape($postUrl) ?></guid>
|
||||
<pubDate><?= date(DATE_RSS, $post['created']) ?></pubDate>
|
||||
<description><?= xmlEscape($post['excerpt']) ?></description>
|
||||
<?php foreach ($post['tags'] as $tag): ?>
|
||||
<category><?= xmlEscape($tag) ?></category>
|
||||
<?php endforeach; ?>
|
||||
</item>
|
||||
<?php endforeach; ?>
|
||||
</channel>
|
||||
</rss>
|
||||
@@ -1,49 +1,12 @@
|
||||
<?php
|
||||
header('Content-Type: application/json');
|
||||
require __DIR__ . '/posts.php';
|
||||
|
||||
$dir = __DIR__;
|
||||
$files = array_diff(scandir($dir), ['.', '..', 'list.php']);
|
||||
$posts = getPosts(__DIR__);
|
||||
|
||||
function parseFrontMatter($raw) {
|
||||
if (preg_match('/^---\r?\n(.+?)\r?\n---\r?\n(.*)$/s', $raw, $m)) {
|
||||
$meta = [];
|
||||
foreach (preg_split('/\r?\n/', $m[1]) as $line) {
|
||||
if (strpos($line, ':') === false) continue;
|
||||
[$key, $value] = explode(':', $line, 2);
|
||||
$meta[trim($key)] = trim($value, " \t\"'");
|
||||
}
|
||||
return $meta;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
$posts = [];
|
||||
foreach ($files as $file) {
|
||||
$ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
|
||||
if (!in_array($ext, ['html', 'md'])) continue;
|
||||
|
||||
$path = $dir . '/' . $file;
|
||||
$fallbackTitle = ucwords(str_replace(['-', '_'], ' ', pathinfo($file, PATHINFO_FILENAME)));
|
||||
$created = filectime($path); // fallback if no front matter date
|
||||
|
||||
$meta = [];
|
||||
if ($ext === 'md') {
|
||||
$raw = file_get_contents($path, false, null, 0, 4096); // just need the header
|
||||
$meta = parseFrontMatter($raw);
|
||||
}
|
||||
|
||||
$title = $meta['title'] ?? $fallbackTitle;
|
||||
$date = isset($meta['date']) ? strtotime($meta['date']) : $created;
|
||||
|
||||
$posts[] = [
|
||||
'file' => $file,
|
||||
'title' => $title,
|
||||
'type' => $ext,
|
||||
'created' => $date ?: $created,
|
||||
'date' => date('F j, Y', $date ?: $created),
|
||||
];
|
||||
}
|
||||
|
||||
usort($posts, fn($a, $b) => $b['created'] - $a['created']); // newest first
|
||||
$posts = array_map(function ($p) {
|
||||
unset($p['excerpt']);
|
||||
return $p;
|
||||
}, $posts);
|
||||
|
||||
echo json_encode($posts);
|
||||
68
posts/posts.php
Normal file
68
posts/posts.php
Normal file
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
function parseFrontMatter($raw) {
|
||||
if (preg_match('/^---\r?\n(.+?)\r?\n---\r?\n(.*)$/s', $raw, $m)) {
|
||||
$meta = [];
|
||||
foreach (preg_split('/\r?\n/', $m[1]) as $line) {
|
||||
if (strpos($line, ':') === false) continue;
|
||||
[$key, $value] = explode(':', $line, 2);
|
||||
$meta[trim($key)] = trim($value, " \t\"'");
|
||||
}
|
||||
return [$meta, $m[2]];
|
||||
}
|
||||
return [[], $raw];
|
||||
}
|
||||
|
||||
function makeExcerpt($body, $length = 220) {
|
||||
$text = preg_replace('/```.*?```/s', '', $body); // code blocks
|
||||
$text = preg_replace('/[#>*_`~\[\]]/', '', $text); // markdown symbols
|
||||
$text = preg_replace('/\(.*?\)/', '', $text); // link targets
|
||||
$text = preg_replace('/\s+/', ' ', $text); // collapse whitespace
|
||||
$text = trim($text);
|
||||
if (mb_strlen($text) > $length) {
|
||||
$text = mb_substr($text, 0, $length) . '…';
|
||||
}
|
||||
return $text;
|
||||
}
|
||||
|
||||
function getPosts($dir) {
|
||||
$skip = ['.', '..', 'list.php', 'feed.php', 'posts.php'];
|
||||
$files = array_diff(scandir($dir), $skip);
|
||||
|
||||
$posts = [];
|
||||
foreach ($files as $file) {
|
||||
$ext = strtolower(pathinfo($file, PATHINFO_EXTENSION));
|
||||
if (!in_array($ext, ['html', 'md'])) continue;
|
||||
|
||||
$path = $dir . '/' . $file;
|
||||
$fallbackTitle = ucwords(str_replace(['-', '_'], ' ', pathinfo($file, PATHINFO_FILENAME)));
|
||||
$created = filectime($path);
|
||||
|
||||
$meta = [];
|
||||
$body = '';
|
||||
if ($ext === 'md') {
|
||||
$raw = file_get_contents($path);
|
||||
[$meta, $body] = parseFrontMatter($raw);
|
||||
}
|
||||
|
||||
$title = $meta['title'] ?? $fallbackTitle;
|
||||
$date = isset($meta['date']) ? strtotime($meta['date']) : $created;
|
||||
$tags = isset($meta['tags']) && trim($meta['tags']) !== ''
|
||||
? array_map('trim', explode(',', $meta['tags']))
|
||||
: [];
|
||||
|
||||
$posts[] = [
|
||||
'file' => $file,
|
||||
'title' => $title,
|
||||
'type' => $ext,
|
||||
'created' => $date ?: $created,
|
||||
'date' => date('F j, Y', $date ?: $created),
|
||||
'tags' => $tags,
|
||||
'excerpt' => $body ? makeExcerpt($body) : '',
|
||||
];
|
||||
}
|
||||
|
||||
usort($posts, fn($a, $b) => $b['created'] - $a['created']); // newest first
|
||||
|
||||
return $posts;
|
||||
}
|
||||
Reference in New Issue
Block a user