添加评论、RSS 订阅和站点地图功能实现
其实通过之前的步骤我们已经完成了博客的基本功能,这一篇也是功能部分的最后一篇,我们来给博客加点料,让博客功能更加完善。
1、评论的问题
现在这个博客的主要缺憾就是用户不能对文章进行评论,不幸的是,博客评论有很多问题要处理。
首先是稳定、令人满意且通用的评论管理,当然,基于 Laravel 我们可以添加这个功能到后台管理系统,并且允许用户注册、登录、对文章进行评论等等。创建这些功能都很简单,没什么复杂性可言。
但是真正的问题在于垃圾评论。
你将如何有效防止垃圾评论?使用验证码?黑名单/白名单?还是创建类似 Maksim Surguy 这样的 SPAM Honeypot ?或者通过集成 Akismet ?
坦白说,我不想处理这些令人头疼的事情,只想安安心心写博客。我们还可以使用第三方评论系统分分钟搞定博客评论。
注:学院采用的策略是注册用户邮箱验证,验证后的用户才能登录进行评论,这虽然一定程度上提升了用户操作的复杂度,但是同时有效拒绝了垃圾用户,整体而言对于有效用户来说,是提升了用户体验的,不然就会到处看到令人糟心的垃圾评论。
2、添加 Disqus 评论框
国内的第三方评论系统基本上都歇菜了,我们可以使用墙外的 Disqus 实现博客评论。
注册 Disqus 账户并获取评论代码
首先到 Disqus.com 注册一个免费账号,有了账号并登录之后,点击「GET STARTED」链接,选择「I want to install Disqus on my site」,会跳转到一个表单页面,按照自己的博客站点填写表单信息如下:
然后点击「Create Site」提交表单,在跳转到的订阅计划里选择一个免费的计划:
接下来在博客平台选择页面选择最下面这个:
最终跳转到的页面中包含了评论区域渲染代码:
我们将上述方框中的代码拷贝到博客页面中评论显示区域即可。
创建 Disqus 评论局部视图
在 resources/views/blog/partials
目录下创建一个新的局部视图文件 disqus.blade.php
,编辑该文件内容如下:
<div id="disqus_thread"></div>
<script>
var disqus_config = function () {
this.page.url = 'http://blog.app/blog/{{ $post->slug }}';
this.page.identifier = 'blog-{{ $post->slug }}';
};
(function () { // DON'T EDIT BELOW THIS LINE
var d = document, s = d.createElement('script');
s.src = 'https://laravelxue-yuan.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
<noscript>
请启用 JavaScript 查看 <a href="https://disqus.com/?ref_noscript">Disqus 驱动的评论框</a>。
</noscript>
其实就是将上个步骤中 Disqus 的通用评论代码拷贝过来,并取消 disqus_config
变量的注释,然后修改 this.page.url
和 this.page.identifier
的值。
我们将传递到视图的 $post->slug
变量作为 Disqus 的标识符以便于聚合该文章下的所有评论。
更新博客详情页视图文件
最后,在布局视图 resources/views/blog/layouts/master.blade.php
中 @yield('content')
这行代码之后新增如下这行代码:
@yield('comments')
然后在 resources/views/blog/layouts/post.blade.php
视图文件底部添加如下代码:
@section('comments')
<hr>
<div class="container">
<div class="row">
<div class="col-lg-8 col-md-10 mx-auto">
@include('blog.partials.disqus')
</div>
</div>
</div>
@stop
好了,现在你的博客具备评论功能了,在文章详情页底部现在可以看到 Disqus 评论框如下:
这样,我们就可以通过评论框发送代码了。对于未登录用户,可以通过社交媒体登录,或者注册 Disqus 账号进行评论:
3、添加分享链接
除了评论之外,很多博客还支持分享文章或站点到社交媒体功能,比如微信、微博、QQ、豆瓣、Facebook、Twitter等。要实现这一功能,可以借助百度分享或者 JiaThis 之类的第三方分享代码工具,还可以通过 overture 维护的 Share.js 来实现。对应的中文文档比较丰富,操作也很简单,这里就不做演示了。
4、实现 RSS 订阅
RSS 订阅对大部分博客应用而言是必备功能。在 Laravrel 中实现 RSS 订阅非常方便。
安装 Composer 依赖包
我们使用 suin/php-rss-writer
扩展包来生成 RSS 文件。
首先通过 Composer 安装该扩展包:
composer require suin/php-rss-writer
创建 RSS 订阅服务
接下来我们来创建一个服务类用于创建和返回 RSS 订阅。在 app/Services
目录下创建一个 RssFeed.php
文件,并编辑其代码如下:
<?php
namespace App\Services;
use App\Models\Post;
use Carbon\Carbon;
use Illuminate\Support\Facades\Cache;
use Suin\RSSWriter\Channel;
use Suin\RSSWriter\Feed;
use Suin\RSSWriter\Item;
class RssFeed
{
/**
* Return the content of the RSS feed
*/
public function getRSS()
{
if (Cache::has('rss-feed')) {
return Cache::get('rss-feed');
}
$rss = $this->buildRssData();
Cache::add('rss-feed', $rss, 120);
return $rss;
}
/**
* Return a string with the feed data
*
* @return string
*/
protected function buildRssData()
{
$now = Carbon::now();
$feed = new Feed();
$channel = new Channel();
$channel
->title(config('blog.title'))
->description(config('blog.description'))
->url(url('/'))
->language('en')
->copyright('Copyright (c) ' . config('blog.author'))
->lastBuildDate($now->timestamp)
->appendTo($feed);
$posts = Post::where('published_at', '<=', $now)
->where('is_draft', 0)
->orderBy('published_at', 'desc')
->take(config('blog.rss_size'))
->get();
foreach ($posts as $post) {
$item = new Item();
$item
->title($post->title)
->description($post->subtitle)
->url($post->url())
->pubDate($post->published_at->timestamp)
->guid($post->url(), true)
->appendTo($channel);
}
$feed = (string)$feed;
// Replace a couple items to make the feed more compliant
$feed = str_replace(
'<rss version="2.0">',
'<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">',
$feed
);
$feed = str_replace(
'<channel>',
'<channel>' . "\n" . ' <atom:link href="' . url('/rss') .
'" rel="self" type="application/rss+xml" />',
$feed
);
return $feed;
}
}
更新博客配置
添加 rss_size
配置项到配置文件 config/blog.php
,我们会在 RSSFeed
服务类中用这个配置值判断在 RSS 显示多少篇文章:
<?php
return [
'name' => "Laravel 学院",
'title' => "Laravel 学院",
'subtitle' => 'https://laravel.geekai.co',
'description' => 'Laravel学院致力于提供优质Laravel中文学习资源',
'author' => '学院君',
'page_image' => 'home-bg.jpg',
'posts_per_page' => 5,
'rss_size' => 25,
'uploads' => [
'storage' => 'public',
'webpath' => '/storage/uploads/',
],
'contact_email'=>env('MAIL_FROM'),
];
添加 RSS 路由、链接和方法
要实现 RSS 订阅功能还有三件事情要做。首先是添加路由到 routes/web.php
:
// 在下面这个路由后面
Route::post('contact', 'ContactController@sendContactInfo');
// 添加新的路由
Route::get('rss', 'BlogController@rss');
接下来更新 blog.layouts.master
视图文件 :
// 将如下这行代码
<title>{{ $title ?? config('blog.title') }}</title>
// 替换为
<title>{{ $title ?? config('blog.title') }}</title>
<link rel="alternate" type="application/rss+xml" href="{{ url('rss') }}"
title="RSS Feed {{ config('blog.title') }}">
最后,更新 BlogController
控制器,新增 rss
方法:
// 在控制器顶部添加如下这个use语句
use App\Services\RssFeed;
// 同时在控制器中添加如下这个方法
public function rss(RssFeed $feed)
{
$rss = $feed->getRSS();
return response($rss)
->header('Content-type', 'application/rss+xml');
}
好了,现在去浏览器中访问 http://blog57.test/rss
你将会看到想要看到的东西。
如果想要在页面中显示 RSS 订阅链接,编辑 page-footer.blade.php
视图文件内容如下:
<hr>
<footer>
<div class="container">
<div class="row">
<div class="col-lg-8 col-md-10 mx-auto">
<ul class="list-inline text-center">
<li class="list-inline-item">
<a href="#">
<span class="fa-stack fa-lg">
<i class="fas fa-circle fa-stack-2x"></i>
<i class="fab fa-twitter fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
<li class="list-inline-item">
<a href="#">
<span class="fa-stack fa-lg">
<i class="fas fa-circle fa-stack-2x"></i>
<i class="fab fa-facebook-f fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
<li class="list-inline-item">
<a href="#">
<span class="fa-stack fa-lg">
<i class="fas fa-circle fa-stack-2x"></i>
<i class="fab fa-github fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
<li class="list-inline-item">
<a href="{{ url('rss') }}" data-toggle="tooltip" title="RSS feed">
<span class="fa-stack fa-lg">
<i class="fa fa-circle fa-stack-2x"></i>
<i class="fa fa-rss fa-stack-1x fa-inverse"></i>
</span>
</a>
</li>
</ul>
<p class="copyright text-muted">Copyright © {{ config('blog.author') }} 2018</p>
</div>
</div>
</div>
</footer>
这样在博客底部会显示如下图标:
5、生成站点地图
最后,我们为博客生成站点地图以利于SEO。
实现思路和 RSS 订阅一样:
创建 SiteMap 服务
在 app/Services
目录下新建一个 SiteMap.php
,编辑其内容如下:
<?php
namespace App\Services;
use App\Models\Post;
use Carbon\Carbon;
use Illuminate\Support\Facades\Cache;
class SiteMap
{
/**
* Return the content of the Site Map
*/
public function getSiteMap()
{
if (Cache::has('site-map')) {
return Cache::get('site-map');
}
$siteMap = $this->buildSiteMap();
Cache::add('site-map', $siteMap, 120);
return $siteMap;
}
/**
* Build the Site Map
*/
protected function buildSiteMap()
{
$postsInfo = $this->getPostsInfo();
$dates = array_values($postsInfo);
sort($dates);
$lastmod = last($dates);
$url = trim(url('/'), '/') . '/';
$xml = [];
$xml[] = '<?xml version="1.0" encoding="UTF-8"?' . '>';
$xml[] = '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
$xml[] = ' <url>';
$xml[] = " <loc>$url</loc>";
$xml[] = " <lastmod>$lastmod</lastmod>";
$xml[] = ' <changefreq>daily</changefreq>';
$xml[] = ' <priority>0.8</priority>';
$xml[] = ' </url>';
foreach ($postsInfo as $slug => $lastmod) {
$xml[] = ' <url>';
$xml[] = " <loc>{$url}blog/$slug</loc>";
$xml[] = " <lastmod>$lastmod</lastmod>";
$xml[] = " </url>";
}
$xml[] = '</urlset>';
return join("\n", $xml);
}
/**
* Return all the posts as $url => $date
*/
protected function getPostsInfo()
{
return Post::where('published_at', '<=', Carbon::now())
->where('is_draft', 0)
->orderBy('published_at', 'desc')
->pluck('updated_at', 'slug')
->all();
}
}
添加路由和控制器方法
首先在路由文件 routes/web.php
中新增一个路由:
// 在如下这行之后
Route::get('rss', 'BlogController@rss');
// 添加新的路由
Route::get('sitemap.xml', 'BlogController@siteMap');
然后编辑控制器 BlogController
,新增 siteMap
方法:
// 在控制器顶部添加如下use语句
use App\Services\SiteMap;
// 同时在控制器中新增这个方法
public function siteMap(SiteMap $siteMap)
{
$map = $siteMap->getSiteMap();
return response($map)
->header('Content-type', 'text/xml');
}
到浏览器访问 http://blog57.test/sitemap.xml
,页面显示如下(以下是部分截图):
至此,我们的博客系列告一段落,你已经构建起一个完整的博客应用,并且在此过程中相信你也学到了很多 Laravel 技能,但愿这个项目能作为大家学习 Laravel 框架的入门项目,并在此基础上,初步掌握 Laravel 框架,也希望大家在以后的进阶之路上越走越远,越走越好!
14 Comments
现在好像是没有免费计划了?
等7文档翻译完了继续入门和精通系列
这个Rss 订阅是个什么东西?订阅服务不应该是那种类似购买vip功能的吗?哈,有点懵
哈哈 搜索一下就知道了 年轻人可能确实不太懂 上一个互联网时代的东西