WordPress 主题的 functions.php:往里面写什么,什么时候该停
functions.php 是我见过最容易长成垃圾桶的文件。 主题目录里它算特殊:WordPress 加载主题时会自动 include 它,不需要任何钩子。所以什么都往里塞都能跑。跑得起来,就没人管它该不该在这儿。 它最常见的四个用途 按我
functions.php 是我见过最容易长成垃圾桶的文件。
主题目录里它算特殊:WordPress 加载主题时会自动 include 它,不需要任何钩子。所以什么都往里塞都能跑。跑得起来,就没人管它该不该在这儿。
它最常见的四个用途
按我经手的主题看,大致是这四类:
- 注册主题支持的功能,
add_theme_support() - 注册菜单、侧栏,
register_nav_menus()、register_sidebar() - 挂载样式和脚本,
wp_enqueue_style()、wp_enqueue_script() - 写主题自己的小函数,然后
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 行,里面有订单计算、会员等级判断、优惠券核销。
最要命的是这东西跟主题绑死了。客户想换个外观,等于把整个业务系统推倒。
那次的处理方式是把业务逻辑整体抽成一个插件,主题只留展示层。做了四天。
当初写这些逻辑的人可能只花了两小时。