Added RSS/Atom feeds to the news section.

This commit is contained in:
flash 2019-04-12 23:37:59 +02:00
parent 6ecb590c57
commit fc476ac28c
10 changed files with 232 additions and 4 deletions

View file

@ -0,0 +1,25 @@
.news__feed {
display: flex;
color: inherit;
text-decoration: none;
font-size: 1.5em;
line-height: 32px;
height: 32px;
transition: background-color .2s;
border-radius: 4px;
&:hover,
&:focus {
background-color: fade(#fff, 20%);
}
&:active {
background-color: fade(#fff, 10%);
}
&__icon {
width: 32px;
height: 32px;
text-align: center;
}
}

View file

@ -0,0 +1,6 @@
.news__feeds {
display: grid;
grid-template-columns: 1fr 1fr;
grid-gap: 2px;
padding: 2px;
}

View file

@ -1,4 +1,5 @@
.news__list {
margin: 2px 0;
&__item {
text-decoration: none;

View file

@ -3,3 +3,5 @@
@import "preview";
@import "sidebar";
@import "post";
@import "feeds";
@import "feed";

View file

@ -9,6 +9,7 @@ if (!empty($_GET['n']) && is_string($_GET['n'])) {
return;
}
$feedMode = trim($_SERVER['PATH_INFO'] ?? '', '/');
$categoryId = !empty($_GET['c']) && is_string($_GET['c']) ? (int)$_GET['c'] : 0;
$postId = !empty($_GET['p']) && is_string($_GET['p']) ? (int)$_GET['p'] : 0;
@ -67,8 +68,23 @@ if ($categoryId > 0) {
$featured = news_posts_get(0, 10, $category['category_id'], true);
tpl_var('news_pagination', $categoryPagination);
echo tpl_render('news.category', compact('category', 'posts', 'featured'));
if ($feedMode === 'rss' || $feedMode === 'atom') {
header("Content-Type: application/{$feedMode}+xml; charset=utf-8");
echo news_feed($feedMode, $posts, [
'title' => config_get('Site', 'name') . ' » ' . $category['category_name'],
'subtitle' => $category['category_description'],
'html-url' => url('news-category', ['category' => $category['category_id']]),
'feed-url' => url("news-category-feed-{$feedMode}", ['category' => $category['category_id']]),
]);
return;
}
echo tpl_render('news.category', [
'category' => $category,
'posts' => $posts,
'featured' => $featured,
'news_pagination' => $categoryPagination,
]);
return;
}
@ -94,5 +110,19 @@ if (!$posts) {
return;
}
tpl_var('news_pagination', $newsPagination);
echo tpl_render('news.index', compact('categories', 'posts'));
if ($feedMode === 'rss' || $feedMode === 'atom') {
header("Content-Type: application/{$feedMode}+xml; charset=utf-8");
echo news_feed($feedMode, $posts, [
'title' => config_get('Site', 'name') . ' » Featured News',
'subtitle' => 'A live featured news feed.',
'html-url' => url('news-index'),
'feed-url' => url("news-feed-{$feedMode}"),
]);
return;
}
echo tpl_render('news.index', [
'categories' => $categories,
'posts' => $posts,
'news_pagination' => $newsPagination,
]);

View file

@ -297,3 +297,85 @@ function news_post_get(int $postId): array
$getPost->bindValue(':post_id', $postId);
return db_fetch($getPost);
}
function news_feed(string $type, array $posts, array $info): string
{
$document = new DOMDocument('1.0', 'utf-8');
$urlPrefix = url_prefix(false);
$htmlUrl = $urlPrefix . $info['html-url'];
$feedUrl = $urlPrefix . $info['feed-url'];
if ($type === 'rss') {
$dateFormat = 'r';
$rss = $document->appendChild($document->createElement('rss'));
$rss->setAttribute('version', '2.0');
$rss->setAttribute('xmlns:atom', 'http://www.w3.org/2005/Atom');
$feed = $rss->appendChild($document->createElement('channel'));
$feed->appendChild($document->createElement('ttl', '900'));
} else {
$dateFormat = 'c';
$feed = $document->appendChild($document->createElement('feed'));
$feed->setAttribute('xmlns', 'http://www.w3.org/2005/Atom');
$link = $feed->appendChild($document->createElement('link'));
$link->setAttribute('href', $htmlUrl);
}
$feed->appendChild($document->createElement('title', $info['title']));
$feed->appendChild($document->createElement(
$type === 'rss' ? 'description' : 'subtitle', $info['subtitle']
));
$feed->appendChild($document->createElement(
$type === 'rss' ? 'link' : 'id', $htmlUrl
));
$feed->appendChild($document->createElement(
$type === 'rss' ? 'pubDate' : 'updated',
date($dateFormat, strtotime($posts[0]['post_created']))
));
$link = $feed->appendChild($document->createElement($type === 'rss' ? 'atom:link' : 'link'));
$link->setAttribute('rel', 'self');
$link->setAttribute('href', $feedUrl);
foreach ($posts as $post) {
$entry = $feed->appendChild($document->createElement($type === 'rss' ? 'item' : 'entry'));
$entry->appendChild($document->createElement('title', $post['post_title']));
$entry->appendChild($document->createElement(
$type === 'rss' ? 'link' : 'id',
$urlPrefix . url('news-post', ['post' => $post['post_id']])
));
$entry->appendChild($document->createElement(
$type === 'rss' ? 'pubDate' : 'updated',
date($dateFormat, strtotime($post['post_created']))
));
$entry->appendChild($document->createElement(
$type === 'rss' ? 'description' : 'summary',
first_paragraph($post['post_text'])
));
if ($type === 'rss') {
$entry->appendChild($document->createElement(
'comments',
$urlPrefix . url('news-post-comments', ['post' => $post['post_id']])
));
$guid = $entry->appendChild($document->createElement(
'guid',
$urlPrefix . url('news-post', ['post' => $post['post_id']])
));
$guid->setAttribute('isPermaLink', 'true');
} else {
$link = $entry->appendChild($document->createElement('link'));
$link->setAttribute('href', $urlPrefix . url('news-post', ['post' => $post['post_id']]));
$link->setAttribute('type', 'text/html');
$html = $entry->appendChild($document->createElement(
'content',
htmlentities(parse_text($post['post_text'], MSZ_PARSER_MARKDOWN))
));
$html->setAttribute('type', 'html');
$author = $entry->appendChild($document->createElement('author'));
$author->appendChild($document->createElement('name', $post['username']));
$author->appendChild($document->createElement('uri', $urlPrefix . url('user-profile', ['user' => $post['user_id']])));
}
}
return $document->saveXML();
}

View file

@ -30,6 +30,10 @@ define('MSZ_URLS', [
'news-post' => ['/news.php', ['p' => '<post>']],
'news-post-comments' => ['/news.php', ['p' => '<post>'], 'comments'],
'news-category' => ['/news.php', ['c' => '<category>', 'page' => '<page>']],
'news-feed-rss' => ['/news.php/rss'],
'news-category-feed-rss' => ['/news.php/rss', ['c' => '<category>']],
'news-feed-atom' => ['/news.php/atom'],
'news-category-feed-atom' => ['/news.php/atom', ['c' => '<category>']],
'forum-index' => ['/forum'],
'forum-leaderboard' => ['/forum/leaderboard.php', ['id' => '<id>', 'mode' => '<mode>']],

View file

@ -56,4 +56,10 @@
<link rel="og:url" href="{{ canonical_url }}">
{% endif %}
{% endif %}
{% if feeds is defined and feeds is iterable %}
{% for feed in feeds %}
<link rel="alternate" type="application/{{ feed.type }}+xml" title="{{ feed.title|default(feed.type) }}" href="{{ feed.url }}">
{% endfor %}
{% endif %}
{% endspaceless %}

View file

@ -9,6 +9,19 @@
'page': news_pagination.page > 2 ? news_pagination.page : 0,
}) %}
{% set feeds = [
{
'type': 'rss',
'title': '',
'url': url('news-category-feed-rss', {'category': category.category_id}),
},
{
'type': 'atom',
'title': '',
'url': url('news-category-feed-atom', {'category': category.category_id}),
},
] %}
{% block content %}
<div class="news__container">
<div class="news__preview__listing">
@ -41,6 +54,29 @@
</div>
</div>
{% endif %}
<div class="container">
{{ container_title('Feeds') }}
<div class="news__feeds">
<a href="{{ url('news-category-feed-atom', {'category': category.category_id}) }}" class="news__feed">
<div class="news__feed__icon">
<i class="fas fa-rss"></i>
</div>
<div class="news__feed__type">
Atom
</div>
</a>
<a href="{{ url('news-category-feed-rss', {'category': category.category_id}) }}" class="news__feed">
<div class="news__feed__icon">
<i class="fas fa-rss"></i>
</div>
<div class="news__feed__type">
RSS
</div>
</a>
</div>
</div>
</div>
</div>
{% endblock %}

View file

@ -8,6 +8,19 @@
}) %}
{% set manage_link = '/manage/news.php?v=index' %}
{% set feeds = [
{
'type': 'rss',
'title': '',
'url': url('news-feed-rss'),
},
{
'type': 'atom',
'title': '',
'url': url('news-feed-atom'),
},
] %}
{% block content %}
<div class="news__container">
<div class="news__preview__listing">
@ -37,6 +50,29 @@
{% endfor %}
</div>
</div>
<div class="container">
{{ container_title('Feeds') }}
<div class="news__feeds">
<a href="{{ url('news-feed-atom') }}" class="news__feed">
<div class="news__feed__icon">
<i class="fas fa-rss"></i>
</div>
<div class="news__feed__type">
Atom
</div>
</a>
<a href="{{ url('news-feed-rss') }}" class="news__feed">
<div class="news__feed__icon">
<i class="fas fa-rss"></i>
</div>
<div class="news__feed__type">
RSS
</div>
</a>
</div>
</div>
</div>
</div>
{% endblock %}