前言 初次看见webring 之前闲着没事干逛开往issues的时候看到了这么个站点:
当时这个按钮引起了我的注意:
这是个啥东西?友链接力?还是什么?于是我写了个邮件问问这位站长
这位站长给我的回复如下:
果然是类似于友链接力的,而且开往正是受到这个webring的启发
当时还以为那站点能加入的原因是简约,而且加入这个成员大多都是foreign,所以我就没怎么去了解
再次看见 后面闲着没事干,又去逛逛开往这波开往上大分 ,来到了他的第二人生 这个站点 然后我就看到了这篇文章:
再加上我在那站点末尾看见了IndieWeb Webring的标志
才知道Hexo的博客原来也能加入IndieWeb webring
而加入IndieWeb webring的前提条件是:站点必须适配IndieWeb
前提条件 必须要有独立网站和个人域名,没错,就是独立网站和个人域名,其实刚开始看的时候我还以为我看错了,后来才发现我没看错,那官方文档就是这么写的
教程开始! 对IndieWeb的适配分为四个部分:IndieAuth、RelMeAuth和Microformats
IndieAuth(必选)&& RelMeAuth(必选) 这个教程其实很简单,就是在你的Github链接和邮箱链接对应的元素添加rel="me"
的标签 并且去 https://indieauth.com/ 那边登录+获取IndieAuth代码放到head里面就行(后面那Web Sign-in form什么的不用添加) 也因此我才把这两个合并到一起
添加标签和代码:
修改[Blogroot]\themes\solitude\layout\includes\widgets\aside\asideInfoCard.pug
,转到最后一行
1 2 3 4 5 6 7 .card-info-social-icons.is-center each value, label in theme.aside.my_card.information || {} - var array = value.split('||') - a.social-icon.u-url(class=array[2] href=url_for(trim(array[0])), title=label) + a.social-icon.u-url(class=array[2] href=url_for(trim(array[0])), title=label, rel="me") i.solitude(class=array[1])
然后修改主题目录下的
_config.yml
或者博客目录下的
_config.solitude.yml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 aside: my_card: information: Github: https://github.com/SinzMise || fab fa-github Email: mailto:email@sinzmise.top || fa fa-envelope ... extends: head: - <link rel="authorization_endpoint" href="https://indieauth.com/auth"> - <link rel="token_endpoint" href="https://tokens.indieauth.com/token">
懒得写了,反正rel-'me'
按照我上面说的来添加就可以 如果你想提前支持IndieAuth,就直接在</head>
之前添加这两个就可以了:
1 2 <link rel ="authorization_endpoint" href ="https://indieauth.com/auth" > <link rel ="token_endpoint" href ="https://tokens.indieauth.com/token" >
然后去
https://indieauth.com/ 这边登录你的账号
如果你用的是静态博客,那么在去登录之前你必须要给博客push上去!要不然提示找不到rel=me标签!
划到最下面,在
Try It!
这个地方输入你的网址
然后点击Sign-In会询问你用Github登录还是用邮箱登录
随便选一个登录之后看到这个就说明成功了:
当然在此之前你可以去
https://indiewebify.me/validate-rel-me/ 那边检测
检测成功会提示这个:
最难的地方来了 因为这个会引入大量的class标签 如果是别的主题魔改还好,如果像solitude这种文章标题在Header里面就很难改,而且一不小心就识别错误 而如果是Redifine这种使用了Tailwind CSS就更难,因为这个会在页面中留下许多h-
开头的类名,导致部分 microformats 解析器解析出错误的数据这也是为什么我这么讨厌Tailwind CSS
因此目前只有Solitude的魔改教程,而且只有必要的class,其它主题或者非Hexo博客可以参考一下wiki:https://microformats.org/wiki/h-card https://microformats.org/wiki/h-entry
h-card(个人信息) 修改[Blogroot]\themes\solitude\layout\includes\widgets\aside\asideInfoCard.pug
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 - .card-widget.card-info + .card-widget.card-info.h-card .card-content .card-info-avatar.is-center .author-info__top-group .author-info__sayhi#author-info__sayhi(onclick="sco.changeWittyWord()") .avatar-img-group - img.avatar-img(alt=_p('aside.avatar'), src=theme.aside.my_card.author.img) + img.u-photo.avatar-img(alt=_p('aside.avatar'), src=theme.aside.my_card.author.img) if theme.aside.my_card.author.sticker .avatar-sticker img.avatar-sticker-img(src=theme.aside.my_card.author.sticker, alt=_p('aside.sticker')) .author-info__description_group .author-info__description!= theme.aside.my_card.content .author-info__bottom-group span.author-info__bottom-group-left - .author-info__name= config.author - .author-info__desc!= theme.aside.my_card.description + .author-info__name.p-name= config.author + .author-info__desc.p-note!= theme.aside.my_card.description .card-info-social-icons.is-center each value, label in theme.aside.my_card.information || {} - var array = value.split('||') - a.social-icon(class=array[2] href=url_for(trim(array[0])), title=label, rel="me") + a.social-icon.u-url(class=array[2] href=url_for(trim(array[0])), title=label, rel="me") i.solitude(class=array[1])
修改完成后给博客push上去
然后去
https://indiewebify.me/validate-h-card/ 这边检测h-card的代码添加情况
如果识别到你设置的信息那就是成功了
h-entry(博客信息) 修改[Blogroot]\themes\solitude\layout\post.pug
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 extends includes/layout.pug block content main.layout#content-inner - #post + #post.h-entry + a.h-card.p-author(href=url_for("/") rel="author" style='display:none')= config.author + a.u-url.p-name(href=urlNoIndex() style='display:none')= page.title + time.dt-published(datetime=date_xml(page.date) style='display:none')= date_xml(page.date) + time.dt-updated(datetime=date_xml(page.updated) style='display:none')= date_xml(page.updated) + if page.categories.data.length > 0 + a.p-category(href=url_for('/' + page.categories.data[0].path) style='display:none')= page.categories.data[0].name if page.not_cover include includes/widgets/post/postInfo article.post-content.article-container if theme.post_ai.enable include includes/widgets/post/post-ai - != page.content + .e-content!= page.content
修改
[Blogroot]\themes\solitude\layout\includes\widgets\post\copyright.pug
,转到第
25
行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 each item in theme.post.share.list || [] case item when 'qq' - a.social-share-ico.icon-qq(href=`https://connect.qq.com/widget/shareqq/index.html?url=${encodedPath}&title=${encodedTitle}&desc=${encodedDescription}&summary=${encodedDescription}&site=${encodedTitle}&pics=${encodedIcon}` title=_p('post.share.qq')) + a.u-syndication.social-share-ico.icon-qq(href=`https://connect.qq.com/widget/shareqq/index.html?url=${encodedPath}&title=${encodedTitle}&desc=${encodedDescription}&summary=${encodedDescription}&site=${encodedTitle}&pics=${encodedIcon}` title=_p('post.share.qq')) i.solitude.fab.fa-qq when 'weibo' - a.social-share-ico.icon-weibo(href=`http://service.weibo.com/share/share.php?url=${encodedPath}&title=${encodedTitle}&pic=${encodedIcon}` title=_p('post.share.weibo')) + a.u-syndication.social-share-ico.icon-weibo(href=`http://service.weibo.com/share/share.php?url=${encodedPath}&title=${encodedTitle}&pic=${encodedIcon}` title=_p('post.share.weibo')) i.solitude.fab.fa-weibo when 'telegram' - a.social-share-ico.icon-telegram(href=`https://t.me/share/url?url=${encodedPath}&text=${encodedTitle}` title=_p('post.share.telegram')) + a.u-syndication.social-share-ico.icon-telegram(href=`https://t.me/share/url?url=${encodedPath}&text=${encodedTitle}` title=_p('post.share.telegram')) i.solitude.fab.fa-telegram when 'whatsapp' - a.social-share-ico.icon-whatsapp(href=`https://api.whatsapp.com/send?text=${encodedTitle} ${encodedPath}` title=_p('post.share.whatsapp')) + a.u-syndication.social-share-ico.icon-whatsapp(href=`https://api.whatsapp.com/send?text=${encodedTitle} ${encodedPath}` title=_p('post.share.whatsapp')) i.solitude.fab.fa-whatsapp when 'linkedin' - a.social-share-ico.icon-linkedin(href=`https://www.linkedin.com/shareArticle?mini=true&url=${encodedPath}&title=${encodedTitle}&summary=${encodedDescription}&source=${encodedTitle}` title=_p('post.share.linkedin')) + a.u-syndication.social-share-ico.icon-linkedin(href=`https://www.linkedin.com/shareArticle?mini=true&url=${encodedPath}&title=${encodedTitle}&summary=${encodedDescription}&source=${encodedTitle}` title=_p('post.share.linkedin')) i.solitude.fab.fa-linkedin when 'facebook' - a.social-share-ico.icon-facebook(href=`https://www.facebook.com/sharer/sharer.php?u=${encodedPath}` title=_p('post.share.facebook')) + a.u-syndication.social-share-ico.icon-facebook(href=`https://www.facebook.com/sharer/sharer.php?u=${encodedPath}` title=_p('post.share.facebook')) i.solitude.fab.fa-facebook when 'twitter' - a.social-share-ico.icon-twitter(href=`https://twitter.com/intent/tweet?url=${encodedPath}&text=${encodedTitle}` title=_p('post.share.twitter')) + a.u-syndication.social-share-ico.icon-twitter(href=`https://twitter.com/intent/tweet?url=${encodedPath}&text=${encodedTitle}` title=_p('post.share.twitter')) i.solitude.fab.fa-twitter
两个步骤修改完成之后给博客push上去
然后去
https://indiewebify.me/validate-h-entry/ 这边检测h-card的代码添加情况
提示:Success!We found the following post
h-entry
on your site就成功了
可选添加 如果你做完前面这三个步骤,恭喜你,你的站点已经适配IndieWeb了 适配完IndieWeb之后就可以选择加入IndieWeb webring或者添加WebMention(也就是我那评论下面的网络回响)
WebMention (可选) 官方介绍 (翻译后):
Webmention 是一种用于跨 Web 对话和交互的开放 Web 标准(W3C 推荐标准),是一个强大的构建块,用于不断增长的分布式网络,该网络包含跨 Web 的点对点评论 、点赞 、转发 和其他响应 。
登录WebMention,获取两段link 前往 https://webmention.io/ 登录你的网站 登录之后点击最上方的Setting,按照图片的来 然后点击最上方的Sites,新增一个网站,新增完成之后点击你新增站点的“Get Setup Code”获取代码 把这个地方的<link>
代码也给复制到</head>
前面
然后,去 https://webmention.rocks/receive/2 检验你的代码是否安装成功 如果提示这个就代表成功了:
添加 网络回响 功能 这个获取Mention的js代码是基于别人的方案而改来 在此基础上适配了pjax
新增[Blogroot]\themes\solitude\layout\includes\widgets\third-party\webmention.pug
,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 hr #post-comment .comment-head .comment-headline i.fas.fa-comments.fa-fw span= ' 网络回响' .comment-wrap p!= '你有对这篇文章写<a href="https://indieweb.org/responses" target="_blank">回应</a>吗? 你可以在这里提交你的文章网址(文章需要包含这篇文章的地址,点击这里了解 <a href="https://indieweb.org/Webmention" target="_blank">Webmention</a>):' br form.form-webmention(action=url_for(theme.webmention.endpoint) method="post" target="_blank") input#form-webmention-source(name="source" placeholder='你的文章网址' required="" type="url") input(name="target" type="hidden" value=urlNoIndex()) input.form-webmention-btn(type="submit" value="Send Webmention") .webmention-timeline
修改
[Blogroot]\themes\solitude\layout\post.pug
给这个功能加在comment下面
1 2 3 4 5 if page.comment - var comment_js = true include includes/widgets/third-party/comments/comment + if theme.webmention.enable && page.webmention !== false + !=partial('includes/widgets/third-party/webmention', {}, {cache: true})
引入css代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 .wm-avatar { border-radius : 50% ; margin : 0 ; } .webmention-avatars .avatar-wrapper { margin-right : -8px ; } a .avatar-wrapper { display : inline-block; width : 50px ; height : 50px ; position : relative; } .replies { margin : 0 ; padding : 0 ; } .reply { list-style : none; display : flex; position : relative; padding : 0 ; align-items : flex-start; margin-top : 0.6rem ; } .reply p { margin : 0 ; } .reply .text { margin-left : 1rem ; font-size : 14px ; } .reply-author-name { font-weight : 500 ; } .form-webmention { display : flex; } .form-webmention-btn { flex : 0 0 auto; margin-left : 12px ; align-items : baseline; border : 0 ; cursor : pointer; } .form-webmention-btn ,a .retweetBtn { display : flex; justify-content : center; padding : 0 12px ; background : var (--anzhiyu-reverse); color : var (--efu-secondbg); } #form-webmention-source { flex : 1 0 auto; border : 1px solid; padding : 0 8px ; background : var (--efu-secondbg); border : var (--style-border-always); } #form-webmention-source ,.form-webmention-btn ,a .retweetBtn { height : 36px ; line-height : 36px ; font-size : 16px ; border-radius : 8px ; }
引入js代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 function webmention ( ) { const url = window .location .href ; const webmentionBaseUrl = "https://webmention.io" fetch (webmentionBaseUrl + "/api/mentions.jf2?target=" + encodeURIComponent (url)) .then (function (response ) { console .log ('sucess ' + webmentionBaseUrl + "/api/mentions.jf2?target=" + url); return response.json (); }) .then (function (data ) { var html = '' ; const distinctMentions = [ ...new Map (data.children .map ((item ) => [item.author .url , item])).values ()].sort ((a, b ) => new Date (a['wm-received' ]) - new Date (b['wm-received' ])); html += `<div><p>` ; if (distinctMentions.length > 0 ) { html += `已经有 ${distinctMentions.length} 朋友喜欢、分享或讨论这篇文章:</p>` ; } html += `<div className="webmention-avatars">` ; distinctMentions.forEach (function (reply ) { html += `<a class="avatar-wrapper" href=${reply.author.url} key=${reply.author.name} ><image class="wm-avatar" loading="lazy" src=${reply.author.photo != "" ? reply.author.photo: "/img/avatar.png" } data-nimg="fill" sizes="(max-width: 768px) 100vw,(max-width: 1200px) 50vw, 33vw"/></a>` ; }); html += `</div>` ; const replies = distinctMentions.filter ( (mention ) => ('in-reply-to' in mention || 'mention-of' in mention)&& 'content' in mention ); if (replies && replies.length ) { html += `<div class="webmention-replies">` ; html += `</br><h3>引用或评论(${replies.length} )</h3>` ; html += `<ul class="replies">` ; replies.forEach (function (reply ){ html += `<li class="reply" key=${reply["wm-id" ]} >` ; html += `<div>` ; html += `<a class="avatar-wrapper" href=${reply.author.url} key=${reply.author.name} ><image class="wm-avatar" loading="lazy" src=${reply.author.photo != "" ? reply.author.photo: "/img/avatar.png" } alt=${reply.author.name} data-nimg="fill" sizes="(max-width: 768px) 100vw,(max-width: 1200px) 50vw, 33vw"/></a>` ; html += `</div>` ; html += `<div class="text">` ; html += `<p class="reply-author-name"><a href=${reply.url} target="_blank">${reply.author.name} </a></p>` ; html += `<p class="reply-content">${reply.content.text.slice(0 , 200 )} </p>` ; html += `</div>` ; html += `</li>` ; }); html += `</ul>` ; html += `</div>` ; } document .querySelector ('div.webmention-timeline' ).innerHTML = html; }) .catch (function (ex ) { console .error ('fetch webmention error' + ex); }); } window .WebMentionLoad = function ( ) { if (document .querySelector ('.webmention-timeline' )) webmention (); }; window .addEventListener ("load" , WebMentionLoad )document .addEventListener ("pjax:complete" , WebMentionLoad )
如果还不知道怎么引入js和css代码的话看这个:
https://blog.leonus.cn/2022/custom.html https://akilar.top/posts/ebf20e02/#%E9%AD%94%E6%94%B9%E6%A0%B7%E5%BC%8F%E5%BC%95%E5%85%A5
Butterfly主题的inject,对应的是Solitude主题的extends,别看错!
在
_config.solitude.yml
中的 新增以下配置项
1 2 3 webmention: enable: true endpoint: https://webmention.io/blog.storical.space/webmention
新增[Blogroot]\themes\butterfly\layout\includes\third-party\webmention.pug
,内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 hr #post-comment .comment-head .comment-headline i.fas.fa-comments.fa-fw span= ' 网络回响' .comment-wrap p!= '你有对这篇文章写<a href="https://indieweb.org/responses" target="_blank">回应</a>吗? 你可以在这里提交你的文章网址(文章需要包含这篇文章的地址,点击这里了解 <a href="https://indieweb.org/Webmention" target="_blank">Webmention</a>):' br form.form-webmention(action=url_for(theme.webmention.endpoint) method="post" target="_blank") input#form-webmention-source(name="source" placeholder='你的文章网址' required="" type="url") input(name="target" type="hidden" value=urlNoIndex()) input.form-webmention-btn(type="submit" value="Send Webmention") .webmention-timeline
修改
[Blogroot]\themes\solitude\layout\post.pug
给这个功能加在comment下面
1 2 3 4 5 6 if page.comments !== false && theme.comments && theme.comments.use - var commentsJsLoad = true !=partial('includes/third-party/comments/index', {}, {cache: true}) + if theme.webmention.enable && page.webmention !== false + !=partial('includes/third-party/webmention', {}, {cache: true})
引入css代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 .wm-avatar { border-radius : 50% ; margin : 0 ; } .webmention-avatars .avatar-wrapper { margin-right : -8px ; } a .avatar-wrapper { display : inline-block; width : 50px ; height : 50px ; position : relative; } .replies { margin : 0 ; padding : 0 ; } .reply { list-style : none; display : flex; position : relative; padding : 0 ; align-items : flex-start; margin-top : 0.6rem ; } .reply p { margin : 0 ; } .reply .text { margin-left : 1rem ; font-size : 14px ; } .reply-author-name { font-weight : 500 ; } .form-webmention { display : flex; } .form-webmention-btn { flex : 0 0 auto; margin-left : 12px ; align-items : baseline; border : 0 ; cursor : pointer; } .form-webmention-btn ,a .retweetBtn { display : flex; justify-content : center; padding : 0 12px ; background : var (--anzhiyu-reverse); color : var (--efu-secondbg); } #form-webmention-source { flex : 1 0 auto; border : 1px solid; padding : 0 8px ; background : var (--efu-secondbg); border : var (--style-border-always); } #form-webmention-source ,.form-webmention-btn ,a .retweetBtn { height : 36px ; line-height : 36px ; font-size : 16px ; border-radius : 8px ; }
引入js代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 function webmention ( ) { const url = window .location .href ; const webmentionBaseUrl = "https://webmention.io" fetch (webmentionBaseUrl + "/api/mentions.jf2?target=" + encodeURIComponent (url)) .then (function (response ) { console .log ('sucess ' + webmentionBaseUrl + "/api/mentions.jf2?target=" + url); return response.json (); }) .then (function (data ) { var html = '' ; const distinctMentions = [ ...new Map (data.children .map ((item ) => [item.author .url , item])).values ()].sort ((a, b ) => new Date (a['wm-received' ]) - new Date (b['wm-received' ])); html += `<div><p>` ; if (distinctMentions.length > 0 ) { html += `已经有 ${distinctMentions.length} 朋友喜欢、分享或讨论这篇文章:</p>` ; } html += `<div className="webmention-avatars">` ; distinctMentions.forEach (function (reply ) { html += `<a class="avatar-wrapper" href=${reply.author.url} key=${reply.author.name} ><image class="wm-avatar" loading="lazy" src=${reply.author.photo != "" ? reply.author.photo: "/img/avatar.png" } data-nimg="fill" sizes="(max-width: 768px) 100vw,(max-width: 1200px) 50vw, 33vw"/></a>` ; }); html += `</div>` ; const replies = distinctMentions.filter ( (mention ) => ('in-reply-to' in mention || 'mention-of' in mention)&& 'content' in mention ); if (replies && replies.length ) { html += `<div class="webmention-replies">` ; html += `</br><h3>引用或评论(${replies.length} )</h3>` ; html += `<ul class="replies">` ; replies.forEach (function (reply ){ html += `<li class="reply" key=${reply["wm-id" ]} >` ; html += `<div>` ; html += `<a class="avatar-wrapper" href=${reply.author.url} key=${reply.author.name} ><image class="wm-avatar" loading="lazy" src=${reply.author.photo != "" ? reply.author.photo: "/img/avatar.png" } alt=${reply.author.name} data-nimg="fill" sizes="(max-width: 768px) 100vw,(max-width: 1200px) 50vw, 33vw"/></a>` ; html += `</div>` ; html += `<div class="text">` ; html += `<p class="reply-author-name"><a href=${reply.url} target="_blank">${reply.author.name} </a></p>` ; html += `<p class="reply-content">${reply.content.text.slice(0 , 200 )} </p>` ; html += `</div>` ; html += `</li>` ; }); html += `</ul>` ; html += `</div>` ; } document .querySelector ('div.webmention-timeline' ).innerHTML = html; }) .catch (function (ex ) { console .error ('fetch webmention error' + ex); }); } window .WebMentionLoad = function ( ) { if (document .querySelector ('.webmention-timeline' )) webmention (); }; window .addEventListener ("load" , WebMentionLoad )document .addEventListener ("pjax:complete" , WebMentionLoad )
如果还不知道怎么引入js和css代码的话看这个:
https://blog.leonus.cn/2022/custom.html https://akilar.top/posts/ebf20e02/#%E9%AD%94%E6%94%B9%E6%A0%B7%E5%BC%8F%E5%BC%95%E5%85%A5 在
_config.butterfly.yml
中的 新增以下配置项
1 2 3 webmention: enable: true endpoint: https://webmention.io/blog.storical.space/webmention
魔改完成之后在 https://webmention.rocks/receive/1 这边测试一下 登录之后输入你的文章链接点击Begin test 如果看见这个提示: 并且去你的测试文章这边看见你的数据: 那就代表成功了
好了,就到一段落,indieweb webring那个我懒得写了,写小记去了