利用WordPress构建页面快速上线年度报告

2024 年年底已经到了,看到网易云音乐和QQ音乐的年度报告,突然觉得,我也可以给同事们安排一个。

实际上这个想法 2023 年就已经有了,并且也确实做了一些工作,但是因为不懂 css 和 javascript ,所以很难做出来漂亮美观的页面。

在大概 8 年前,我尝试过用 WordPress 来搭建博客和个人网站,虽然后来没有再使用,但是对 WordPress + Elementor 这种直接可视化拖动小部件来搭建网页的方式,印象非常深刻。能让一个完全不懂前端的人,快速的地搭建一个相对美观的网页。

所以,我在今年尝试了新的技术方案,以便于我能够在对前端一无所知的情况下,也能构建出来一个美观的、带有简单动画的年度报告页面,那就是利用 WordPress 来可视化地制作网页,具体的技术思路如下:

  1. 使用 WordPress 的页面构建器 Elementor Pro 插件来构建想要的页面;
  2. 使用 WordPress 的 Simply Static 插件来将站点导出为静态资源;
  3. 替换静态资源中的对应页面 html 文件,将数据部分更改为 jinja2 模板的格式,并用 python 脚本为每个同事提取数据,渲染页面;
  4. 将渲染的页面部署到腾讯云对象存储,并开启静态网站功能;
  5. 将每个同事的页面地址推送到钉钉工作通知。

最终效果如下:

  • 工作通知效果:
    image
    image
  • 年度报告页面效果:
    image

第一步:使用 WordPress 构建页面

直接使用 Docker Desktop 部署 WordPress:

