群晖NAS使用Docker部署WordPress

搭建网站的工具和过程降到低门槛和极低成本,WordPress使用小型文件数据库SQLite

有什么用

怎么用

1
2
3
4
5
6
7
8
9
10
11
version: '3'
services:
wordpress:
image: soulteary/sqlite-wordpress
restart: always
ports:
- 8104:80
volumes:
- ./:/var/www/html
#用于对接兰空图床批量上传的图库, CSV中含文件名对应到产品
- /volume2/KingchuxingSSD512G/MacBookPro_Skitch/storage/app/uploads/2026/05:/var/www/html/wp-content/uploads/lskyupload202605

https://wp.carlzeng.com:3/wp-admin/

相关内容

WooCommerce导入产品

安装插件: WebToffee Import Export

image-20260511092148886

如何导入产品照片?

需求: 导入所有几千张照片, 然后关联到产出

WP的SQLlite数据库文件在哪里?

WordPress 用 SQLite 时(官方插件 sqlite-database-integration 或 wp-sqlite-db),数据库文件默认在:

1
wp-content/database/.ht.sqlite

最后图片还是要使用WP原始的图库功能;

上传到图库, 但由于兰空图床的目录使用的docker的映射方式, 被我直接映射到docker目录

/volume2/KingchuxingSSD512G/MacBookPro_Skitch/storage/app/uploads/2026/05

这样; Addd From Server Reloaded 就能加载到这些1170+张照片了

导入后: 图库

image-20260512231637885

故障: 很多可以在兰空中看到的照片, 无法访问, 不知为何(是否和docker wordpress映射 并上传后有关? )
https://img.carlzeng.com:3/i/2026/05/O1CN01bBq8Wx1smZl0yPj7B_!!4611686018427385985-53-fleamarket.jpg

O1CN01fP0ICM1smZqe9QMrt_!!4611686018427385985-53-xy_item.jpg

成功链接到使用免费版的WebToffee Import Export; 导入所有产品和相关联的图片(先导入到图库中)

照片可以导入格式:
/wp-content/uploads/O1CN013Dpd011smZsfIaiIb_4611686018427385985-53-xy_item.jpg

可以导入多张照片, 用 , 空格分开

-5:09pm- 用,分隔即可

    修改全部的csv文件, 转化
    | 为 ,
    !! 去除
    格式如上

优化docker-compose 的目录映射 添加:ro, 确保兰空图床中的文件, 不要受影响/删除

如何批量导入MD博客文章

插件: Import Markdown 似乎只能单独, 单个文件的导入?

各种研究, 最后在一个博主的站点上找到了解决方案, 用一个python脚本 一键批量上传目录中441篇文章到WordPress

简直太高效了, 分享源码:

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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
import os  # 用来遍历文件路径
import sys
import ssl
ssl._create_default_https_context = ssl._create_unverified_context


"""
需要安装如下pip包
pip3 install python-frontmatter
pip3 install markdown
pip install 'Markdown'
pip3 install python-wordpress-xmlrpc
"""
# 1 导入frontmatter模块
import frontmatter

# 2 导入markdown模块
import markdown

# 3 导入wordpress_xmlrpc模块
from wordpress_xmlrpc import Client, WordPressPost
from wordpress_xmlrpc.methods.posts import NewPost


def make_post(filepath, metadata):
"""
make a WordPressPost for Client call
:param filepath: 要发布的文件路径
:param metadata: 字典类型
包括 metadata['category']: 文章分类
metadata['tag']: 文章标签
metadata['status']: 有publish发布、draft草稿、private隐私状态可选
:return WordPressPost: if success
None: if failure
"""
filename = os.path.basename(filepath) # 例如:test(2021.11.19).md
filename_suffix = filename.split('.')[-1] # 例如:md
filename_prefix = filename.replace('.' + filename_suffix, '') # 例如:test(2021.11.19);注意:这种替换方法要求文件名中只有一个".md"

# 目前只支持 .md 后缀的文件
if filename_suffix != 'md':
return None

# 1 通过frontmatter.load函数加载读取文档里的信息,包括元数据
post_from_file = frontmatter.load(filepath)

# 2 markdown库导入内容
post_content_html = markdown.markdown(post_from_file.content, extensions=['markdown.extensions.fenced_code'])
post_content_html = post_content_html.encode("utf-8")

# 3 将本地post的元数据暂存到metadata中
metadata['title'] = filename_prefix # 将文件名去掉.md后缀,作为标题
# metadata['slug'] = metadata['title'] # 别名
metadata_keys = metadata.keys()
# 如果post_from_file.metadata中的属性key存在,那么就将metadata[key]替换为它
for key in metadata_keys:
if key in post_from_file.metadata: # 若md文件中没有元数据'category',则无法调用post.metadata['category']
metadata[key] = post_from_file.metadata[key]

# 4 将metadata中的属性赋值给post的对应属性
post = WordPressPost() # 要返回的post
post.content = post_content_html
post.title = metadata['title']
# post.slug = metadata['slug']
post.post_status = metadata['status']
post.terms_names = {
'category': metadata['category'],
'post_tag': metadata['tag']
}
post.comment_status = 'open' # 开启评论
return post


