需求背景

在 Avada 子主题开发中,经常需要把不同业务功能拆分到独立文件,例如轮播图短代码、特色产品模块、推荐设备模块、应用场景短代码、TablePress PDF 下载短代码等。把这些文件统一放到子主题目录,再在 functions.php 中集中引入,可以让代码结构清晰、便于维护。

但这里有两个必须解决的安全与规范问题:

  1. 被引入的子文件如果被浏览器直接访问,可能暴露代码或触发意外执行,必须加防护。
  2. 多个文件集中引入时,检查代码写在哪里、会不会互相冲突,需要明确规则。

本手册给出可直接落地的写法,覆盖需求、执行步骤和最终效果。

核心结论先看

  • functions.php 顶部要加一次 ABSPATH 检查。
  • 每一个被 require_once 引入的子文件开头也要各加一次 ABSPATH 检查。
  • 每个文件都加不会冲突,因为这段代码只是条件判断加 exit,不涉及函数或类重复定义。
  • 真正需要防的冲突是函数名、类名、常量名重复,与 ABSPATH 检查无关。

防护代码的作用

防护代码如下:

1
2
3
if ( ! defined( 'ABSPATH' ) ) {
exit;
}

ABSPATH 是 WordPress 核心加载时定义的常量。正常通过 WordPress 访问时它存在,检查通过,代码继续执行。如果有人直接访问某个 PHP 文件路径,ABSPATH 未定义,脚本立即 exit,从而阻止文件内逻辑被直接执行。

这段代码不是函数定义、不是类定义、不是常量声明,所以多个文件各写一份不会产生重复定义错误。

落地执行步骤

第一步 确认子主题目录结构

子主题目录中应包含 functions.php 和各个子功能文件,例如:

1
2
3
4
5
6
7
8
avada-child/
├── functions.php
├── lier-slider-shortcode.php
├── lier-inc-featured-products.php
├── get_page_link_shortcode.php
├── lier-recommended-equipment.php
├── lier-application-scenario-shortcode.php
└── tablepress-pdf-download-shortcode.php

第二步 修改 functions.php

在 functions.php 最顶部先写防护检查,再写 require_once 引入列表。正确写法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
// 防止直接访问文件
if ( ! defined( 'ABSPATH' ) ) {
exit;
}

// 引入制冰机轮播图短代码模块
require_once get_stylesheet_directory() . '/lier-slider-shortcode.php';
require_once get_stylesheet_directory() . '/lier-inc-featured-products.php';
require_once get_stylesheet_directory() . '/get_page_link_shortcode.php';
require_once get_stylesheet_directory() . '/lier-recommended-equipment.php';
require_once get_stylesheet_directory() . '/lier-application-scenario-shortcode.php';
require_once get_stylesheet_directory() . '/tablepress-pdf-download-shortcode.php';

注意:防护检查必须放在 require_once 之前,不能放在列表后面。放在后面时,被引入的文件已经执行完毕,检查失去意义。

第三步 给每个子文件加防护

打开每一个被引入的子文件,在 <?php 之后第一行加上同样的检查:

1
2
3
4
5
6
7
<?php
// 防止直接访问文件
if ( ! defined( 'ABSPATH' ) ) {
exit;
}

// 下面写该文件原本的功能代码

六个文件逐一处理,写法完全一致。

第四步 检查函数与类命名

防护代码不冲突,但业务代码可能冲突。如果两个子文件都定义了同名函数,例如都写 function my_helper(),会报 Cannot redeclare 致命错误。处理方式二选一:

方式一 加统一前缀:

1
2
function lier_slider_render() { /* ... */ }
function lier_featured_products_render() { /* ... */ }

方式二 用存在性判断包裹:

1
2
3
if ( ! function_exists( 'my_helper' ) ) {
function my_helper() { /* ... */ }
}

第五步 验证效果

  1. 后台正常访问网站首页和内页,确认短代码、轮播图、推荐设备等模块显示正常。
  2. 浏览器直接访问子文件地址,例如 https://你的域名/wp-content/themes/avada-child/lier-slider-shortcode.php,页面应为空白或直接退出,不应输出任何业务内容或报错信息。
  3. 查看 PHP 错误日志,确认没有 Cannot redeclare 或 undefined constant 类错误。

常见错误写法对照

错误写法一 检查放在 require 列表之后:

1
2
3
4
5
require_once get_stylesheet_directory() . '/lier-slider-shortcode.php';
// ...
if ( ! defined( 'ABSPATH' ) ) {
exit;
}

问题:文件已经执行完,检查无效。

错误写法二 只在 functions.php 加检查,子文件不加:

问题:直接访问子文件路径时仍可能执行文件内代码。

正确做法:functions.php 顶部加检查,且每个子文件开头各加检查。

最终效果

  • 子主题功能模块集中管理,functions.php 结构清晰。
  • 所有子文件具备直接访问防护,降低代码暴露和意外执行风险。
  • 多文件重复写 ABSPATH 检查不会冲突,运行稳定。
  • 通过统一前缀或 function_exists 判断,避免函数重名导致的致命错误。
  • 网站前台功能正常,直接访问子文件路径被安全拦截。