WordPress 主题的 functions.php:往里面写什么,什么时候该停

· wordpress · 阅读 14
摘要

functions.php 是我见过最容易长成垃圾桶的文件。 主题目录里它算特殊:WordPress 加载主题时会自动 include 它,不需要任何钩子。所以什么都往里塞都能跑。跑得起来,就没人管它该不该在这儿。 它最常见的四个用途 按我

functions.php 是我见过最容易长成垃圾桶的文件。

主题目录里它算特殊:WordPress 加载主题时会自动 include 它,不需要任何钩子。所以什么都往里塞都能跑。跑得起来,就没人管它该不该在这儿。

它最常见的四个用途

按我经手的主题看,大致是这四类:

  1. 注册主题支持的功能,add_theme_support()
  2. 注册菜单、侧栏,register_nav_menus()、register_sidebar()
  3. 挂载样式和脚本,wp_enqueue_style()、wp_enqueue_script()
  4. 写主题自己的小函数,然后 add_action() 挂上去

前两类是「声明」,本质是告诉 WordPress「我这个主题支持这些东西」。这类调用应该集中放在文件开头,一眼看全。

第三类有个必须遵守的规则:不能直接 echo 一个 <link> 到 wp_head 里。

enqueue 和直接写的区别

我见过太多主题这么干:

add_action('wp_head', function() {
    echo '<link rel="stylesheet" href="' . get_template_directory_uri() . '/style.css">';
});

能显示,页面也正常。但后果是:

  • 插件想管理这个样式的加载顺序,管不了,因为它不在队列里
  • 缓存合并、CDN 替换、生产环境压缩,几乎全部依赖 enqueue 队列,直接 echo 的会被漏掉
  • 同一个样式可能被加载两次——插件也 enqueue 了,你的 echo 又输出一遍

正确写法:

add_action('wp_enqueue_scripts', function() {
    wp_enqueue_style('my-theme-style', get_stylesheet_uri(), array(), '1.0.0');
});

get_stylesheet_uri() 返回当前主题 style.css 的地址,子主题场景下自动指向子主题。写死路径的话,做成子主题就指向错了。

那第四个参数 '1.0.0' 是版本号,作用是拼在 URL 后面 ?ver=1.0.0。浏览器缓存靠它更新,不写或者不更新版本号,改了 CSS 用户看不到。

子主题的时候,这件事必须做

如果这个主题可能被用作父主题,functions.php 里加载样式必须走 get_stylesheet_uri()。

原因:get_template_directory_uri() 永远指向父主题,get_stylesheet_directory_uri() 永远指向当前激活的主题。子主题激活时,前者还是父主题目录。

用错了,子主题改了 CSS 不生效,因为加载的还是父主题那份。这算经典故障了。

什么时候该停手

判断标准挺简单的:这段代码换一个主题还成立吗?

成立,就该进插件。不成立,才留在 functions.php。

举例:

  • 注册一个自定义文章类型 —— 换主题也该有,进插件
  • 给文章加一个阅读时长的计算 —— 内容属性,进插件
  • 给主题加一个「是否显示作者」的开关 —— 主题能力,留在主题
  • 往 head 里加统计代码 —— 跟主题无关,进插件或用现成插件

我把这条讲给过几个刚学主题的人,反应普遍是「那我这一半都得搬走」。对,确实得搬。

搬走的好处不是洁癖。是换主题那天——你换过就知道,几百行东西跟着旧主题一起被废掉,重新在 functions.php 里再写一遍是什么感觉。

文件太长就拆

官方没有要求 functions.php 必须是一个文件。超过两三百行,我会拆开:

inc/
  setup.php
  enqueue.php
  template-tags.php
  customizer.php

然后在 functions.php 里统一引入:

foreach (glob(get_template_directory() . '/inc/*.php') as $file) {
    require_once $file;
}

一句话解决,以后加文件不用改这行。

注意 glob() 返回的顺序不保证,如果文件之间有依赖(比如 setup.php 里定义的常量被 enqueue.php 用),得手工列出来。我有一次栽在这,本地开发环境顺序对,上了服务器顺序变了,直接报常量未定义。

最后一条:别在 functions.php 里写业务逻辑

我接手过一个主题,functions.php 有 1800 行,里面有订单计算、会员等级判断、优惠券核销。

最要命的是这东西跟主题绑死了。客户想换个外观,等于把整个业务系统推倒。

那次的处理方式是把业务逻辑整体抽成一个插件,主题只留展示层。做了四天。

当初写这些逻辑的人可能只花了两小时。