推广 热搜: 行业  机械  设备    系统  教师  经纪    参数  蒸汽 

在WordPress站点中展示阅读量等流量分析数据(超详细实现)

   日期:2024-11-10     移动:http://yejunbin01.xhstdz.com/mobile/quote/65961.html

专业的流量统计系统能够相对真实地反应网站的访问情况。 这些数据可以在后台很好地进行分析统计,但有时我们希望在网站前端展示一些数据

在WordPress站点中展示阅读量等流量分析数据(超详细实现)

最常见的情景就是:展示页面的浏览量 这简单的操作当然也可以通过简单的计数器实现,但可能会造成重复统计(比如同一个用户点击10次

流量分析工具所提供的准确性是不可比拟的 因此这篇文章我们就来实现如何将流量分析数据搬到网站展示,做到

  1. 同步流量分析工具数据到网站前端
    • 显示页面的阅读量
  2. 不影响页面加载
    • 用户不会感知到同步任务进行
  3. 不频繁访问分析工具API
    • 减少网络资源、API次数消耗

为完成这些目标,需要一些前提准备

  1. 配置好带有数据访问API的流量分析工具
    • 如、(本文将以Umami为例
    • 这是我们的真实数据来源
  2. 配置好WordPress后台进程(Background Process)支持
    • 如Action-Scheduler(本文将以此为例
    • 这是我们非阻塞运行的基础

API访问频率

阅读量实时性并不强,我们无须(也不可能)每次页面访问都从远程分析工具获取数据 频繁访问很有可能会被禁止访问API(自建的相当于DDoS攻击自己😅) 在获取数据后,应该在短时间内缓存起来

WordPress中的跨请求缓存API是

处理缓存未命中

但如果缓存未命中怎么办?是立刻访问远程分析工具吗? 不可能,这样同步执行会使页面加载阻塞 特别是:如果你一次展示多篇文章,你需要等待它们全部完成才能加载出页面

因此我们必须在本地数据库也持久化存储阅读量 这个冗余数据是缓存未命中时的唯一可行数据来源

在WordPress中,我们可以使用存储它

与此同时,这也可作为数据过时的标志: 我们应该触发更新阅读量的后台进程 非阻塞地将第三方分析工具的数据同步到本地上

小结

的是用于页面获取数据的接口。它的数据来源是

  1. 内存缓存
    • 减少短期重复访问,减少服务器压力
  2. 本地数据库
    • 缓存未命中时的保底数据
  3. 远程分析工具
    • 数据更新的途径

它的职责是

  1. 读写本地数据
  2. 发出更新请求

注意组织文件结构,本文将文件夹作为根目录

在创建文件

编写类,它主要包含一些静态函数

 
getPageViews

本文实现需要依赖$post->ID作为唯一标识符 如果你希望实现任何页面的阅读量展示,你需要

  1. 使用的作为唯一标识符
  2. 使用自定义数据库表存储阅读量

需要做什么? 当访客来访时,需要展示阅读量,此时

  1. 我们需要获取目标地址的实例
    • 以获取url等信息
  2. 有缓存读缓存
  3. 无缓存读数据库
    1. (不阻塞执行)请求第三方流量分析API,更新记录
    2. 马上使用旧数据刷新缓存

前面提到了缓存过期是发出数据同步请求的标志,但我们不希望重复发起请求, 因此缓存未命中时需要马上再次写入缓存。

虽然数据是旧的,但不急。我们可以在数据同步时强制刷新它


大部分都好处理,异步请求比较麻烦,先卖个关子 同时我们还为阅读量定义了缓存键值和在数据库的meta键值

 

为了减少不必要的请求数,我们使用确保当前访问的是文章页面 否则文章大概率是被输出为概要、列表,并不存在真的访问,没必要更新

setPageViews

这个函数用于写入本地的数据存储,包括缓存和数据库 注意,它并不包含异步更新的过程,只是异步更新的结果需要借助它写入

 
Provider

好了,该想想怎么访问远程API了 因为大多为固定操作,我们实现为静态 但是更新数据来源的逻辑呢

不同的流量分析工具会提供不同的API,因此我们也需要为它们编写各自的处理逻辑 我们需要根据设置为注入一个恰当的数据来源实例,这里称为

先关注类中需要如何支持注入Provider

没使用任何框架,我只能纯手工注入 以下代码是额外增加内容,需要与上文合并

 

我们需要先设置使用的数据源,后续使用获取它

因为某些可能会很沉重,这里支持传入一个返回的 以实现懒加载,只有需要使用它的时候才会生成

接下来再看看需要怎么编写

不同的provider有不同的访问逻辑,但至少有没有些共性? 还真有

Provider负责组织后台任务,但每次请求更新都立刻组织一个后台任务还是很恐怖的。

比如:一个页面有100篇文章 如果我们需要为每篇文章组织一个任务 此时需要组织100个任务

虽然我们这里使用限制了只在文章页面发起更新请求(见上文) 但这里讨论的问题是更一般化的 我们编写的代码可不只是为了显示访问量一种数据而已

因为php无守护进程,每个后台任务其实需要通过写数据库进行任务信息持久化 因此组织100个后台任务,意味着访问数据库上百次

而组织任务这个过程,是同步的、阻塞的 用户会看着页面转十秒加载不出来

但说到底,有没有必要把它视为100个任务?不能批处理一下吗? 当然可以,而且这就是不同的一个共性。

在创建文件

编写类

 

pushUpdatePostViews

这是登记更新任务的逻辑 上文说了,我们不希望立刻生成后台任务,而是记录它

 

主要是请求API时的参数,比如:时间段?目标地址?国家?…… 这与具体数据源的实现有关,但总之,我们需要把这些可能用到的数据存到里

记录了本次请求中,所有需要请求阅读量更新的文章和相应参数 但我们如何把它加到后台任务

submitTasks()

submitTasks由子类负责给出任务提交的逻辑 父类只需要给出约束

 

没完,我们需要有人在最后调用这个函数,才能完成所有任务一次性提交 可以利用WordPress的hook

 

因为是WordPress最后一个hook,因此不用担心之后还会有新的任务提交请求

注意,WordPress hook的回调必须是函数

还记得的空缺位置吗? 它应该调用

 

注意:在上下文中就是

主要完成两件事

  1. 完成任务提交逻辑
  2. 封装处理参数

以下我以为例

在创建文件 编写类

 
  1. 获取阅读量必须提供页面的,因此我重写并按获取了它的
  2. 先检测了是否真有待提交任务数据,如有,提交
  • 具体提交逻辑见下文

万事俱备,只欠东风 我们只剩下后台任务需要解决了,但你先别急 这篇文章目前只到一半

本文将使用作为后台任务的驱动 但不管你是否使用它,后文的结构都可以给你一点灵感

基本上是WordPress中支持后台进程的唯一选择了 它的官方例子如下

 

这个例子将在每天午夜输出一个log

但这例子其实有个坑,的执行机制事实上跨越了2次php执行

  1. 第一次,制定任务
    1. 使用制定任务
    2. 此时hook无效
  2. 第二次,午夜时执行任务(可能由cron或其它机制触发
    1. 它从数据库中检测到预定的任务,生成hook
    2. 执行hook的逻辑

所以坑点就在于必须在执行任务时加入,在制定任务时加入是无效

而我们的目标,则是

  1. 把2次php执行的代码尽可能地透明化,封装起来
  2. 使用面向对象的思想处理任务,使其模块化

主要用于负责所有任务的提交和触发,我的实现主要针对,如果使用其它后台任务库,该类需要做对应修改。

在阅读前,建议先了解的基本操作

在创建文件 编写类

 

用于记录所有需要管理的任务名,它的作用只是将名字加入列表

submitTask

用于提交“保证任务触发时正常执行”所需的一切数据,包括

  1. 交给谁处理(给谁处理
  2. 执行处理的指引(怎么处理
  3. 需要处理的数据(处理什么

因此它需要传入3个参数

  1. : 承载任务处理逻辑的类名
    • 后文会详细介绍,它的基类是,包含一个方法
  2. : 承载任务处理的元数据
    • 比如任务时限?重试次数
    • 反正是与任务相关,但与任务执行主体无关
  3. : 任务执行所需的数据
    • 比如我们需要访问api,那可能就是api参数等等

因此可以写出这样的代码

 
  1. 使用提供的,将任务数据移交至其托管。
  2. 所有参数将被存储于数据库,当执行时取出
    • 有点像序列化
  3. 是类的静态变量,表示任务名
    • 因为与任务直接关联,因此任务名就存在它那了
  4. 防止完全重复任务
    1. 标记为唯一任务(第四个参数
    2. 计算参数的md5作为分组,用于识别重复任务

init

init需要在每次执行、所有调用结束后调用,它用于监听后台任务是否已触发,如果是,则分配到相应的处理函数

 

首先需要引入文件,然后对每个注册的任务名,都使用监听函数(这里实现为匿名函数)订阅它的

当事件触发时,这个函数将获得我们从中传入的3个参数

  1. : 任务处理逻辑的类名
    • 用于动态生成负责处理事件的handler对象
    • 调用它的方法
  2. : 承载任务处理的元数据
    • 将其转交给handler
  3. : 任务执行所需的数据
    • 将其转交给handler

当某个任务真正触发时,其对应的就会被触发,然后由监听函数转发至真正的执行逻辑

Task代表了一个任务,它包括: 任务名、任务提交逻辑、任务执行逻辑

在创建文件 编写类

 

submitTask

是对提交函数的简单封装

  1. 因为自身存储了,因此它可以省略的第一个参数
  2. 元数据可以明确限定
    • 比如我只需要重试次数,我就只把它当做输入参数,然后封装成

具体编写为以下逻辑

 

handleTask

前面也提到了,是最终用于处理任务的逻辑 它其实有两个作用

  1. 准备、善后处理
    • 接受任务元数据,先进行准备
  2. 处理任务
    • 接受任务参数,真正处理任务

在这里,“准备、善后”部分我只用作处理重试逻辑 处理任务的逻辑我把它分割到另一个方法,由子类实现

应在成功时返回假,失败时返回需要任务再次执行所需的参数

 

将由处理并显示在控制台中

真正的功能类继承自Task类,这里需要编写访问远程分析工具,并返回页面浏览量的逻辑 因此命名为

同样地,具体的依靠于具体的远程分析工具API 但在这层抽象中,我们只关注它们的共性:都需要失败重试

在创建文件 编写类

 

首先别忘了我们需要给任务起名

php的静态多态太爽了 C#什么时候能站起来

这段逻辑呼应了我们远古时代实现的逻辑 我们为了节省开销,将多次阅读量更新捆绑成一次提交 因此包含的是一个列表的待更新文章

我们在foreach循环中分割成单个更新,再次踢皮球到交给子类处理

然后更新过程中的就有点秀了

  • 如果没出意外,我们把它从列表中移除,意为不再需要
  • 如果出了意外,将被catch,并跳转到foreach下个循环

所以一顿操作后,最终执行失败的参数会保留在中 将它返回,则会触发父类的重试逻辑,再次压入后台进程队列

妙妙妙妙妙

每个远程统计工具实现不同,所以这层是必须的 这里还是以为例,其它的也差不多,只是需要修改访问的参数

在创建文件 编写类

 

这段代码因为比较简单,也直接给出了 需要提醒的是

  1. 重要数据不要硬编码在代码中,在WordPress中可以使用控制台的设置功能
    • 不过这里用到的是装了插件
  2. 大部分参数都可以自身构造而来,真正从外部接受的参数其实就只有
  3. 我们在为时抛出异常,以示意出错
    • 出错的主要原因是网络连接不佳,因此我们需要抛出错误,并重试
    • 返回401,404等不算出错,有返回的情况反而没有重试的必要
      • 因为试几次都是一样的
  4. 返回的处理取决于返回数据,这里是顺着的返回写的

ruaaaaaaaaaaaaaaaaaaaaa

还记得吗?之前的代码有一段空了一块 在提交任务时,没有给出具体的操作代码

因为当时还没引入后面的一堆 但现在,我们都是懂哥了 加入这句代码,让这个系统运作起来

 

调用

  1. 参数1:重试1次
  2. 参数2:更新若干文章的必要数据

最后,我们需要初始化,如果不初始化,没有任务会被监听 不管需不需要加入新任务,请确保每次php执行都会执行以下语句

 
  1. 记得设置,当然你也可以传入实现懒加载
    • e.g. ;
  2. 记得注册所有可能执行的任务
    • 注册开销并不大,不要省
    • 省了任务绝对执行不了
  3. 在最后,记得调用,否则不会进行任何实质初始化操作

花了好久,写了这么多 包括代码,包括文章

这过程中不止一次问自己,至于吗? 我最终的答案是肯定的

确实绕,甚至是俄罗斯套娃 但在理解了绕之后,带来的是可拓展性、可维护性

当然也可以直接一步步写下来 实不相瞒,我第一个版本就是一步步写下去的,根本就没有一个类

但这样做,怎么进行拓展? 不同的代码混在一起,怎么维护

所以就算是花更多时间,在把这坨屎跑起来之后,都要给它框架化、规则化 消化了这坨小屎,才能避免整个程序变成大屎

框架本身增加复杂性,但它也带来了规则性: 有了框架,就很容易借用相似的逻辑 有了框架,一切东西都井然有序

现在这个版本,你可以随意增加更多的Task,逻辑都是一样的 多舒服啊

至于访问远程统计工具获取精准数据吗? 至于搞缓存吗? 至于搞后台进程吗

没错,要实现“显示浏览量”可以很简单 甚至不精准的统计数据,可以增加我网站的显示访问量(草,现在全是个位数

本文地址:http://yejunbin01.xhstdz.com/quote/65961.html    物流园资讯网 http://yejunbin01.xhstdz.com/ , 查看更多

特别提示:本信息由相关用户自行提供,真实性未证实,仅供参考。请谨慎采用,风险自负。


0相关评论
相关最新动态
推荐最新动态
点击排行
网站首页  |  关于我们  |  联系方式  |  使用协议  |  版权隐私  |  网站地图  |  排名推广  |  广告服务  |  积分换礼  |  网站留言  |  RSS订阅  |  违规举报  |  鄂ICP备2020018471号