用自定义短代码重建Divi博客一份现场报告

博客列表和帖子详细信息页面的重新设计第6版,一个在Cloudways上运行WordPress + Divi的健身健康平台。这与其说是一篇"看看漂亮的结果"的文章,不如说是一篇诚实的关于架构决策和错误的文章,这些错误教会了我一些东西------包括花费了一个周六的大部分时间并且与代码完全无关的那篇。

起点

Rev6的博客需要一个完整的视觉和结构检修:一个适当的编辑列表页面,带有类别侧边栏、排序和卡片网格,加上一个干净的以阅读为重点的详细页面,带有作者栏、作者简历和相关帖子。该网站是建立在Divi儿童主题之上的,所以第一个明显的问题是是否依赖Divi的内置博客模块。

我没有。Blog模块对于一般的列表来说很好,但是它没有满足这个项目实际需要的东西:基于URL的类别路由、定制卡片标记和会员感知的帖子处理。与页面生成器对抗以产生非默认标记是一场失败的游戏------你最终会得到一堆覆盖,这些覆盖会在下一次Divi更新时中断。所以列表和细节页面是由子主题中的自定义短代码的小系统驱动的inc/rev6-blog-functions.php,由单个assets/rev6-blog.css,并在Divi的主题生成器中组装。

短码系统

整个前端由几个集中的短代码组成:

rev6_blog_sidebar---类别导航、搜索、品牌推广

rev6_sort_dropdown---排序控制

rev6_post_grid---卡片网格

rev6_author_bar---详细页面上的署名

rev6_author_bio---作者阻止在帖子的底部

rev6_related_posts---"继续阅读"部分

将每一部分都保留为自己的短代码意味着主题构建器模板只是一个很薄的组装层------一个代码模块,短代码按照它们应该呈现的顺序排列------所有的逻辑都保留在版本化的PHP中,而不是锁定在页面构建器的数据库中。

每个类别一个模板

列表方面的巧妙之处在于,单个主题构建器模板既服务于主博客索引,也服务于每个类别归档。post网格读取查询上下文并自行过滤:

$current_id = is_category() ? (int) get_queried_object_id() : null;

// ...

if (is_category()) {

$args'cat' = (int) get_queried_object_id();

}

将模板分配给Pages → Blog和Categories → All Category Pages,同样的标记在任何地方都会产生正确的结果。在索引上你可以看到所有的帖子;在/category/longevity/网格把自己的范围扩大到长寿。没有每个类别的模板,没有重复。

编辑布局和一个27000像素的bug

列表页面使用命名区域CSS网格:一个横跨整个高度的粘性边栏,排序控件、卡片网格和分页堆叠在主栏中。

.rev6-blog-layout {

display: grid;

grid-template-columns: var(--rev6-sidebar-w) 1fr;

grid-template-rows: auto 1fr auto;

grid-template-areas:

"sidebar sort"

"sidebar grid"

"sidebar pagination";

column-gap: var(--rev6-gutter);

row-gap: 28px;

}

这是2.2版的布局。v2.1有一个真正有趣的bug。为了让侧边栏覆盖整个内容的高度,我使用了grid-row: 1 / span 999---"跨越一切"的懒惰举动。问题是:span 999不限制实际行数。它产生大约996英镑幽灵内容下面的隐式行,并且每一行都继承了28pxrow-gap。结果是分页下面大约有27,888px的死空格。解决方法是停止懒惰,定义一个带有命名区域的显式三行网格,让侧边栏占据一个跨越实际存在的行的命名区域。教训:span <big number>是网格布局中的代码味道;说出你的区域。

详细信息页面

帖子详细信息模板由四部分组成:帖子标题、作者栏、帖子内容(带有rev6-single-content排版课程)、作者简介和相关文章。

排版是通常的编辑设置------深蓝色的机器人衬线标题(#1d5280),一身藏青色(#232a43),大的行高,可读性的约束措施。作者系统是定制的:主题在用户编辑屏幕上注册了一个"Rev6作者简介"部分,有专门的角色和简历字段,作者照片来自简单的本地头像,而不是依赖WordPress的原生简历字段。

related-posts块很小,但值得展示,因为它成了与代码无关的调试会话的核心:

function rev6_related_posts($atts) {

atts = shortcode_atts(\['count' =\> 3\], atts);

if (!is_single()) return '';

$cat = rev6_primary_category();

if (!$cat) return '';

$q = new WP_Query([

'post_type' => 'post',

'posts_per_page' => (int) $atts'count',

'post_status' => 'publish',

'cat' => (int) $cat->term_id,

'post__not_in' => get_the_ID(),

'ignore_sticky_posts' => 1,

'orderby' => 'date',

'order' => 'DESC',

]);

if (!$q->have_posts()) return '';

// ...render cards...

}

它从当前的帖子中拉出多达三个帖子主要的类别,不包括当前类别。主要类别解析是防御性的,它更喜欢Yoast指定的主要术语,但如果该术语不再存在,它会优雅地退回:

function rev6_primary_category($post_id = null) {

post_id = post_id ?: get_the_ID();

if (function_exists('yoast_get_primary_term_id')) {

term_id = yoast_get_primary_term_id('category', post_id);

if ($term_id) {

term = get_term(term_id, 'category');

if (!is_wp_error(term) \&\& term) return $term;

}

}

cats = get_the_category(post_id);

return !empty(cats) ? cats0 : null;

}

不是的"错误"

在直播网站上,相关帖子部分拒绝在旗舰帖子上呈现。代码看起来是正确的。我已经确认了这些类别的存在。窃听器在哪里?

根本没有。该类别已存在,但已过时空的------唯一一个被指定为"长寿"的帖子正是正在被浏览的帖子。post__not_in排除它,查询返回零个结果,并且函数做了它应该做的事情:返回一个空字符串。当我给这个类别分配第二个帖子的时候,"继续阅读"立刻出现了。

这是一个重复出现的陷阱,具有内容驱动的特征:功能是正确的,数据是不完整的,症状看起来像代码失败。在调试查询之前,检查它是否有要查询的内容。

切换:代码和布局移动,内容不动

最昂贵的一课发生在从准备到运行的迁移过程中,这也是我最想让过去的自己内在化的一课。

我将主题文件推送到live,并从staging导入Divi主题构建器模板。一切应该已经匹配。事实并非如此------详细页面的正文放在了错误的位置,相关的文章不见了,www.jpbara.com侧边栏看起来很薄。我的直觉是继续在live上编辑CSS以强制匹配。那种直觉是错误的,而且要花好几个来回。

实际问题是:导入移动代码和布局。他们不移动内容。

主题文件(.css, .php)进行演示和逻辑。

Divi主题生成器导出携带模板结构---节、模块、CSS类。

两者都不携带帖子、类别,也不知道哪个帖子属于哪个类别。这些是数据库行。

因此,staging和live之间的主体宽度差异根本不是CSS问题------宽度是在Divi模块的Design选项卡上设置的,该选项卡位于数据库中,而不是样式表中。空的related-posts块不是代码问题------类别到帖子的分配从来没有在live上重新创建过。我一字不差地复制了样式表,但两种环境仍然存在差异,这是最明显的信号,表明差异存在于样式表无法触及的地方。

一旦你内化了这种分裂---文件和模板是外壳;数据库就是内容------"我导入了它,但它是不同的"这一类问题在几秒钟内就可以诊断出来,而不是在CSS中调试一个小时。

这是一个必然的结果,它让我们付出了惨痛的代价,并在这里提出了一个警告:永远不要通过将数据库全面推向生产来解决临时/实时差异。完整的数据库同步会覆盖live的真实数据---订单、注册、用户自快照以来创建的所有数据。使用目标文件副本,在数据确实必须移动的地方,使用限定了范围的表级操作。一键"推送一切"的便利,抵不上它能抹去的东西。

缓存会骗你

另一个值得命名的环境小鬼:激进的CSS优化。Cloudways的Breeze with"Used CSS"(RUCSS)去除了它在生成优化样式表时没有检测到的选择器。如果一个模板在缓存构建时不存在,那么完全正确的规则是---list-style: none分页、容器宽度、图标字体------被删除后,你会得到部分的样式:一些规则适用,另一些规则消失。部分应用是一个信号。完全缺失的样式表看起来不同于半应用的样式表。

解决方法不是去碰CSS这是为了在任何模板更改后清除并重新生成使用过的CSS,并且如果相关的选择器不断被剥离,则从优化中排除它们。在一个优化的WordPress站点上调试CSS时,清除缓存是第0步,而不是第10步。

外卖食品

不要和页面生成器作对。如果您需要非默认标记或自定义查询逻辑,请在版本化的PHP中拥有它,并让构建器进行组装。

命名你的网格区域。span 999会想办法让你难堪。

空数据上的正确函数看起来和坏函数一样。先查数据。

文件和模板是外壳;数据库就是内容。大多数"我迁移了它,但它是不同的"错误存在于这两者之间。

永远不要将数据库一刀切地推向生产。

在一个优化的WordPress堆栈上,在你相信你看到的任何东西之前,清空缓存。

重新设计的内容包括:编辑列表页面,具有上下文感知的类别路由,一个清晰的以阅读为中心的详细页面,一个工作的作者系统,以及从类别数据中填充的相关文章。代码是最简单的部分。环境就是老师。