搭建网站的工具和过程降到低门槛和低成本,WordPress使用小型文件数据库SQLite组建Sandbox系统模拟
由于访问速度的因素, 整个方案切换至hexo+vercel的方案(全站照片CDN, 首页背景采用bing每日照片API自动更新)
朗读全文
Your browser does not support the audio element.
有什么用
创建工作室/公司网站, 网店; 发布文章, 分享经验等
SEO友好
展示: https://n.carlzeng.com
怎么用 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 - /volume2/KingchuxingSSD512G/MacBookPro_Skitch/storage/app/uploads/2026/05:/var/www/html/wp-content/uploads/lskyupload202605
后来验证: 这种方式最后用于sandbox的建设, 因为网店再导入商品和图片后下单会报错, 切换使用官方版本后解决; 用这种轻量级的sandbox好处有: 随便安装插件等, 不怕污染了主数据库(数据的清理干净很麻烦, 耗时, 易出错)
演示/实践 https://w.carlzeng.com
相关内容
WooCommerce导入产品 安装插件: WebToffee Import Export
如何导入产品照片? 需求: 导入所有几千张照片, 然后关联到产出
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+张照片了
导入后: 图库
故障: 很多可以在兰空中看到的照片, 无法访问, 不知为何(是否和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, 确保兰空图床中的文件, 不要受影响/删除
导入详细商品目录 用DBeaver, 导入wp_posts表数据, 和 wp_postmeta表数据
绝大部分数据成功/轻松导入.
发现问题:
有的货品的SKU和价格丢失
修复步骤:
查询到sku 或 price为空的行, 一共60个; 复制出p.ID
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 SELECT p.ID as product_id, p.post_title as product_name, sku.meta_value as sku, price.meta_value as price FROM wp_posts p LEFT JOIN wp_postmeta sku ON p.ID = sku.post_id AND sku.meta_key = '_sku' LEFT JOIN wp_postmeta price ON p.ID = price.post_id AND price.meta_key = '_price' WHERE p.post_type = 'product' AND p.post_status = 'publish' AND ( sku.meta_value IS NULL OR sku.meta_value = '' OR price.meta_value IS NULL OR price.meta_value = '' );
到Sandbox正常的数据库中提取这些wp_postmeta相关的行数据
1 2 3 4 5 6 7 8 SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE post_id IN (9, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 281, 282, 283, 284, 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, 295, 296, 297, 298, 299, 300, 321, 322, 323, 324, 325, 326, 327, 328, 329, 330, 331, 332, 333, 334, 335, 336, 337, 338)
使用DBeaver导出这些数据, 然后目标选择到MariaDB的wp_postmeta 表,
注意: 不要输出meta_id, 列, 不然会存在PK冲突的问题, 导致数据无法正常导入
导入最后一步选择 Insert IGNORE
至此60个有显示故障的商品wp_postmeta被重新导入修复完毕!
下一步: 继续设置商品的分类和品牌, 标签等
解锁媒体库目前上传限制2MB 媒体库目前上传限制时2MB, 如何改成4M?
docker-compose中添加
1 2 3 4 WORDPRESS_CONFIG_EXTRA: | @ini_set( 'upload_max_filesize', '4M' ); @ini_set( 'post_max_size', '4M' ); @ini_set( 'max_execution_time', '300' );
无法解决问题, 媒体上传限制还是2M
1 2 @ini_set ( 'upload_max_size' , '4M' ); @ini_set ( 'post_max_size' , '4M' );
解决办法: 新建一个插件
1 2 3 4 5 6 7 8 9 <?php add_filter ( 'upload_size_limit' , 'b5f_increase_upload' );function b5f_increase_upload ( $bytes ) { return 4194304 ; }
把这个文件保存, 然后压缩成.zip文件; 比如: increase-upload-limit.zip
然后在安装插件页面 上传, 启用, 解决!
而且编辑是动态的, 也就是说 想要修改这个限制; 直接ssh过去服务器中, 修改这个值; 立即生效, 简单直接.
在wordpress 根目录 创建一个新的php.ini文件
使用代码或文本编辑器,将以下代码添加到现有或新的php.ini 文件中:
1 2 3 upload_max_filesize = 5M post_max_size = 5M memory_limit = 128M
本小节感谢: WordPress上传限制,最大上传文件大小,最大上传限制 文字教程
修改商店页面标题:
同时也添加到了vi increase-upload-limit.php 这个文件中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 add_filter ( 'document_title_parts' , function( $parts ) { if ( is_shop () || is_product_category () || is_product_tag () ) { if ( ! empty ( $parts ['title' ] ) ) { $parts ['title' ] = '案例 - ' . $parts ['title' ]; } else { $parts ['title' ] = '案例' ; } } return $parts ; }, 999 );
如何批量导入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 sysimport sslssl._create_default_https_context = ssl._create_unverified_context """ 需要安装如下pip包 pip3 install python-frontmatter pip3 install markdown pip install 'Markdown' pip3 install python-wordpress-xmlrpc """ import frontmatterimport markdownfrom wordpress_xmlrpc import Client, WordPressPostfrom wordpress_xmlrpc.methods.posts import NewPostdef 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) filename_suffix = filename.split('.' )[-1 ] filename_prefix = filename.replace('.' + filename_suffix, '' ) if filename_suffix != 'md' : return None post_from_file = frontmatter.load(filepath) post_content_html = markdown.markdown(post_from_file.content, extensions=['markdown.extensions.fenced_code' ]) post_content_html = post_content_html.encode("utf-8" ) metadata['title' ] = filename_prefix metadata_keys = metadata.keys() for key in metadata_keys: if key in post_from_file.metadata: metadata[key] = post_from_file.metadata[key] post = WordPressPost() post.content = post_content_html post.title = metadata['title' ] 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): if 'secret' in now_dirpath.lower(): 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 : return None if __name__ == '__main__' : path = '/Users/carlzeng/App/blog/source/_posts' domain_list = [ 'https://wp.carlzeng.com:3/' ] username = '*******' password = '*******' for domain in domain_list: post_metadata = { 'category' : ['未分类' ], 'tag' : ['手柄一修哥' ], 'status' : 'publish' } 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 : 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
修改的点有:
第137行 post = make_post(filepath, post_metadata) 这个需要try catch
添加排序功能: 目前加载目录下的文件没有排序, 请按文件的英文字母顺序排序
请排除目录名中包含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
遇到的bug/enhancement:
手动完成文章所有分类,
标签和照片无法导入; (用python, 等待更新, 提取这些信息到WP)
下一步:
Woocommerce下单错误 点击下单报错:
1 Uncaught Error: Call to a member function get_total() on false in /var/www/html/wp-content/plugins/woocommerce/includes/gateways/cod/class-wc-gateway-cod.php:314\nStack trace:\n#0 /var/www/html/wp-content/plugins/woocommerce/src/StoreApi/Legacy.php(56): WC_Gateway_COD->process_payment(4131)\n#1 /var/www/html/wp-includes/class-wp-hook.php(341): Automattic\\WooCommerce\\StoreApi\\Legacy->process_legacy_payment(Object(Automattic\\WooCommerce\\StoreApi\\Payments\\PaymentContext), Object(Automattic\\WooCommerce…wp-includes/class-wp-hook.php(365): WP_Hook->apply_filters(NULL, Array)\n
wp_woocommerce_order_items 等等, 这些表都有的
为了解决woocommerce的故障, 需要让wordpress使用官方的docker image, 切换数据库(mssql, mariadb)方案
从另外一个wordpress数据库导入文章 通过工具链接到MariaDB, 将查询导出为CSV; 然后导入到在线的文件型数据库中: .ht.sqlite
1 2 3 4 5 6 7 8 9 10 SELECT p.* FROM wp_posts pJOIN wp_term_relationships tr ON p.ID = tr.object_idJOIN wp_term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_idWHERE tt.term_id = 22 AND tt.taxonomy = 'category' AND p.post_type = 'post' AND p.post_status = 'publish' ORDER BY p.post_date DESC ;
继续在新的系统中编辑这些文章
修改域名, 和导入的文章URL需要修改
1 2 3 4 5 6 7 8 9 10 11 SELECT 'wp_posts' AS src, CONCAT(ID,':' ,post_title) AS name, guid FROM wp_posts WHERE guid LIKE 'http%' UNION ALL SELECT 'wp_postmeta' AS src, meta_key, meta_value FROM wp_postmeta WHERE meta_value LIKE 'http%' ;
1 2 3 4 5 6 7 8 9 10 11 12 13 UPDATE wp_posts SET post_content=REPLACE(post_content,'http://192.168.6.203:8108','https://netsuite.carlzeng.com'), guid=REPLACE(guid,'http://192.168.6.203:8108','https://netsuite.carlzeng.com'); UPDATE wp_posts SET post_content=REPLACE(post_content,'https://w.carlzeng.com','https://netsuite.carlzeng.com'), guid=REPLACE(guid,'https://w.carlzeng.com','https://netsuite.carlzeng.com'); --手动更新了一行 -- 4. 文章自定义字段里的URL SELECT 'wp_postmeta' AS src, meta_key, meta_value, * FROM wp_postmeta WHERE meta_value LIKE 'http%';
如何修复错误 “Too Many Redirects” WordPress 报错 (ERR_TOO_MANY_REDIRECTS) ERR_TOO_MANY_REDIRECTS
使用本地部署后, 局域网可访问, 如: http://192.168.6 .* 那么NPM反代以后, 使用 https://wp.yourdomain.com:3/wp-admin可正常访问后台 ; 下一步: 如何让远程的CDN直接使用无需携带端口的访问方式?
首先要去处理的是本地访问
然后反向代理, 测试反向代理后的后台访问是否正常, css都正常, 登录也正常
确保CDN后者cloudflare中的映射是通的; 具体详见“博客迁移说明” CDN章节
//define(‘WP_HOME’,’https://w.carlzeng.com ‘); define(‘WP_SITEURL’,’https://w.carlzeng.com ‘);
#这个用来应急时调整, 获得后台的访问权限; 主要是要先把CDN那边端口映射先做好, 映射到本地的NPM 如: *.yourdomain.com:4443(这个端口目前只有后台的访问权限/wp-admin
切换到官方Docker Image Production生成环境
1 2 mkdir wordpresshtml && mkdir db vi docker-compose.yaml
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 services: wordpress: image: wordpress restart: always ports: - 8106 :80 environment: WORDPRESS_DB_HOST: db WORDPRESS_DB_USER: example user WORDPRESS_DB_PASSWORD: example pass WORDPRESS_DB_NAME: wordpress volumes: - ./wordpresshtml:/var/www/html db: image: mysql:8.0 restart: always environment: MYSQL_DATABASE: wordpress MYSQL_USER: example user MYSQL_PASSWORD: example pass MYSQL_RANDOM_ROOT_PASSWORD: '1' volumes: - ./db:/var/lib/mysql volumes: wordpress: db:
chown mysql /volume2/KingchuxingSSD512G/docker/compose/wordpress2/db -R
chmod +777 /volume2/KingchuxingSSD512G/docker/compose/wordpress2/db -R
chown mysql /volume2/KingchuxingSSD512G/docker/compose/wordpress2/wordpresshtml -R
chmod +777 /volume2/KingchuxingSSD512G/docker/compose/wordpress2/wordpresshtml -R
必须要运行这个目录权限, 否者就是各种报错.
woocommerce Connection Information
upload a WooCommerce .zip file and install the plugin on the local host. Every time I click install button, WordPress is asking for connection for FTP
Add this line in wp-config.php
1 define ( 'FS_METHOD' , 'direct' );
1 2 3 4 define ('WP_SITEURL' ,'https://w.carlzeng.com' ); define ('WP_CONTENT_URL' , '/wp-content' );
还是决定切换到MariaDB
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 services: wordpress: image: wordpress restart: always ports: - 8106 :80 environment: WORDPRESS_DB_HOST: db WORDPRESS_DB_USER: example user WORDPRESS_DB_PASSWORD: example pass WORDPRESS_DB_NAME: wordpress volumes: - ./wordpresshtml:/var/www/html db: image: mariadb:jammy restart: always ports: - 8107 :3306 environment: MYSQL_DATABASE: wordpress MYSQL_USER: example user MYSQL_PASSWORD: example pass MYSQL_RANDOM_ROOT_PASSWORD: '1' volumes: - ./db:/var/lib/mysql volumes: wordpress: db:
初始化安装好wordpress, 只需要这些表:
手工导入wp_posts (直接从数据库到数据库)
然后用csv导入wp_postmeta
裁剪您的图片时发生错误。
原来是操作不了PNG; JPG可以的, 无所谓, 无伤大雅
SQL修复文章分类 wp_term_taxonomy 这个基础表维护的是: 分类ID和分类名称; 比如: 产品分类、文章分类、产品类型、模版类型部分区域
wp_term_relationships 这个表保存文章/产品 与分类的关系; 比如: 文章#1属于类名#1
步骤一: 插入wp_term_relationships 1 2 3 INSERT IGNORE INTO wp_term_relationships (object_id, term_taxonomy_id, term_order) select ID, 22, 0 from wp_posts where post_type = 'post' and post_content like '%netsuite%' or post_title like '%netsuite'
note: 用IGNORE支持多次执行, 会避开重复的行, 输出
1 2 3 4 5 6 7 Duplicate entry '205-22' for key 'PRIMARY' Duplicate entry '3298-22' for key 'PRIMARY' Duplicate entry '3306-22' for key 'PRIMARY' Duplicate entry '3312-22' for key 'PRIMARY' Duplicate entry '3640-22' for key 'PRIMARY' Duplicate entry '3662-22' for key 'PRIMARY'
步骤二: 插入wp_term_taxonomy 1 2 3 4 5 6 7 8 #关键后续:更新 WordPress 分类计数器 UPDATE wp_term_taxonomy SET count = ( SELECT COUNT(*) FROM wp_term_relationships WHERE wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id ) WHERE term_taxonomy_id = 22
添加剩余的文章都分类到: 一修哥工作室
1 2 3 4 5 6 7 8 9 10 11 12 INSERT IGNORE INTO wp_term_relationships (object_id, term_taxonomy_id, term_order)select ID, 23 , 0 from wp_posts where post_type = 'post' and ID not in (select object_id from wp_term_relationships) UPDATE wp_term_taxonomy SET count = ( SELECT COUNT (* ) FROM wp_term_relationships WHERE wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id ) WHERE term_taxonomy_id = 23
导入部分硬件工作记录/成功案例 以准备好成功案例的md聊天记录导出, 导入展现. 此md来源为: 闲鱼APP中聊天记录导出
批量, 加载目录下md文件时, 需要按md文件的创建时间顺序来加载
Sanbox测试得知: 待修复 视频,如何支持在线点击查看? md文件中如何显示视频播放器?
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 import osimport repattern = r'\[\s*视频\s*\]\(\s*(https?://[^\s\)]+|[^\s\)]+\.mp4|[^\s\)]+)\s*\)' def get_file_creation_time (file_path ): """兼容多系统的获取文件创建时间函数""" stat = os.stat(file_path) try : return stat.st_birthtime except AttributeError: return stat.st_ctime def convert_md_files_by_order (): current_dir = os.getcwd() md_files = [f for f in os.listdir(current_dir) if f.endswith(".md" )] md_files.sort(key=lambda x: get_file_creation_time(os.path.join(current_dir, x))) success_count = 0 print ("开始按创建时间【升序】处理文件...\n" + "-" * 40 ) for filename in md_files: file_path = os.path.join(current_dir, filename) with open (file_path, "r" , encoding="utf-8" ) as f: content = f.read() if re.search(pattern, content): replaced_content = re.sub( pattern, r"\n\n<video src='\1' controls width='100%' height='auto' loop='loop'></video>\n\n" , content, ) with open (file_path, "w" , encoding="utf-8" ) as f: f.write(replaced_content) c_time = get_file_creation_time(file_path) from datetime import datetime time_str = datetime.fromtimestamp(c_time).strftime( "%Y-%m-%d %H:%M:%S" ) print (f"[{time_str} ] 成功转换: {filename} " ) success_count += 1 print ("-" * 40 + f"\n处理完成!共依序转换了 {success_count} 个文件。" ) if __name__ == "__main__" : convert_md_files_by_order()
1 2 3 ----------------------------------------------START---------------------------------- Process number: 1/30 SUCCESS: Push "聊天记录_tbNick_n9c42_2026-05-17.md" completed! ....
对隐私/敏感信息的屏蔽保护 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 SELECT ID, post_title, post_date FROM wp_posts WHERE post_content LIKE '%13261977480%' ;UPDATE wp_posts SET post_content = REPLACE(post_content, '13261977480' , '1326****480' )WHERE post_content LIKE '%13261977480%' ;UPDATE wp_posts SET post_content = REPLACE(post_content, '后北营家园一区10号楼3-130' , '后北营家园一区10号(大运河果蔬便民店外)' )WHERE post_content LIKE '%后北营家园一区10号楼3-130%' ;UPDATE wp_posts SET post_content = REPLACE(post_content, 'VPN' , 'V*P*N' )WHERE post_content LIKE '%VPN%' ;UPDATE wp_posts SET post_title = REPLACE(post_title, '_2026-05-17' , '_手柄一修哥' )WHERE post_title LIKE '%_2026-05-17%' ;
维护商品分类 1 2 3 4 5 6 7 8 INSERT IGNORE INTO wp_term_relationships (object_id, term_taxonomy_id, term_order)SELECT ID, 17 , 0 FROM wp_posts WHERE post_type = 'product' AND post_title like '%PS5%' and ID not in (select object_id from wp_term_relationships)
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 INSERT IGNORE INTO wp_term_relationships (object_id, term_taxonomy_id, term_order)SELECT ID, 27 , 0 FROM wp_posts WHERE post_type = 'product' AND post_title like '%switch%' INSERT IGNORE INTO wp_term_relationships (object_id, term_taxonomy_id, term_order)SELECT ID, 27 , 0 FROM wp_posts WHERE post_type = 'product' AND post_title like '%joycon%' #totally 43 row , success 23 , duplicated Updated rows 23 ; Duplicate entry '242-27' for key 'PRIMARY' Duplicate entry '432-27' for key 'PRIMARY' Duplicate entry '443-27' for key 'PRIMARY' Duplicate entry '455-27' for key 'PRIMARY' Duplicate entry '487-27' for key 'PRIMARY' Duplicate entry '506-27' for key 'PRIMARY' Duplicate entry '259-27' for key 'PRIMARY' Duplicate entry '293-27' for key 'PRIMARY' Duplicate entry '323-27' for key 'PRIMARY' Duplicate entry '578-27' for key 'PRIMARY' Duplicate entry '580-27' for key 'PRIMARY' Duplicate entry '606-27' for key 'PRIMARY' Duplicate entry '608-27' for key 'PRIMARY' Duplicate entry '615-27' for key 'PRIMARY' Duplicate entry '631-27' for key 'PRIMARY' Duplicate entry '652-27' for key 'PRIMARY' Duplicate entry '659-27' for key 'PRIMARY' Duplicate entry '682-27' for key 'PRIMARY' Duplicate entry '684-27' for key 'PRIMARY' Duplicate entry '695-27' for key 'PRIMARY'
17 ps5 93 27 Switch 133 joycon; duplicate lite, oled, 大气层
28 Xbox 35 29 SteamDeck 27 30 Quest3 6 31 PS4 6 32 IT支持 10 远程 10 ; 上门 4
33 NetSuite 1 34 掌机 3
未分类: 24
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 SELECT ID, 27 , 0 FROM wp_posts WHERE post_type = 'product' and wp_posts.ID not in (select object_id from wp_term_relationships) #更新分类的统计表 UPDATE wp_term_taxonomy SET count = ( SELECT COUNT (* ) FROM wp_term_relationships WHERE wp_term_relationships.term_taxonomy_id = wp_term_taxonomy.term_taxonomy_id ) WHERE term_taxonomy_id = 34
Next 搭建: 网站客服系统 docker 比如: https://zhuanlan.zhihu.com/p/23677870488
用于新增一个潜在客户直接语言沟通的机会, 直接在网站中聊天
快速上线的,但是无拓展功能(只能去付费拓展的)
https://www.tawk.to/software/live-chat/
https://www.twt.com/en/chat/pricing
https://github.com/chaskiq/chaskiq
https://github.com/chatwoot/chatwoot
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 version: '3.8' services: chaskiq-redis: image: redis:7-alpine container_name: chaskiq-redis restart: always chaskiq-app: image: chaskiq/chaskiq:latest container_name: chaskiq-app restart: always ports: - "3000:3000" environment: - HOST=http://localhost:3000 - SECRET_KEY_BASE=Another_very_long_random_string_64_chars - REDIS_URL=redis://chaskiq-redis:6379/1 DATABASE_URL=postgresql://umami:umami20260109@192.168.6.117:5434/chaskiq_prod
方案一:正确配置 Chatwoot Community 纯开源版(解除限制)
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 version: '3.8' services: cskefu-redis: image: redis:7-alpine container_name: cskefu-redis restart: always chatwoot-web: image: chatwoot/chatwoot:latest container_name: chatwoot-web restart: always ports: - "3000:3000" environment: - FRONTEND_URL=http://localhost:3000 - SECRET_KEY_BASE=a_very_long_random_string_here_32_chars - ENABLE_ACCOUNT_LIMITS=false - INSTALLATION_ENV=docker - POSTGRES_HOST=172.17.0.1 - POSTGRES_PORT=5432 - POSTGRES_DATABASE=chatwoot_prod - POSTGRES_USERNAME=postgres - POSTGRES_PASSWORD=your_existing_postgres_password - REDIS_URL=redis://cskefu-redis:6379/0 command: bundle exec rails s -p 3000 -b '0.0.0.0' depends_on: - cskefu-redis chatwoot-worker: image: chatwoot/chatwoot:latest container_name: chatwoot-worker restart: always environment: - ENABLE_ACCOUNT_LIMITS=false - INSTALLATION_ENV=docker - POSTGRES_HOST=172.17.0.1 - POSTGRES_PORT=5432 - POSTGRES_DATABASE=chatwoot_prod - POSTGRES_USERNAME=postgres - POSTGRES_PASSWORD=your_existing_postgres_password - REDIS_URL=redis://cskefu-redis:6379/0 command: bundle exec sidekiq -g chatwoot -C config/sidekiq.yml depends_on: - cskefu-redis
SEO优化, 尝试提交Google 下载 wordpress sitemap generator 用于生成网站地图
下载zip, 上传安装后, 自动生成了http://w.carlzeng.com/sitemap.xml
状态: Processing data, please check again in a day or so
待下周重新查阅一下Google收录情况
https://ziyuan.baidu.com/linksubmit/url
Bing
提交了网站地图 http://w.carlzeng.com/sitemap.xml
Google Page Indexing issue
这个很简单, 按链接提示, 把货品图片补上即可.
Missing field “hasMerchantReturnPolicy” (in “offers”)
This is a non-critical issue. Items with these issues are valid, but could be presented with more features or be optimized for more relevant queries
这个已经在商品的详细页面添加了退款和退货策略 还是无法通过校验. 请高人指点.
總結:WPSSO Merchant Return Policy Manager 外掛可以幫助你輕鬆管理Google Merchant 列表的任何數量的退貨政策,同時修復遺失”hasMerchantReturnPolicy “ 的警告。
页面加载速度优化 去除首页的woocommerce区块, 避免照片的3M载入
下面这段是最能减负的, 让css减轻了首页和非commerce页面的负担
1 2 3 4 5 6 7 8 9 10 11 12 13 /** * 禁用 WooCommerce 所有的 CSS 样式和 JS 脚本 */ add_action( 'template_redirect', 'remove_woocommerce_styles_scripts', 999 ); function remove_woocommerce_styles_scripts() { if ( function_exists( 'is_woocommerce' ) ) { if ( ! is_woocommerce() && ! is_cart() && ! is_checkout() ) { remove_action('wp_enqueue_scripts', [WC_Frontend_Scripts::class, 'load_scripts']); remove_action('wp_print_scripts', [WC_Frontend_Scripts::class, 'localize_printed_scripts'], 5); remove_action('wp_print_footer_scripts', [WC_Frontend_Scripts::class, 'localize_printed_scripts'], 5); } } }
解决问题: wordpress首页并没有放woocommerce组件 页面很多woocommerce的css
速度检测网站: https://tools.pingdom.com
用CDN把JS给缓存起来, 能有效的提升网站访问速度
优化n.carlzeng.com访问速度
20260620 优化了所有照片, 剪裁尺寸到500px - 1000px (宽度最大值)
但是cloudflare缓存了之前大照片的, 大文件;
TODO: 等待cloudflare刷新缓存, 看需要耗时多久?
半小时左右还是有问题的:
0621第二天了, 用tools.pingdom.com来查询整个网址 还有1.8MB; 照片还有257kb的, 说明CDN的缓存还在生效, 怎么刷新cloudflare的cdn?
操作步骤
登录 dash.cloudflare.com ,选中你的域名
左侧菜单:Caching(缓存) → Configuration(配置)
找到 Purge Cache 区域,点击 Custom Purge(自定义清除)
可以purge特定的URL资源, 或者整个站点清除, 或者 全部清除.
开启「开发模式 Development Mode」临时禁用缓存
域名首页 Overview 页面
找到 Development Mode 开关打开(持续 3 小时)
此时所有资源直接回源,不会走 CDN 缓存,用来验证源站图片是否真的替换成功
1:15pm 已经提交过了好几分钟, 重新用浏览器还是看到了旧的图片大小内容; Monitor 要多久才能更新缓存?
0622 又是一个; purge后第二天, clashflare扯淡的, 不会刷新不回purge(用域名的方式已尝试) 重新尝试使用 URL prefix的方式 purge n.carlzeng.com/wp-content; 再一次拭目以待
9am URL访问源站点, 肯定已经清除到最新的小图片了; 开了develpment mode 持续3小时
0623 等了一天, 依旧无法刷新缓存. 验证方法
1 2 curl -I https://n.carlzeng.com/wp-content/uploads/20 26/06/image-3.png
域名 Overview 页面点击「Pause Cloudflare on Site」,完全停用 CDN 测试图片
pause后马上测试, 依旧是无法生效的, 依旧是 HIT cf-cache-status
分享媒体库中的照片 chmod 644 media-images.php
1 /volume2/KingchuxingSSD512G/docker/compose/wordpress2/wordpresshtml# vi getimages.php
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 <?php $dir = __DIR__ ;for ($i = 0 ; $i < 5 ; $i ++) { if (file_exists ($dir . '/wp-load.php' )) { require_once ($dir . '/wp-load.php' ); break ; } $dir = dirname ($dir ); } $images = get_posts ([ 'post_type' => 'attachment' , 'post_mime_type' => 'image' , 'post_status' => 'inherit' , 'posts_per_page' => -1 , ]); ?> <!DOCTYPE html> <html lang="zh-CN" > <head> <meta charset="UTF-8" > <title>案例图片 - 手柄一修哥</title> <meta name="viewport" content="width=device-width, initial-scale=1" > <!-- Cloudflare CDN: baguetteBox CSS --> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/baguettebox.js/1.11.1/baguetteBox.min.css" > <style> *{margin:0 ;padding:0 ;box-sizing:border-box} body{background: .grid{display:grid;grid-template-columns:repeat (auto-fill,minmax (180 px,1 fr));gap:15 px;margin-top:20 px} .card{background: img{width:100 %;height:140 px;object -fit:cover;display:block;background: img.lazy{opacity:0 ;transition:opacity 0.3 s} img.lazy.loaded{opacity:1 } h3 a { text-decoration: none !important; } </style> </head> <body> <h3>✅ <a href="https://w.carlzeng.com" target='_blank' >案例图库:<?php echo count ($images ); ?> 张(手柄一修哥工作室w.carlzeng.com)</a></h3> <div class ="grid " id ="gallery "> <?php foreach ($images as $img ): $img_url = wp_get_attachment_image_url ($img ->ID , 'medium '); $full_url = wp_get_attachment_image_url ($img ->ID , 'full '); ?> <div class ="card "> <a href ="<?php echo $full_url ; ?>" class ="gallery -item "> <img class ="lazy " data -src ="<?php echo $img_url ; ?>" alt =""> </a > </div > <?php endforeach ; ?> </div > <script src ="https ://cdnjs .cloudflare .com /ajax /libs /vanilla -lazyload /17.1.0/lazyload .min .js "></script > <script src ="https ://cdnjs .cloudflare .com /ajax /libs /baguettebox .js /1.11.1/baguetteBox .min .js "></script > <script > // 懒加载初始化 new LazyLoad ( { elements_selector: ".lazy" }); baguetteBox.run ('#gallery' , { animation : 'fadeIn' , noScrollbars : true }); </script> <!-- Matomo --> <script> var _paq = window._paq = window._paq || []; _paq.push (["setDocumentTitle" , document.domain + "/" + document.title]); _paq.push (["setCookieDomain" , "*.carlzeng.com" ]); _paq.push (['trackPageView' ]); _paq.push (['enableLinkTracking' ]); (function ( ) { var u="//statcounter.carlzeng.com/" ; _paq.push (['setTrackerUrl' , u+'matomo.php' ]); _paq.push (['setSiteId' , '1' ]); var d=document, g=d.createElement ('script' ), s=d.getElementsByTagName ('script' )[0 ]; g.async=true ; g.src=u+'matomo.js' ; s.parentNode.insertBefore (g,s); })(); </script> <noscript><p><img src="//statcounter.carlzeng.com/matomo.php?idsite=1&rec=1" style="border:0;" alt="" /></p></noscript> <!-- End Matomo Code --> <script defer="" src="https://umami.carlzeng.com:3/script.js" data-website-id="84261200-b106-4d11-8bc3-ad3b395a3f31" ></script> </body> </html>
修正文章中的URL地址 由于切换使用CDN等缘故, 修改源文章中的链接
Mariadb中更新
1 2 3 4 5 select * from wp_posts where post_content LIKE '%https://query.carlzeng.com:3/%' UPDATE wp_posts SET post_content= REPLACE(post_content,'https://query.carlzeng.com:3/' ,'https://query.carlzeng.com/' )
下载sqllite的数据库, 同样在数据库中更新
灵感来源与项目计划 WordPress 告别 MySQL:Docker SQLite WordPress
我写了个从 Obsidian 自动发布文章到微信公众号的工具
将 WordPress 架构成“前端静态托管(GitHub Pages)+ 后端动态处理(Docker 容器)” 是一种非常经典的 headless(无头)或 JAMstack 解决方案。由于 WordPress 本身是动态的(每次访问都查数据库),你不能直接把原本的 WordPress 代码上传到 GitHub Pages,而是需要将其静态化(Static Export) 。
实现这一架构的核心逻辑是:在本地或云服务器的 Docker 中运行完整的 WordPress 编写内容,然后通过插件将全站生成为纯 HTML/CSS/JS 静态文件并推送到 GitHub Pages;动态功能(如订单、评论、搜索)则通过 API 跨域请求你公网 IP 的 Docker 容器。
第一步:部署后端逻辑与数据库(Docker)
已有
第二步:将页面静态化并托管至 GitHub Pages
Wenprise Pinyin Slug介绍 自动转换 WordPress 中的中文文章别名、分类项目别名、图片文件名称为汉语拼音或英文翻译。
WP2Static 下载
6 Years ago: https://github.com/Premium-WP-Plugins/static-html-output-plugin/releases/tag/6.6.7
3 Years ago: https://github.com/elementor/wp2static/releases/tag/7.2
(看似官方最新的这个7.2的最新版本, 居然是会出错的!; 要用6年前的6.6.7 第三方转存的)
如何让wordpress不自动升级 wp_config.php中添加了一个设置, 等待时间的验证与核实
wordpress 如何将主页等静态页面部分利用 GitHub Pages (github.io) 进行托管展示, 而将逻辑和数据库部署在有公网IP的docker容器中
由于源站点使用了大量的照片, 可否打zip包时不包含这些照片?
方法二:使用 WP2Static 排除指定文件类型或目录
由于闲鱼的核心视觉是双列卡片瀑布流 ,以下几款主题天然具备这种布局:
优先考虑:
https://github.com/fluid-dev/hexo-theme-fluid
演示: https://fluid.ist/
1.9.9Latest7 months ago
平替 。天然具备商品卡片的厚重感。 https://github.com/blinkfox/hexo-theme-matery 演示: https://blinkfox.com/#searchModal 6年前更新
最优先尝试迁移w.carlzeng.com到 hexo的: https://github.com/blinkfox/hexo-theme-matery
原因: 样式ok, 简洁, 易搜索产品
如何快速迁移? ‘产品页’ 到 ‘文章介绍’
1 2 3 4 5 6 7 #创建并进入目录(将 my-blog 替换为你的文件夹名称): sudo hexo init w sudo npm install #要用这个sudo 不然报错 hexo server #测试
全站发布方案选择 打算push的尝试:
hexo push gitee
hexo Vercel :
表现 :自带全球 CDN,在部分地区和运营商下有节点或优选 IP,默认状态下比 GitHub Pages 略快。
现状 :其默认分配的 *.vercel.app 域名在大陆经常出现 DNS 污染或无法直接打开的问题。
创建页面和添加插件 1 2 3 4 5 6 sudo hexo new page "about" sudo npm install hexo-generator-search --save sudo npm i hexo-permalink-pinyin --save
下一步 服务产品, 导入与展示
5:47pm 确定思路, 直接使用ali的CDN, 67G多照片 有着落了, 而且速度666飞起
https://github.com/blinkfox/hexo-theme-matery 太给力了
vercel 被github默认绑定的老Email给卡住了; 备份的email没有收到验证码
发布: 1 2 3 git add . git commit -m "add: 上架一款九成新机械键盘" git push
全站照片CDN, 首页背景采用bing每日照片API自动更新
Python迁移单个CSV文件至Hexo多个MD文件 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 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 import csv import json import os import re # ================= 配置参数 ================= CSV_FILE = 'your_products.csv' # 替换为你的 CSV 文件路径 OUTPUT_DIR = '.' # Hexo 文章存放目录 # ============================================ if not os.path.exists(OUTPUT_DIR): os.makedirs(OUTPUT_DIR) def slugify(text): """生成安全的文件名,移除特殊字符,空格转连字符""" text = str(text).strip().lower() text = re.sub(r'[^\w\s-]', '', text) return re.sub(r'[-\s]+', '-', text) def ensure_https(url): """将 http 开头的图片链接转换为 https""" if url and url.startswith("http://"): return "https://" + url[7:] return url def generate_tags_by_title(title): """根据标题内容智能生成标签,且确保至少有一个标签""" tags = [] title_lower = title.lower() # 转为小写以忽略大小写匹配 # 规则 1:包含 switch 则添加 switch 标签 if 'switch' in title_lower: tags.append('Switch') if 'joycon' in title_lower: tags.append('Switch') tags.append('Joycon') # 规则 2:包含 ps5 则添加 PS5 标签 if 'ps5' in title_lower: tags.append('PS5') if 'xbox' in title_lower: tags.append('Xbox') if 'steamdeck' in title_lower: tags.append('SteamDeck') if 'Quest' in title_lower: tags.append('Quest3') # 保底机制:如果没有任何匹配项,添加一个默认标签 if not tags: tags.append('Switch') return tags def parse_item_detail(detail_str): """解析第8列的JSON字符串,提取主图和图片列表""" img = "" gallery_images = [] if not detail_str or str(detail_str).strip() == "": return img, gallery_images try: # 将文本JSON转译为Python对象 detail_obj = json.loads(detail_str) # 逐层安全获取 detail_params detail_params = detail_obj.get('detail_params', {}) if detail_params: # 提取主图 picUrl -> md中的 img raw_img = detail_params.get('picUrl', '') img = ensure_https(raw_img) # 提取图片信息(样本中它是包裹在字符串里的 JSON 数组) image_infos_raw = detail_params.get('imageInfos', '') if image_infos_raw: # 2. 第二次解析:如果是字符串格式,我们需要对它进行二次反序列化 if isinstance(image_infos_raw, str): image_infos = json.loads(image_infos_raw) else: image_infos = image_infos_raw # 3. 循环遍历提取真正图片的 url if isinstance(image_infos, list): for info in image_infos: url = info.get('url', '') if url: gallery_images.append(ensure_https(url)) except json.JSONDecodeError: print("⚠️ 警告: 发现无法解析的 JSON 文本,已略过图片解析。") except Exception as e: print(f"⚠️ 解析 JSON 时发生未知错误: {e}") return img, gallery_images def convert_csv_to_hexo(): success_count = 0 with open(CSV_FILE, mode='r', encoding='utf-8') as f: # 使用 csv.reader,这样可以直接通过数字索引拿数据 reader = csv.reader(f) # 如果你的 CSV 第一行是表头,请取消下面这行的注释来跳过表头 next(reader) for index, row in enumerate(reader): # 防止某一行列数不够导致越界报错(我们最高需要用到第8列,即索引7) if len(row) < 8: print(f"第 {index+1} 行列数不足 8 列,已跳过。") continue # 严格对应你的列位(Python 索引从 0 开始,所以第4列是索引3) item_title = row[3].strip() # 第4列 item_description = row[4].strip() # 第5列 item_price = row[6].strip() # 第7列 item_detail_str = row[7].strip() # 第8列 if not item_title: print(f"第 {index+1} 行缺失商品标题,已跳过。") continue # 解析第8列的复杂 JSON img, gallery_images = parse_item_detail(item_detail_str) # 智能提取当前文章的标签 article_tags = generate_tags_by_title(item_title) # 构造 Hexo 的 Front-matter 头部 front_matter = [] front_matter.append("---") front_matter.append(f"title: {item_title}") # 防止标题含双引号冲突 front_matter.append(f"categories: 服务商品") front_matter.append(f"date: 2026-10-29 17:59:59") front_matter.append(f"price: {item_price}") if img: front_matter.append(f"img: {img}") # 将生成的标签以 YAML 列表形式写入 Front-matter if article_tags: front_matter.append("tags:") for tag in article_tags: front_matter.append(f" - {tag}") # 如果有详情多图,以 YAML 列表形式存入 Front-matter,供主题轮播或画廊使用 # if gallery_images: # front_matter.append("images:") # for g_img in gallery_images: # front_matter.append(f" - {g_img}") front_matter.append("---\n") # 构造 Markdown 正文 md_content = [] # 1. 放入正文描述 md_content.append(item_description) md_content.append("\n---\n") # 分割线 # 2. 如果你在正文中也想把这些解析出来的图片展示出来,可以自动生成并追加 <img> 标签 if gallery_images: md_content.append("\n") # ### 商品详情图 # 配合你前面要求的“9张图完美拼接且留细缝”的样式,这里可以直接套用对应的布局容器 md_content.append('<div class="grid-container">') for g_img in gallery_images: md_content.append(f' <img src="{g_img}" title="{item_title}">') md_content.append('</div>') md_content.append("\n") md_content.append("### 想要私聊?") md_content.append("👉 点击这里跳转到[手柄一修哥]的 [真实闲鱼链接/小红书链接/微信/淘宝] 交易。") md_content.append("<div class=\"image-container\">") md_content.append("<img src=\"https://img.carlzeng.com:3/i/2026/06/image-20260605122759174.png\" alt=\"微信扫码下单\" title=\"微信扫码下单\" width=\"200\">") md_content.append("<img src=\"https://img.carlzeng.com:3/i/2026/06/image-20260605123612070.png\" alt=\"淘宝扫码下单\" title=\"淘宝扫码下单\" width=\"200\">") md_content.append("<img src=\"https://img.carlzeng.com:3/i/2026/06/image-20260605122033888.png\" alt=\"闲鱼扫码下单\" title=\"闲鱼扫码下单\" width=\"200\">") md_content.append("</div>") # 拼接完整的文章内容 full_markdown = "\n".join(front_matter) + "\n".join(md_content) # 写入 md 文件 file_name = f"{slugify(item_title)}.md" file_path = os.path.join(OUTPUT_DIR, file_name) with open(file_path, 'w', encoding='utf-8') as wf: wf.write(full_markdown) success_count += 1 print(f"成功转换第 {index+1} 行 -> {file_name}") print(f"\n🎉 处理完成!共成功处理 {success_count} 篇文章到 {OUTPUT_DIR}。") if __name__ == '__main__': convert_csv_to_hexo()
再此感谢Google的AI, 给予强大的技术支持!
个性化需求沟通 扫客服加V加群: