Skip to content

Commit fa4319d

Browse files
mobeicanyuezkqiang
authored andcommitted
✨ umami 插件挂载统计数据
1 parent c4f7ac7 commit fa4319d

File tree

5 files changed

+170
-27
lines changed

5 files changed

+170
-27
lines changed

_config.yml

+32-19
Original file line numberDiff line numberDiff line change
@@ -260,21 +260,6 @@ web_analytics:
260260
google:
261261
measurement_id:
262262

263-
# Umami Analytics,src 和 data-website-id 是必填项,其他可选
264-
# Umami Analytics, src and data-website-id are required, others are optional
265-
umami:
266-
# umami js 文件地址,需要在 umami 后台创建站点后获取
267-
# umami js file url, get after create website in umami
268-
src:
269-
# umami 的 website id,需要在 umami 后台创建站点后获取
270-
# umami website id, get after create website in umami
271-
data_website_id:
272-
# 如果你只想跟踪器跟踪特定的域名,你可以将它们添加到你的跟踪器脚本中。这是一个逗号分隔的域名列表。
273-
# 如果你在一个分阶段、开发的环境中工作,这会很有帮助。避免统计 localhost。
274-
# If you want the tracker to only run on specific domains, you can add them to your tracker script. This is a comma delimited list of domain names.
275-
# Helps if you are working in a staging/development environment. Avoids tracking localhost.
276-
data_domains:
277-
278263
# 腾讯统计的 H5 App ID,开启高级功能才有cid
279264
# Tencent analytics, set APP ID
280265
# See: https://mta.qq.com/h5/manage/ctr_app_manage
@@ -307,6 +292,34 @@ web_analytics:
307292
# If true, ignore localhost & 127.0.0.1
308293
ignore_local: false
309294

295+
# Umami Analytics,仅支持自部署。如果要展示 PV UV 需要填写所有配置项,否则只填写 `src` 和 `website_id` 即可
296+
# Umami Analytics, only Self-host support. If you want to display PV UV need to set all config items, otherwise only set 'src' and 'website_id'
297+
# See: https://umami.is/docs/authentication
298+
umami:
299+
# umami js 文件地址,需要在 umami 后台创建站点后获取
300+
# umami js file url, get after create website in umami
301+
src:
302+
303+
# umami 的 website id,需要在 umami 后台创建站点后获取
304+
# umami website id, get after create website in umami
305+
website_id:
306+
307+
# 如果你只想统计特定的域名可以填入此字段,多个域名通过逗号分隔,这可以避免统计 localhost。
308+
# If you only want to tracker to specific domains you can fill in this field, multiple domain names are separated by commas, which can avoid tracker localhost
309+
domains:
310+
311+
# 用于统计 PV UV 的开始时间,格式为 "YYYY-MM-DD"
312+
# statistics on the start time, the format is "YYYY-MM-DD"
313+
start_time: 2024-01-01
314+
315+
# 新建一个 umami viewOnly 用户,然后通过 login api 获取该用户 token
316+
# create an umami viewOnly user, and then get user token through the login api
317+
token:
318+
319+
# 填写 umami 部署的服务器地址,如 "https://umami.example.com"
320+
# server url of umami deployment, such as "https://umami.example.com"
321+
api_server:
322+
310323
# Canonical 用于向 Google 搜索指定规范网址,开启前确保 hexo _config.yml 中配置 `url: http://yourdomain.com`
311324
# Canonical, to specify a canonical URL for Google Search, need to set up `url: http://yourdomain.com` in hexo _config.yml
312325
# See: https://support.google.com/webmasters/answer/139066
@@ -453,9 +466,9 @@ footer:
453466
statistics:
454467
enable: false
455468

456-
# 统计数据来源,使用 leancloud 需要设置 `web_analytics: leancloud` 中的参数;使用 busuanzi 不需要额外设置,但是有时不稳定,另外本地运行时 busuanzi 显示统计数据很大属于正常现象,部署后会正常
457-
# Data source. If use leancloud, you need to set the parameter in `web_analytics: leancloud`
458-
# Options: busuanzi | leancloud
469+
# 统计数据来源,使用 leancloud, umami 需要设置 `web_analytics` 中对应的参数;使用 busuanzi 不需要额外设置,但是有时不稳定,另外本地运行时 busuanzi 显示统计数据很大属于正常现象,部署后会正常
470+
# Data source. If use leancloud, umami, you need to set the parameter in `web_analytics`
471+
# Options: busuanzi | leancloud | umami
459472
source: "busuanzi"
460473

461474
# 国内大陆服务器的备案信息
@@ -598,7 +611,7 @@ post:
598611
enable: false
599612
# 统计数据来源
600613
# Data Source
601-
# Options: busuanzi | leancloud
614+
# Options: busuanzi | leancloud | umami
602615
source: "busuanzi"
603616

604617
# 在文章开头显示文章更新时间,该时间默认是 md 文件更新时间,可通过 front-matter 中 `updated` 手动指定(和 date 一样格式)

layout/_partials/footer/statistics.ejs

+20-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<div class="statistics">
2-
<% var pv_texts = (theme.footer.statistics.pv_format || __('footer.pv')).split('{}') %>
3-
<% var uv_texts = (theme.footer.statistics.uv_format || __('footer.uv')).split('{}') %>
2+
<% let pv_texts = (theme.footer.statistics.pv_format || __('footer.pv')).split('{}') %>
3+
<% let uv_texts = (theme.footer.statistics.uv_format || __('footer.uv')).split('{}') %>
44

55
<% if (theme.footer.statistics.source === 'leancloud') { %>
66
<% if (pv_texts.length >= 2) { %>
@@ -35,5 +35,23 @@
3535
</span>
3636
<% } %>
3737
<% import_js(theme.static_prefix.busuanzi, 'busuanzi.pure.mini.js', 'defer') %>
38+
39+
<% } else if (theme.footer.statistics.source === 'umami') { %>
40+
<% if (pv_texts.length >= 2) { %>
41+
<span id="umami-site-pv-container" style="display: none">
42+
<%- pv_texts[0] %>
43+
<span id="umami-site-pv"></span>
44+
<%- pv_texts[1] %>
45+
</span>
46+
<% } %>
47+
<% if (uv_texts.length >= 2) { %>
48+
<span id="umami-site-uv-container" style="display: none">
49+
<%- uv_texts[0] %>
50+
<span id="umami-site-uv"></span>
51+
<%- uv_texts[1] %>
52+
</span>
53+
<% } %>
54+
<% import_js(theme.static_prefix.internal_js, 'umami-view.js', 'defer') %>
3855
<% } %>
56+
3957
</div>

layout/_partials/plugins/analytics.ejs

+11-6
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,17 @@
3131
</script>
3232
<% } %>
3333
34-
<% if(theme.web_analytics.umami && theme.web_analytics.umami.src && theme.web_analytics.umami.data_website_id) { %>
35-
<!-- Umami Analytics -->
36-
<script async defer src="<%= theme.web_analytics.umami.src %>" data-website-id="<%= theme.web_analytics.umami.data_website_id %>"
37-
<% if (theme.web_analytics.umami.data_domains) { %> data-domains="<%= theme.web_analytics.umami.data_domains %>" <% } %>
38-
<% if (theme.web_analytics.follow_dnt) { %> data-do-not-track="<%= theme.web_analytics.follow_dnt %>" <% } %>
39-
></script>
34+
<% if(theme.web_analytics.umami && theme.web_analytics.umami.src && theme.web_analytics.umami.website_id) { %>
35+
<script async>
36+
if (!Fluid.ctx.dnt) {
37+
let umami = document.createElement('script');
38+
umami.async = true;
39+
umami.src = "<%= theme.web_analytics.umami.src %>";
40+
umami.setAttribute("data-website-id", "<%= theme.web_analytics.umami.website_id %>");
41+
umami.setAttribute("data-domains", "<%= theme.web_analytics.umami.domains %>");
42+
document.head.appendChild(umami);
43+
}
44+
</script>
4045
<% } %>
4146
4247
<% if(theme.web_analytics.tencent && theme.web_analytics.tencent.sid && theme.web_analytics.tencent.cid) { %>

layout/_partials/post/meta-top.ejs

+8
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,20 @@
5151
<%- views_texts[0] %><span id="leancloud-page-views"></span><%- views_texts[1] %>
5252
</span>
5353
<% import_js(theme.static_prefix.internal_js, 'leancloud.js', 'defer') %>
54+
5455
<% } else if (theme.post.meta.views.source === 'busuanzi') { %>
5556
<span id="busuanzi_container_page_pv" style="display: none">
5657
<i class="iconfont icon-eye" aria-hidden="true"></i>
5758
<%- views_texts[0] %><span id="busuanzi_value_page_pv"></span><%- views_texts[1] %>
5859
</span>
5960
<% import_js(theme.static_prefix.busuanzi, 'busuanzi.pure.mini.js', 'defer') %>
61+
62+
<% } else if (theme.post.meta.views.source === 'umami') { %>
63+
<span id="umami-page-views-container" class="post-meta" style="display: none">
64+
<i class="iconfont icon-eye" aria-hidden="true"></i>
65+
<%- views_texts[0] %><span id="umami-page-views"></span><%- views_texts[1] %>
66+
</span>
67+
<% import_js(theme.static_prefix.internal_js, 'umami-view.js', 'defer') %>
6068
<% } %>
6169
<% } %>
6270
</div>