def push_post(post, client):
"""
上传post到WordPress网站
:param post: 要发布的文章(WordPressPost类型),由make_post函数得到
:param client: 客户端
:return True: if success
"""
return client.call(NewPost(post))


def get_filepaths(path):
"""
如果path是目录路径,递归遍历path目录下的所有文件,将所有文件路径存入filepaths
如果path是文件路径,直接将单个文件路径存入filepaths
:param path: 你要上传的目录路径或文件路径(绝对路径)
:return filepaths: 该目录下的所有子文件或单个文件的绝对路径
None: wrong path
"""
filepaths = []
if os.path.isdir(path): # 当前路径是目录
for now_dirpath, child_dirnames, child_filenames in os.walk(path):
# ========== 新增:排除包含 secret 的目录 ==========
if 'secret' in now_dirpath.lower(): # 不区分大小写:Secret / SECRET 都排除
continue

for filename in child_filenames:
filepath = os.path.join(now_dirpath, filename)
filepaths.append(filepath)
filepaths.sort() # <-- 按英文字母 / 数字顺序排序(就加这一行)
return filepaths
elif os.path.isfile(path): # 当前路径是文件
return [path]
else: # wrong path
return None


if __name__ == '__main__':
# User Configuration
path = '/Users/carlzeng/App/blog/source/_posts' # e.g. D:/PythonCode/post-wordpress-with-markdown/doc
domain_list = [
'https://wp.carlzeng.com:3/'
] # e.g. https://example.com(配置了SSL证书就用https,否则用http)
username = '*******'
password = '*******'

for domain in domain_list:
# Optional Configuration
post_metadata = {
'category': ['未分类'], # 文章分类
'tag': ['手柄一修哥'], # 文章标签
'status': 'publish' # 可选publish发布、draft草稿、private隐私状态
}

# Start Work
print('----------------------------------------------START----------------------------------------------')
filepaths = get_filepaths(path)
if filepaths is None:
print('FAILURE: wrong path')
sys.exit(1)

client = Client(domain + '/xmlrpc.php', username, password) # 客户端

md_cnt = 0
all_cnt = len(filepaths)
process_number = 0
failpaths = [] # 存储上传失败的文件路径
for filepath in filepaths:
process_number = process_number + 1
filename = os.path.basename(filepath)
try:
# 把可能报错的逻辑全部放进 try
post = make_post(filepath, post_metadata)

if post is not None:
push_post(post, client)
md_cnt = md_cnt + 1
print('Process number: %d/%d SUCCESS: Push "%s" completed!' % (process_number, all_cnt, filename))
else:
failpaths.append(filepath)
print('Process number: %d/%d WARNING: Can\'t push "%s" because it\'s not Markdown file.' % (
process_number, all_cnt, filename))
except Exception as e:
# 捕获解析/发布失败,不中断程序
failpaths.append(filepath)
print('Process number: %d/%d ERROR: Failed to push "%s" | Reason: %s' % (process_number, all_cnt, filename, str(e)))

print('-----------------------------------------------END-----------------------------------------------')
print('SUCCESS: %d files have been pushed to {0}.'.format(domain) % md_cnt)

if len(failpaths) > 0:
print('WARNING: %d files haven\'t been pushed to {0}.'.format(domain) % len(failpaths))
print('\nFailure to push these file paths:')
for failpath in failpaths:
print(failpath)

感谢作者: 一键上传markdown 格式文章到wordpress

修改的点有:

  1. 第137行 post = make_post(filepath, post_metadata) 这个需要try catch
  2. 添加排序功能: 目前加载目录下的文件没有排序, 请按文件的英文字母顺序排序
  3. 请排除目录名中包含secret的目录

运行后输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
----------------------------------------------START----------------------------------------------
Process number: 8/418 SUCCESS: Push "1099-MISC是什么-CarlZeng.md" completed!
Process number: 9/418 SUCCESS: Push "A-feature-in-Netsuite-Reports-Financial-Balance-Sheet-CarlZeng.md" completed!
Process number: 10/418 SUCCESS: Push "AI脸部识别,人脸比对,人脸识别-CarlZeng.md" completed!
Process number: 11/418 SUCCESS: Push "AJAX提交数据时-中文处理-以及js-url-中文处理-CarlZeng.md" completed!
Process number: 12/418 SUCCESS: Push "Bar-codes-in-NetSuite-Saved-Searches-transport-reprint-活用NetSuite搜索页面显示可扫描条码-CarlZeng.md" completed!

...

Process number: 417/418 SUCCESS: Push "高手写出的是天使,而新手写的,可能是魔鬼!-Javascript这样的脚本语言,由于太灵活-CarlZeng.md" completed!
Process number: 418/418 SUCCESS: Push "高效的服务端生成QRCODE二维码方案-Docker搭建.md" completed!
-----------------------------------------------END-----------------------------------------------
SUCCESS: 411 files have been pushed to https://wp.carlzeng.com:3/.
WARNING: 7 files haven't been pushed to https://wp.carlzeng.com:3/.

Failure to push these file paths:
/Users/carlzeng/App/blog/source/_posts/.DS_Store

灵感来源

WordPress 告别 MySQL:Docker SQLite WordPress

个性化需求沟通 扫客服加V加群: