
简介织梦微信小程序助手2.0专为织梦CMS用户打造旨在降低微信小程序开发门槛。通过后台傻瓜式操作即可将网站新闻、产品等内容同步生成小程序适合不懂编程的站长快速拥抱移动端无论是个人站点还是企业官网都能低成本搭建。压缩包共5个文件整体仅184KB其中txt文档提供安装与更新说明xml文件保存接口及模板配置html页面可作为本地预览入口结构精简、用途明确便于快速上手。已有390人学习下载。借助该助手用户无需编写复杂代码即可完成内容同步、模板定制、一键生成代码包及后台管理还可按需扩展会员、支付等电商功能显著缩短开发周期让传统织梦站点更顺畅地接入微信生态。同时提供数据分析与版本管理功能方便运营者持续优化小程序体验。1. 织梦微信小程序助手2.0老站点做小程序先看这条最短的路织梦微信小程序助手2.0一句话概括就是在不重建站的前提下把织梦CMSDedeCMS里的栏目和文章通过一层JSON接口喂给微信小程序端让小程序以原生页面展示内容。很多做企业站、资讯站、地方门户的站长手里都压着织梦老站内容不少、权重也有就是缺一个能跑的移动端入口这套方案的价值就是把这部分存量内容变成小程序的骨架避免“为了一个小程序再搭一套后台”的重复投入。适合谁正在用织梦维护内容、又想低成本上线小程序的站长或外包开发者。不需要动织梦的模板不需要换数据库只要PHP环境正常就能在现有的站点目录里加几个接口文件再写一个小程序前端。下文会把这套方案从数据原理一直拆到参数配置和踩坑记录尽量让新手照着也能跑通。2. 数据怎么从织梦流进小程序栏目树、文章表、JSON出口2.1 织梦不是黑匣子先看懂它是怎么存文章的织梦装了之后MySQL里会多出几十张表日常使用中真正要关心的只有三张dede_arctype是栏目表靠id和reid两个字段维护父子层级reid为0的是顶级栏目dede_archives是文档主表存标题、缩略图、发布时间、摘要和审核状态dede_addonarticle是文章附加表通过aid关联主表的id正文那一大坨HTML就存在这张表的body字段里。小程序端不认织梦的模板标签也不该直接连数据库。常见的做法是在织梦站点里加一层PHP接口用织梦自带的common.inc.php完成初始化拿到$dsql数据库对象后直接查这三张表拼成JSON返回给小程序。织梦微信小程序助手2.0比1.x时代更强调的是这个“接口层”的价值1.x经常用web-view套网页体验和加载速度都一般2.0的思路上来就做原生页面用API喂数据交互顺畅很多也更容易过微信审核。2.2 小程序端的真实诉求不是整站搬家是一个可浏览的内容API有些站长一开始就想要“小程序里跟电脑站一模一样”这其实是误解。微信小程序对包体积有2MB限制页面栈有限富文本渲染靠rich-text组件它只认节点数组或HTML字符串且不执行任何JavaScript。换句话说把织梦整个站搬过去既不现实也没必要用户在小程序里要的是看到栏目、看到文章列表、点进去能读正文。所以助手2.0这类方案真正要解决的问题只有四个栏目怎么分、列表怎么分页、详情怎么取、正文里的图片怎么正常显示。这四个问题全部可以在接口层解决小程序端只是拿到JSON后渲染而已。理解这一点就不会被“小程序开发很复杂”的舆论吓住也不会反方向去造一个和织梦并行的内容后台——那是得不偿失的做法。2.3 自建API还是装插件2.0时代的主流选型市面上确实有一些织梦小程序插件后台能配置栏目映射、自动生成API文档用起来省事。但插件的问题在于字段是写死的想加一个“阅读量排序”或“按关键字搜索”就得等作者更新二次开发的自由度很低。自建API则相反代码量不大但每个字段、每个查询都能自己控制遇到问题也能直接改。我对中小型资讯站的一贯建议是自建。原因很现实织梦本身已经停止官方更新很久了生态里的第三方插件质量参差不齐装一个来路不明的插件反而可能给老站带来安全风险。自建接口只需要PHP基础动手写一遍之后对织梦的数据结构也熟了后续调整栏目、加字段、接搜索都不求人。这套思路也贯穿下面所有代码。3. 自己写一套织梦JSON接口分类、列表、详情三步跑通3.1 先搭接口骨架在织梦站点目录下新建独立接口目录常见的做法是在织梦站点根目录下建一个weapp目录专门放小程序接口文件。这样做有两个好处一是和织梦后台文件分离方便排查和备份二是在配置伪静态规则或域名白名单时可以直接针对这个目录放行不影响主站。第一步就是创建目录并放一个最简单的接口文件验证织梦环境能正常初始化?php // /weapp/ping.php —— 接口连通性测试 define(DEDEINC, str_replace(\\, /, dirname(__FILE__)) . /include); require_once(DEDEINC . /common.inc.php); header(Content-Type: application/json; charsetutf-8); echo json_encode([ code 0, msg weapp api ready ], JSON_UNESCAPED_UNICODE);这段代码做了两件事通过DEDEINC常量定位织梦的include目录再引入common.inc.php完成数据库连接和全局初始化。$dsql对象就是织梦的数据库操作入口后面所有查询都用它。在浏览器里访问https://你的域名/weapp/ping.php如果看到{code:0,msg:weapp api ready}就说明接口骨架已经通了。这一步卡住的人多半是路径问题。有些织梦站是装在子目录里的DEDEINC就要写成dirname(__FILE__) . /子目录/include另外PHP版本过高时common.inc.php里部分写法会报警告建议在站点入口处把错误显示关掉接口统一只输出JSON避免调试信息污染前端解析。3.2 列表接口栏目过滤、分页、缩略图一次返回列表接口是小程序首页和栏目页的数据来源核心SQL从dede_archives主表取数按时间倒序支持typeid过滤。下面这段是完整的列表接口?php // /weapp/list.php —— 文章列表接口 define(DEDEINC, str_replace(\\, /, dirname(__FILE__)) . /include); require_once(DEDEINC . /common.inc.php); header(Content-Type: application/json; charsetutf-8); $typeid isset($_GET[typeid]) ? intval($_GET[typeid]) : 0; $page isset($_GET[page]) ? max(1, intval($_GET[page])) : 1; $pagesize 12; // 每页条数资讯站建议10-12 $offset ($page - 1) * $pagesize; // 按栏目过滤时只查当前栏目typeid0表示全站最新 if ($typeid 0) { $sql SELECT id, typeid, title, litpic, pubdate, description FROM #__archives WHERE typeid $typeid AND arcrank 0 ORDER BY id DESC LIMIT $offset, $pagesize; } else { $sql SELECT id, typeid, title, litpic, pubdate, description FROM #__archives WHERE arcrank 0 ORDER BY id DESC LIMIT $offset, $pagesize; } $dsql-SetQuery($sql); $dsql-Execute(); $list []; while ($row $dsql-GetArray()) { $row[pubdate] date(Y-m-d, $row[pubdate]); $row[litpic] str_replace({style}, , $row[litpic]); // 清除织梦标签残留 $list[] $row; } echo json_encode([ code 0, page $page, has_more count($list) $pagesize, // 按是否取满一页判断是否有下一页 list $list ], JSON_UNESCAPED_UNICODE);这里的#__是织梦的表前缀占位符实际执行时会替换成配置里的前缀常见是dede_。arcrank 0是审核状态过滤0表示正常发布-1是待审核-2是回收站这个条件必须带上否则小程序里会出现草稿和已删除内容。litpic字段偶尔会混入{style}这种模板残留值用str_replace清理掉避免小程序端图片链接带花括号。分页判断用count($list) $pagesize而不是再查一次总数因为对小程序“上拉加载更多”的场景来说只需要知道“还有没有下一页”这个判断在数据量大时性能更好。如果一页刚好取满前端就会认为可能还有下一页再触发一次请求也不算错。3.3 详情接口join内容表顺便把正文清洗干净详情页的难点在于dede_addonarticle里的body字段是一整段HTML里面有织梦自带的{dede:}标签、站内相对路径图片甚至还有空行和样式残留。小程序rich-text组件可以直接渲染HTML字符串但前提是这段HTML是干净的。详情接口在返回前必须做两件事去掉织梦标签残留、把图片路径补成完整域名。?php // /weapp/detail.php —— 文章详情接口 define(DEDEINC, str_replace(\\, /, dirname(__FILE__)) . /include); require_once(DEDEINC . /common.inc.php); header(Content-Type: application/json; charsetutf-8); $id isset($_GET[id]) ? intval($_GET[id]) : 0; if ($id 0) { http_response_code(400); echo json_encode([code 1, msg id参数缺失]); exit; } $sql SELECT a.id, a.typeid, a.title, a.litpic, a.pubdate, a.description, b.body FROM #__addonarticle b INNER JOIN #__archives a ON a.id b.aid WHERE a.id $id AND a.arcrank 0 LIMIT 1; $dsql-SetQuery($sql); $dsql-Execute(); $row $dsql-GetArray(); if (!$row) { http_response_code(404); echo json_encode([code 1, msg 文章不存在]); exit; } $row[pubdate] date(Y-m-d H:i, $row[pubdate]); // 清理织梦模板引擎残留标记 $row[body] preg_replace(/\{dede:.*?\}/is, , $row[body]); // 把站内图片相对路径补全为https绝对路径防止小程序里图片裂开 $row[body] preg_replace(/src\/(uploads|images)\//i, srchttps://你的域名/$1/, $row[body]); echo json_encode([code 0, data $row], JSON_UNESCAPED_UNICODE);这段代码里的JOIN是关键织梦的文章内容不在主表里只查dede_archives永远拿不到正文。b.aid a.id是两张表的关联条件如果站点启用了多图或独立模型表名会变成dede_addonxxx需要根据后台的模型名调整。preg_replace清洗正文时正则\/\{dede:.*?\}/is覆盖了所有形如{dede:field.name/}的标签这是织梦模板最常见的残留物。图片路径补全这步不能省。织梦后台如果填的是/uploads/allimg/2401/xxx.jpg小程序端拿到的就是相对路径真机上会因无法解析而裂图。替换时注意域名前缀一定是https://微信小程序不支持明文HTTP。如果你的站点用了七牛、OSS这类第三方存储路径前缀又不一样按实际情况改正则即可。3.4 小程序端对接request封装、下拉刷新、触底加载接口就绪后小程序端的对接反而是体力活。列表页的数据请求、分页累加、触底加载这三件事必须同时处理否则就会出现“翻页后数据被清空”或“重复请求”的问题。下面是一个标准的列表页脚本// pages/list/list.js Page({ data: { typeid: 0, page: 1, articles: [], hasMore: true, loading: false }, onLoad(options) { // 栏目页传入typeid首页默认全站 if (options.typeid) { this.setData({ typeid: Number(options.typeid) }); } this.loadArticles(true); }, loadArticles(reset false) { if (this.data.loading) return; // 防止重复触发 const page reset ? 1 : this.data.page 1; this.setData({ loading: true }); wx.request({ url: https://你的域名/weapp/list.php, data: { typeid: this.data.typeid, page }, success: (res) { const data res.data; if (data.code 0) { const articles reset ? data.list : this.data.articles.concat(data.list); this.setData({ articles, page, hasMore: data.has_more, loading: false }); } }, fail: () { this.setData({ loading: false }); wx.showToast({ title: 加载失败, icon: none }); } }); }, onReachBottom() { if (this.data.hasMore) { this.loadArticles(false); } }, onPullDownRefresh() { this.loadArticles(true).then(() wx.stopPullDownRefresh()); } });这段代码的逻辑是reset为true时从第一页重新拉数据用于下拉刷新触底时用当前页1去拉下一页成功后再concat追加。注意loading标志位必须加否则用户快速滚动时会同时发出多个请求列表顺序会错乱。列表页的WXML渲染建议用wx:for配合wx:keyid图片用modeaspectFill裁切摘要字段直接展示description它本身是从正文里截取的一段纯文本适合做列表摘要。下面是列表项和详情页的渲染片段!-- pages/list/list.wxml 列表项核心结构 -- view classarticle-item wx:for{{articles}} wx:keyid bindtapgoDetail>// 递归获取当前栏目及所有子栏目ID function get_child_typeids($dsql, $typeid) { $ids [$typeid]; $dsql-SetQuery(SELECT id FROM #__arctype WHERE reid $typeid); $dsql-Execute(); while ($row $dsql-GetArray()) { $ids array_merge($ids, get_child_typeids($dsql, $row[id])); } return $ids; } // 使用时把SQL里的typeid条件替换为 $typeid_list get_child_typeids($dsql, $typeid); $typeid_sql implode(,, $typeid_list); // WHERE typeid IN ($typeid_sql) AND arcrank 0递归层数要限制我一般控制在三层以内防止站点栏目结构太深导致查询变慢。如果栏目只有两级直接用一条reid IN子查询也能替代但递归写法对任意层级都通用值得保留。4.3 开启伪静态后接口文件被规则吞掉现象织梦后台开启了伪静态Apache的mod_rewrite或Nginx的try_files小程序接口在电脑上打开正常一到小程序里就报“request:fail url not in domain list”或直接404。原因伪静态规则通常会把所有不带真实文件名的请求全部rewrite到index.php如果规则写得比较宽/weapp/list.php这种以.php结尾的真实路径也会被拦截导致接口返回织梦的404页面。更隐蔽的情况是Nginx的location ~ \.php$规则里没放行/weapp/目录PHP请求被扔给了静态文件处理逻辑。解决在伪静态规则里把/weapp/目录单独放行。Apache的.htaccess在RewriteRule前加一条RewriteCond %{REQUEST_URI} !^/weapp/Nginx则在server块里的PHP location前加入location ^~ /weapp/ { include fastcgi_params; fastcgi_pass unix:/tmp/php-cgi.sock; # 根据实际环境改 fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; }判断是不是这个原因的方法很直接用浏览器访问接口文件加上一个不存在的参数如果返回的是织梦的HTML错误页而不是JSON说明请求根本没进PHP接口。此时直接在服务器上curl一下接口地址看返回体就能确认。4.4 接口时通时不通原来是被session和登录态拖住现象小程序端调用列表接口有时候几秒就返回有时候卡到超时偶尔还会出现不同用户看到不同数据的情况。原因织梦的common.inc.php初始化时会启动会话机制并加载会员状态如果站点启用了会员功能接口每次执行都可能触发session_start()和用户表查询。小程序端在并发请求时同一时间多个页面请求接口PHP的session文件锁会让请求排队表现就是时通时不通。另外如果接口文件放在织梦后台能访问的目录下还可能被后台的登录校验逻辑拦截。解决这套方案里接口只做内容读取不需要用户登录态所以我在接口文件里在引入common.inc.php之前先声明不启动session同时把接口放到独立子域名比如api.你的域名.com只允许通过微信小程序访问。如果不想上子域名也可以在Nginx层面对/weapp/目录单独配置一个不带session的PHP-FPM池但这样成本略高。实际中最快的缓解手段是接口文件顶部加上if (session_status() PHP_SESSION_ACTIVE) { session_write_close(); // 释放会话锁 }这个改动对性能提升立竿见影微信小程序请求默认不带Cookie这些接口本身就“不认识”用户干脆跳过所有会员态才是正确的姿态。血泪经验是不要为了省事把织梦后台的管理员session校验逻辑复制到接口里否则小程序审核时容易被判定为“强制登录才能使用”。4.5 微信审核被拒先检查这三样别急着申诉现象小程序提交审核后被微信以“页面内容为空”或“功能不完整”为由驳回有些资讯站还被提示“涉及信息发布但无相关资质”。原因审核被拒的原因绝大多数不在代码而在内容。列表页如果默认typeid0且站点尚没有文章审核员打开就是空页面详情页如果rich-text渲染失败也会被当成“功能不完整”。更麻烦的是织梦老站经常有一些分类叫“行业资讯”“合作伙伴”审核员点进去看到一堆空白或重复内容就会被判定为低质。解决提交审核之前用游客视角把小程序完整走一遍从首页列表点进详情正文图片必须显示完整底部不能有“联系客服加微信”这类诱导性按钮栏目页必须有至少五条真实内容有搜索功能的搜索空结果要展示友好提示。如果站点内容偏少建议先只在后台发布十篇以上高质量文章再提审。审核被拒后不要急着申诉先按驳回理由把空页面补上内容再重新提审成功率更高。5. 织梦助手2.0必调参数分页、图片、缓存与超时的推荐值5.1 织梦端SQL查询、栏目递归、图片尺寸接口性能的瓶颈几乎都在织梦端的SQL查询上。列表接口的分页数不建议超过15条移动端屏幕一次展示不了太多拉太长反而增加小程序内存压力。详情接口的JOIN查询很轻但要注意LIMIT 1必须写防止同一个ID存在多条附加记录时查出重复数据。栏目递归层数上面提过控制在三层以内如果站点很深改成在织梦后台把栏目结构压平对维护也是好事。图片尺寸这块织梦后台的缩略图默认是按原图尺寸生成的很多老站直接上传了3MB的大图小程序列表页加载起来非常慢。常见做法是在列表接口里对litpic做处理或者在上传时就在织梦后台的“系统基本参数→图片设置”里把缩略图宽度设成750px。750px正好是iPhone的物理像素宽度列表页用2倍屏显示也不会模糊高度按4:3裁切UI上比较协调。5.2 微信公众平台request合法域名、业务域名、HTTPS这一步参数配错小程序开发者工具里调试没问题真机上却会被挡住。在微信公众平台后台“开发管理→开发设置→服务器域名”里要配置request合法域名填入接口所在的域名必须是HTTPS且已备案。如果你的接口域名和网页里用到的域名不一致还要在“业务域名”里一并加上否则rich-text里偶尔出现的网页跳转会被拦截。HTTPS证书别贪便宜小程序对证书链的要求很严有些免费证书在Android低版本机型上会握手失败。我一般直接用云厂商的一年期证书配合Nginx配置HTTP/2接口请求的耗时能显著下降。域名数量也是坑request合法域名最多能配20个如果你既有主站的图片域名、又有API子域名、还有CDN域名数一数很容易超提前规划好。5.3 小程序端请求超时、缓存策略、token时效小程序端的wx.request默认超时是60秒对移动网络来说太长。推荐设置成10秒配合失败重试一次的策略用户体验最稳。列表数据建议缓存到本地缓存Storage我在书籍类、资讯类小程序里一般用wx.setStorageSync做一个“先展示缓存、再静默拉新”的策略用户第二次打开首页时不用白屏等接口。token时效这个参数只在你后续接入评论、点赞这类需要用户身份的功能时才需要。微信小程序没有传统意义上的session常见做法是用wx.login拿code在后端换成openid再签发一个有效期2小时的token存在Storage里过期后静默重新登录即可。不建议为了省事把token有效期设成30天一旦泄露就有刷接口的风险。参数项推荐值说明列表分页数量10-12条/页移动端一屏半高度加载体验最好列表缓存TTL600秒织梦端文件缓存或Redis缓解MySQL压力接口请求超时10秒wx.request的timeout设置token有效期2小时需要用户态时使用过期静默刷新详情正文缓存24小时文章不常改详情接口可做页面级缓存缩略图宽度750px适配2倍屏列表页不乱码缓存策略上织梦端我一般用文件缓存不用Redis因为老站大多是虚拟主机装不了Redis插件。一个简单做法是在/weapp/cache/目录下写JSON文件接口运行时先检查缓存文件是否在TTL内在就直接读文件不在才查数据库。注意缓存目录要加权限保护避免被Web访问到。6. 进阶用法把资讯站做成“书架式”小程序离线也能读如果你维护的是类似“织梦图书馆”这种以书目、文档、文章摘录为主的内容站列表页做成简单的feed流有点浪费。书架式布局更适合这类站点每个栏目像一格书架书架里摆着文档封面和标题用户点进去直接读全文。实现起来不复杂列表接口已经返回了litpic和title小程序端只需要把数据重新分组// pages/shelf/shelf.js const groupByType (articles) { const map {}; articles.forEach(item { const key item.typeid; if (!map[key]) map[key] []; map[key].push(item); }); return Object.keys(map).map(key ({ typeid: Number(key), list: map[key] })); };离线阅读是这类内容站最能提升好评的功能。织梦的文章更新频率不高完全可以把已读过的详情页正文缓存到本地下次无网络时直接读取。做法是在详情页请求成功后写入缓存onLoad时先读缓存再发请求const detail wx.getStorageSync(article_ id); if (detail) { this.setData({ body: detail.body }); } wx.request({ /* 请求详情接口成功后更新缓存 */ });我第一版做小程序时没做缓存用户每次打开详情都要转圈等接口在弱网环境几乎不可用后来花了半天补上这层用户反馈明显改善。现在我对所有织梦类小程序都默认要求“列表可缓存、详情可离线”这个习惯直接提升了留存率。书架式的视觉配合离线缓存用户甚至会以为你专门做了一个App——其实后端还是那套织梦接口还是那两个PHP文件。希望这个方案能帮你把手里的织梦老站盘活少走几步弯路。本文还有配套的精品资源点击获取