服务器配置比较低,运行 WordPress 越来越吃力了,上个月把站点转移到 Typecho 了,为了让 Typecho 变得更为好用,进行了若干改造。
登录
针对登录写了一个 Cloudflare Turnstile 的插件 typecho-plugin-turnstile
为什么选择 Turnstile 而不是 Google reCAPTCHA 呢?因为 Turnstile 不像 reCAPTCHA 那样恶心人,动不动弹一堆图片让识别。
Turnstile 仅需一个简单的免费代码片段,即可向网站访问者提供零挫败感、无 CAPTCHA 的 Web 体验。此外,Turnstile 可以阻止滥用并确认访问者的真实性,但不会有任何 CAPTCHA 给用户造成的数据隐私担忧或糟糕体验。
启用插件之后,配置好 Site Key
和 Secret Key
就可以在登录的时候显示 Turnstile 的验证模块了。
搜索
Typecho 的搜索功能不太好用,实现即时搜索比较麻烦。要是能集成 Algolia 就好了。
要集成 Algolia 需要进行两部分工作,第一部分是数据的提交,即将数据结构化地提交到 Algolia。第二部分就是在主题中集成 Algolia 的搜索:InstantSearch.js 或者 Autocomplete。
数据提交
Typecho 没有原生的 RESTful API 也不像 WordPress 内置 Cron 功能。考虑到部署等原因,用 Rust 实现了一个将 Tyepcho 的文章同步到 Algolia 的应用:typecho-algolia。填写好配置,运行程序就可以建立 Algolia 的 index。
要想及时提交数据,可以通过 Cron
定时运行程序。
*/5 * * * * cd /path/to/the/app && ./sync > /dev/null
搜索实现
Instant Search
const search = instantsearch({
indexName: 'typecho_posts',
searchClient,
insights: true,
searchFunction(helper) {
const $hits = $('#hits');
const $pagination = $('#pagination');
if (helper.state.query === '') {
$hits.empty();
$pagination.empty();
} else {
$hits.show();
$pagination.show();
helper.search();
}
},
});
search.addWidgets([
searchBox({
container: '#searchbox',
}),
hits({
container: '#hits',
templates: {
item: (hit, { html, components }) => html`
<a href="/${hit.slug}.html" style="text-decoration: none">
<h1>${components.Highlight({ hit, highlightedTagName: 'mark', attribute: 'title' })}</h1>
<p>${components.Snippet({ hit, highlightedTagName: 'mark', attribute: 'text' })}</p>
</a>
`,
},
}),
configure({
hitsPerPage: 5,
attributesToSnippet: ['text:25'],
}),
pagination({
container: '#pagination',
}),
]);
search.start();
Autocomplete
autocomplete({
container: '#search',
placeholder: '请输入关键字',
insights: true,
getSources({ query }) {
return [
{
sourceId: 'post',
getItems() {
return getAlgoliaResults({
searchClient,
queries: [
{
indexName: 'typecho_posts',
query,
params: {
hitsPerPage: 5,
attributesToSnippet: ['title:10', 'text:35'],
snippetEllipsisText: '…',
},
},
],
});
},
templates: {
item({ item, components, html }) {
return html`
<a style="text-decoration: none" title="${item.title}" href="/${item.slug}.html">
<div class="aa-ItemWrapper">
<div class="aa-ItemContent">
<div class="aa-ItemContentBody">
<div class="aa-ItemContentTitle">
${components.Highlight({
hit: item,
attribute: 'title',
})}
</div>
<div class="aa-ItemContentDescription">
${components.Snippet({
hit: item,
attribute: 'text',
})}
</div>
</div>
</div>
</div>
</a>
`;
},
},
},
];
},
});
效果
404 页面
头部弹窗搜索
一些探索
获取所有分类
$this->category
和 $this->categories
获取的分类数据跟当前页面是强关联的,要想获取数据库中的所有分类,可以通过以下方式。
<?php $db = Typecho_Db::get(); ?>
<?php $categories = $db->fetchAll($db->select()->from('table.metas')->where('type = ?', 'category')) ?>
未完待续~