source/js/umami-view.js

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// 从配置文件中获取 umami 的配置
2+
const website_id = CONFIG.web_analytics.umami.website_id;
3+
// 拼接请求地址
4+
const request_url = `${CONFIG.web_analytics.umami.api_server}/websites/${website_id}/stats`;
5+
6+
const start_time = new Date(CONFIG.web_analytics.umami.start_time).getTime();
7+
const end_time = new Date().getTime();
8+
const token = CONFIG.web_analytics.umami.token;
9+
10+
// 检查配置是否为空
11+
if (!website_id) {
12+
throw new Error("Umami website_id is empty");
13+
}
14+
if (!request_url) {
15+
throw new Error("Umami request_url is empty");
16+
}
17+
if (!start_time) {
18+
throw new Error("Umami start_time is empty");
19+
}
20+
if (!token) {
21+
throw new Error("Umami token is empty");
22+
}
23+
24+
// 构造请求参数
25+
const params = new URLSearchParams({
26+
startAt: start_time,
27+
endAt: end_time,
28+
});
29+
// 构造请求头
30+
const request_header = {
31+
method: "GET",
32+
headers: {
33+
"Content-Type": "application/json",
34+
"x-umami-api-key": "oZKCH3msvqt10VlXKwoJvHclmaS4bVx0",
35+
},
36+
};
37+
38+
// 获取站点统计数据
39+
async function siteStats() {
40+
try {
41+
const response = await fetch(`${request_url}?${params}`, request_header);
42+
const data = await response.json();
43+
const uniqueVisitors = data.uniques.value; // 获取独立访客数
44+
const pageViews = data.pageviews.value; // 获取页面浏览量
45+
46+
let pvCtn = document.querySelector("#umami-site-pv-container");
47+
if (pvCtn) {
48+
let ele = document.querySelector("#umami-site-pv");
49+
if (ele) {
50+
ele.textContent = pageViews; // 设置页面浏览量
51+
pvCtn.style.display = "inline"; // 将元素显示出来
52+
}
53+
}
54+
55+
let uvCtn = document.querySelector("#umami-site-uv-container");
56+
if (uvCtn) {
57+
let ele = document.querySelector("#umami-site-uv");
58+
if (ele) {
59+
ele.textContent = uniqueVisitors;
60+
uvCtn.style.display = "inline";
61+
}
62+
}
63+
} catch (error) {
64+
console.error(error);
65+
return "-1";
66+
}
67+
}
68+
69+
// 获取页面浏览量
70+
async function pageStats(path) {
71+
try {
72+
const response = await fetch(`${request_url}?${params}&url=${path}`, request_header);
73+
const data = await response.json();
74+
const pageViews = data.pageviews.value;
75+
76+
let viewCtn = document.querySelector("#umami-page-views-container");
77+
if (viewCtn) {
78+
let ele = document.querySelector("#umami-page-views");
79+
if (ele) {
80+
ele.textContent = pageViews;
81+
viewCtn.style.display = "inline";
82+
}
83+
}
84+
} catch (error) {
85+
console.error(error);
86+
return "-1";
87+
}
88+
}
89+
90+
siteStats();
91+
92+
// 获取页面容器
93+
let viewCtn = document.querySelector("#umami-page-views-container");
94+
// 如果页面容器存在,则获取页面浏览量
95+
if (viewCtn) {
96+
let path = window.location.pathname;
97+
let target = decodeURI(path.replace(/\/*(index.html)?$/, "/"));
98+
pageStats(target);
99+
}

0 commit comments

Comments
 (0)