services:  
  wordpress:  
    image: wordpress:php8.3  
    restart: always  
    volumes:  
      - './html/plugins:/var/www/html/wp-content/plugins'
      - './html/uploads:/var/www/html/wp-content/uploads'
      - './html/public_static:/var/www/html/public_static'
      - './php/php.ini:/usr/local/etc/php/php.ini'
    ports:  
      - '60080:80'
    environment:
      TZ: "Asia/Shanghai"
      WORDPRESS_DB_NAME: 'wordpress'
      WORDPRESS_DB_USER: 'root'
      WORDPRESS_DB_PASSWORD: '********'
      WORDPRESS_DB_HOST: 'mysql'
      WORDPRESS_CONFIG_EXTRA: |
        define( 'WP_MEMORY_LIMIT', '1024M' );  
        define( 'WP_MAX_MEMORY_LIMIT', '2048M' );  
        define( 'WP_SITEURL', 'https://<your-domian>' );  
        define( 'WP_HOME', https://<your-domian>' );  
        define( 'WP_CACHE', true );  
        define( 'WP_ENVIRONMENT_TYPE', 'production' );  
  mysql:  
    image: mysql:latest  
    restart: always  
    volumes:  
      - 'mysql-data:/var/lib/mysql'  
    environment:  
      MYSQL_DATABASE: 'wordpress'  
      MYSQL_ROOT_PASSWORD: '********'
  
volumes:  
  mysql-data:
docker-compose.yaml 说明
  1. 对于 wordpress 容器,只需挂载插件目录 /var/www/html/wp-content/plugins 、附件上传目录 /var/www/html/wp-content/uploads 即可,有必要时还可以挂载主题目录 /var/www/html/wp-content/themes
  2. 无需挂载 wp-config.php 文件,在容器启动时,会根据传入的环境变量自动生成。
  3. 在本地创建好 php.ini 并挂载到 /usr/local/etc/php/php.ini ,有利于更改内存限制和最大文件上传大小。
  4. ./html/public_static:/var/www/html/public_static 是给 Simply Static 准备的静态页面存储位置。

将访问端口接入到腾讯云EdgeOne来得到可以公网访问的域名并添加 SSL 证书,并将域名配置到 WORDPRESS_CONFIG_EXTRA 环境变量中,然后部署容器即可。

安装 Elementor Pro 页面构建器插件

Pro 版本可以直接在淘宝搜索购买,价格在 18元 ~ 30元 不等,一般都需要发送页面的公网访问地址、管理员用户名、管理员密码给商家进行激活。

如果想要使用 Elementor Pro 构建器,来获得更多的页面动态效果、视差效果,则必须使用域名来访问,否则无法激活 Pro 版本插件。

安装 Simply Static 静态网站转换插件

直接在插件商店搜索安装即可。也可以在 Simply Static - the best WordPress static site generator. 官网下载安装,然后将其放到 ./html/plugins 目录下,然后在插件管理页面开启。

还可以安装其他 Elementor 相关插件,获得更加丰富的页面小部件。

image

构建页面

在页面菜单中,用 Elementor 构建器创建编辑一个页面,并将其设置为站点主页。

image

由于我是用来作为年度报告,所以不希望页面有导航栏、菜单栏,所以我在页面设置中,将 页面布局 设置为 Elementor 画布 ,然后开始使用各种小部件来搭建页面。

image

通过设置板块最小高度为 100vh 来让每一个页面部分都能动态适应各种型号的手机屏幕满屏显示,这样截图时才能够更加美观。

最小高度不等于实际高度,如果一个板块中的元素过多,可能会超出手机屏幕的高度。

通过将数据部分写成 {{data}} 占位符,我在转换成静态页面之后,能轻松地搜索这些占位符,替换成 jinja2 模板用到的实际字段名。

转换为静态页面

在完成页面构建,预览效果满意后,就可以使用 Simply Static 插件来转换。

  1. 转到插件的 Settings-General 页面设置为 Offline Usage
    image
  2. 转到插件的 Settings-Deploy 页面设置为 Local Diretory 并配置导出目录为 /var/www/html/public_static
    image
  3. 点击 Generate Static Files 按钮,并切换到 Activity Log 查看日志,耐心等待导出完成。出现 Done! Finished in <time> 字样说明导出成功。
    image
在导出前可以先到 Diagnostics 诊断工具页面检查是否可以转换、是否存在不兼容插件等情况。

第二步:从静态文件生成年度报告

./html/public_static 目录将所有生成的静态文件复制到一个新的项目文件夹。

在清理完不用的静态文件后,我们可以编写一个 python 脚本。

以下脚本是一个示例,它加载 jinja2 模板,从 postgresql 数据库中查询数据,并渲染成本地的静态页面。注意,在渲染前,必须将 index.html 中的 {{data}} 占位符改为实际数据字段名,本例中为 namedatesome_data 三个字段。

from datetime import datetime  
  
import psycopg  
from pydantic import BaseModel  
from jinja2 import Environment, FileSystemLoader  
import os
  
  
teachers = ["张三", "李四", "王五"]
  
template_dir = os.path.join(os.path.dirname(__file__), 'static')  
env = Environment(loader=FileSystemLoader(template_dir))  
template = env.get_template('index.html')
  
class ReportData(BaseModel):  
    name:str  
    date:str = datetime.now().strftime("%Y-%m-%d %H:%M")
	some_data:int = 0

conn = psycopg.connect("postgresql://<user>:<pwd>@<host>:5432/<database>")
cur = conn.cursor()  
  
for teacher in teachers:  
    report_data = ReportData(name=teacher)
        
    cur.execute("""
    SELECT .... AS some_data FROM table  
    WHERE "teacherName" = %s AND "startTime" BETWEEN '2024-01-01' AND '2024-12-31';
	""", [teacher])
    record = cur.fetchone()  
    if record:
        report_data.some_data = record[0]
        
    output = template.render(report_data.model_dump())
    
    with open(f'static/{teacher}.html', 'w', encoding="utf-8") as f:  
        f.write(output)
        
cur.close()

运行脚本,可以生成 张三.html 李四.html 王五.html 三个年度报告,然后打开确认,如果有需要调整的地方,可以直接调整 index.html 模板,或者重新编辑 WordPress 页面并生成静态文件。

第三步:部署上线并推送

配置腾讯云对象存储静态站

我们首先在腾讯云对象存储中创建一个新的私有读写的桶,然后开启桶的静态网站功能。

image

然后使用腾讯云 EdgeOne 配置一个域名,并将存储桶接入。

image

然后可以将静态资源上传到对象存储根目录,然后访问 http://your-domain/index.html 来查看配置是否正确。

image

推送钉钉

在上一步中,我们使用 for 循环遍历teachers 列表,生成了一些 html 页面,用于本地预览。

但是实际上线时,可能不希望一个人能查看另一个人的年度报告,所以,文件名就不能简单地使用人名。

我们可以引入 uuid 库,然后为每个老师生成一个随机的 uuid,并截取后 12 位作为文件名,将其上传到腾讯云对象存储中。

同时,还需要为每个人推送他们的报告,我使用了钉钉工作通知。

注意:以下代码中使用的 dagster_dingtalk 库是我编写的用于 dagster 与钉钉集成的第三方库,在 dagster 环境中方可使用。推荐自己编写与钉钉 openapi 交互的代码。

...  # 省略重复代码

import uuid
from qcloud_cos import CosConfig, CosS3Client
from dagster_dingtalk import DingTalkAppClient

cos_client = CosS3Client(
	CosConfig(Region="ap-guangzhou", SecretId="<your-secretid>", SecretKey="<your-secretkey>")
)

dt_client = DingTalkAppClient(  
    app_id="<your-app_id>",  
    client_id="<your-client_id>",  
    client_secret="<your-client_secret>"
)

teachers = ["张三", "李四", "王五"]

...  # 省略重复代码

for teacher in teachers:

	...  # 省略重复代码
	
	output = template.render(report_data.model_dump())
	
	uuid_str = str(uuid.uuid4())[-12:]
	cos_client.put_object(
	    Bucket='<your-bucket>',  
        Body=output.encode('utf-8'),  
        Key=f'{uuid_str}.html',  
        EnableMD5=False  
    )
    msg = {  
        "msgtype": "action_card",  
        "action_card": {  
            "title": "你的年度教学报告来啦!快来查看吧!",  
            "markdown": "![](<cover-image-url>)\n"  
                        f"\n### {teacher}老师,您的2024年度教学报告已生成!快来查看吧!",  
            "single_title": "点击查看",  
            "single_url": f"https://<your-domain>/{uuid_str}.html"  
        }  
    }
    dt_client.即时通信.工作通知.发送工作通知(to_all_user=False, user_list=[user_id], msg=msg)
    
...  # 省略重复代码

至此,搞定完工!