feat(tags): this adds support for post, link, book, show and movie tags with a tag list view and per tag pages

This commit is contained in:
Cory Dransfeldt 2025-04-16 18:59:47 -07:00
parent 3d866262ca
commit 6fdc0b56b9
No known key found for this signature in database
35 changed files with 500 additions and 70 deletions

View file

@ -0,0 +1,7 @@
{% if tags %}
<div class="tags">
{%- for tag in tags -%}
<a href="/tags/{{ tag | downcase | url_encode }}">#{{ tag | downcase }}</a>
{%- endfor -%}
</div>
{% endif %}

View file

@ -0,0 +1,109 @@
<?php
require __DIR__ . "/../vendor/autoload.php";
require __DIR__ . "/../server/utils/init.php";
use GuzzleHttp\Client;
use voku\helper\HtmlMin;
$requestUri = $_SERVER["REQUEST_URI"];
$url = trim(parse_url($requestUri, PHP_URL_PATH), "/");
$postgrestUrl = $_ENV["POSTGREST_URL"] ?? getenv("POSTGREST_URL");
$postgrestApiKey = $_ENV["POSTGREST_API_KEY"] ?? getenv("POSTGREST_API_KEY");
if ($url === "tags") {
readfile("index.html");
exit();
}
if (!preg_match('/^tags\/(.+?)(?:\/(\d+))?$/', $url, $matches)) {
echo file_get_contents(__DIR__ . "/../404/index.html");
exit();
}
if (isset($matches[2]) && (int)$matches[2] === 1) {
header("Location: /tags/{$matches[1]}", true, 301);
exit();
}
$tag = strtolower(urldecode($matches[1]));
if (!preg_match('/^[\p{L}\p{N} _\-]+$/u', $tag)) {
http_response_code(400);
echo "Invalid tag";
exit();
}
$pageParam = isset($matches[2]) ? (int)$matches[2] : 0;
$page = max($pageParam, 1);
$pageSize = 20;
$offset = ($page - 1) * $pageSize;
$cacheKey = "tag_{$tag}_{$page}";
$useRedis = false;
$tagged = null;
try {
if (extension_loaded('redis')) {
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);
$useRedis = true;
}
} catch (Exception $e) {
error_log("Redis not available: " . $e->getMessage());
}
if ($useRedis && $redis->exists($cacheKey)) {
$tagged = json_decode($redis->get($cacheKey), true);
} else {
$client = new Client();
try {
$response = $client->post($postgrestUrl . '/rpc/get_tagged_content', [
'headers' => [
'Content-Type' => 'application/json',
'Authorization' => "Bearer {$postgrestApiKey}",
],
'json' => [
'tag_query' => $tag,
'page_size' => $pageSize,
'page_offset' => $offset
]
]);
$tagged = json_decode($response->getBody(), true);
if ($useRedis) {
$redis->setex($cacheKey, 3600, json_encode($tagged));
}
} catch (Exception $e) {
error_log($e->getMessage());
echo file_get_contents(__DIR__ . '/../404/index.html');
exit();
}
}
if (!$tagged || count($tagged) === 0) {
echo file_get_contents(__DIR__ . '/../404/index.html');
exit();
}
$totalCount = $tagged[0]['total_count'] ?? 0;
$totalPages = max(ceil($totalCount / $pageSize), 1);
$pagination = [
'pageNumber' => $page,
'pages' => range(1, $totalPages),
'href' => [
'previous' => $page > 1 ? "/tags/{$tag}/" . ($page - 1) : null,
'next' => $page < $totalPages ? "/tags/{$tag}/" . ($page + 1) : null
],
'links' => range(1, $totalPages)
];
$pageTitle = "#" . strtolower(ucfirst($tag)) . "";
$pageDescription = "All content tagged with #" . strtolower(ucfirst($tag)) . ".";
$fullUrl = "https://www.coryd.dev" . $requestUri;
ob_start();
header("Cache-Control: public, max-age=3600");
header("Expires: " . gmdate("D, d M Y H:i:s", time() + 3600) . " GMT");
?>

View file

@ -13,11 +13,11 @@
{{ item.content_date | date:"%B %e, %Y" }}
</time>
• {{ item.label }}
<span class="client-side">
<span class="client-side">
{%- if item.notes -%}
{% assign notes = item.notes | prepend: "### Notes\n" | markdown %}
{% render "blocks/dialog.liquid",
label:"Notes",
{% render "blocks/dialog.liquid",
icon:"info-circle",
content:notes,
id:item.content_date
%}
@ -54,6 +54,9 @@
{%- endif -%}
{%- endif -%}
</h3>
{% render "blocks/tags.liquid",
18 tags:item.tags
19 %}
</article>
{%- endfor -%}
</article>

View file

@ -5,3 +5,11 @@
<meta property="og:image" content="<?= htmlspecialchars("{{ globals.cdn_url }}" . ($ogImage ?? '{{ ogImage }}'), ENT_QUOTES, 'UTF-8') ?>" />
<meta property="og:url" content="<?= htmlspecialchars($fullUrl ?? '{{ fullUrl }}', ENT_QUOTES, 'UTF-8') ?>" />
<link rel="canonical" href="<?= htmlspecialchars($fullUrl ?? '{{ fullUrl }}', ENT_QUOTES, 'UTF-8') ?>" />
<?php if (!empty($pagination)): ?>
<?php if ($pagination['href']['next']): ?>
<link rel="next" href="<?= $pagination['href']['next'] ?>">
<?php endif; ?>
<?php if ($pagination['href']['previous']): ?>
<link rel="prev" href="<?= $pagination['href']['previous'] ?>">
<?php endif; ?>
<?php endif; ?>

View file

@ -29,6 +29,8 @@
{% render "fetchers/movie.php.liquid" %}
{%- when 'show' -%}
{% render "fetchers/show.php.liquid" %}
{%- when 'tags' -%}
{% render "fetchers/tags.php.liquid" %}
{%- when 'blog' -%}
{%- assign pageTitle = post.title -%}
{%- assign pageDescription = post.description -%}