Bricks 的能力不止于点选拖拽——你完全可以在子主题里写 PHP 类,扩展 Bricks 的 Element 基类,创建真正属于自己的元素。这类自定义元素会像原生元素一样出现在构建器面板里,拥有自己的分类、图标、控件(settings)、样式入口和前端渲染逻辑,甚至能做成可嵌套元素(nestable)。
本文依据 Bricks 官方文档《Create Your Own Elements》与《Code signatures》改写,覆盖从零写一个元素的全过程,以及配套的代码签名机制——它决定了你写的可执行 PHP/HTML 代码能否安全运行。
自定义元素是什么
在 Bricks 中创建自定义元素,模式与创建 WordPress widget 非常相似:继承 \Bricks\Element 基类,按需填充属性和方法即可。
官方子主题(可从你的 Bricks 账户 下载)里自带一个演示用的自定义元素,本文以它为基础展开讲解。一个典型的开发流程是:
| 步骤 | 做什么 | 产物 |
|---|---|---|
| 1 | 在子主题根目录新建元素类文件 | element-test.php |
| 2 | 写类:定义属性、控件、渲染逻辑 | Prefix_Element_Test 类 |
| 3 | 在 functions.php 里注册元素 |
Bricks\Elements::register_element() |
| 4 | 打开构建器,像用原生元素一样使用 | 面板中出现自定义元素 |
整个过程不需要动 Bricks 核心文件,也不影响后续升级。
准备工作:子主题与文件结构
自定义元素代码必须放在子主题里(不要改父主题,否则 Bricks 升级会被覆盖)。如果你还没有子主题,先从 my.bricksbuilder.io 下载官方子主题并启用。
先在子主题根目录新建一个文件 element-test.php,后面所有元素代码都写在这个文件里。
空白元素类骨架
一个空白的元素类长这样——先看结构,再逐个理解:
<?php
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
class Prefix_Element_Test extends \Bricks\Element {
// Element properties
public $category = '';
public $name = '';
public $icon = '';
public $css_selector = '';
public $scripts = [];
public $nestable = false; // true || @since 1.5
// Methods: Builder-specific
public function get_label() {}
public function get_keywords() {}
public function set_control_groups() {}
public function set_controls() {}
// Methods: Frontend-specific
public function enqueue_scripts() {}
public function render() {}
}
可以看到类由两部分组成:属性(properties,描述元素的元信息)和方法(methods,构建器侧与前端侧的行为)。下面把每一项讲清楚。
元素属性与方法速查表
| 成员 | 必填 | 作用与规则 |
|---|---|---|
$category |
✅ | 元素在构建器面板中的分类名(全小写、无空格)。可以用预置分类(如 general、media),也可以自定义新分类;自定义分类需要用 bricks/builder/i18n 过滤器提供可翻译的分类名 |
$name |
✅ | 元素的唯一标识(全小写、无空格)。为避免与其他元素冲突,务必加前缀,如 prefix-element-test |
$icon |
— | 图标字体 CSS 类,决定元素在面板里显示什么图标。Bricks 内置 Fontawesome 6(如 fas fa-anchor)、Ionicons 4(如 ion-md-alarm)、Themify Icons(如 ti-bolt-alt) |
$css_selector |
— | 默认所有 CSS 控件设置都作用在元素外层 .bricks-element-wrapper 上;想让默认 CSS 选择器指向某个子元素,就在这里指定 |
$nestable |
— | 普通元素省略即可;设为 true 可创建可嵌套元素(nestable element) |
$scripts |
— | 元素在前端渲染或构建器中更新时要运行的 JS 脚本名数组。例如 Counter 元素用 bricksCounter(定义在 frontend.min.js 里),加载方式:public $scripts = ['bricksCounter'];。所有脚本名都要加前缀,如 prefixElementTest |
get_label() |
✅ | 返回本地化(可翻译)的元素标签 |
get_keywords() |
— | 字符串数组,构建器搜索元素时匹配这些关键词就能搜到该元素 |
set_control_groups() |
— | 默认所有控件都无分组地堆在「Content」标签下;想给控件分组就在这里定义控件组:title(本地化组名)+ tab(content 或 style) |
set_controls() |
✅ | 定义元素的控件(设置项)。所有可用控件类型见官方 Element Controls 文档 |
enqueue_scripts() |
— | 加载元素专属的脚本与样式,只在用到该元素的页面上加载,性能更好。示例:wp_enqueue_script( 'prefix-element-test', get_template_directory_uri() . '/js/custom.js', ['jquery'], '1.0', true ); |
render() |
✅ | 渲染元素 HTML。用 $this->set_attribute() 设置 HTML 属性,用 $this->render_attributes() 输出 |
set_attribute( $key, $attribute, $value ) |
— | 为任意 HTML 标签设置属性的辅助方法:$key 是该标签的唯一标识,$attribute 是属性名,$value 是字符串或数组 |
render_attributes( $key ) |
— | 输出通过 set_attribute() 设置的属性,$key 是同一个标识 |
render_dynamic_data_tag( $tag, $context, $args ) |
— | 在 render 里渲染动态数据标签的辅助方法(如 {post_title}),会自动根据渲染环境设置正确的 post ID |
render_dynamic_data( $content ) |
— | 在 render 里渲染可能包含动态数据标签的内容字符串,同样会自动处理 post ID |
填充一个完整示例元素
把上面的骨架填上真实数据,就是一个可用的「提示框」元素(带文本内容 + 类型下拉):
<?php
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
class Prefix_Element_Test extends \Bricks\Element {
// Element properties
public $category = 'general'; // Use predefined element category 'general'
public $name = 'prefix-test'; // Make sure to prefix your elements
public $icon = 'ti-bolt-alt'; // Themify icon font class
public $css_selector = '.prefix-test-wrapper'; // Default CSS selector
public $scripts = ['prefixElementTest']; // Script(s) run when element is rendered on frontend or updated in builder
// Return localised element label
public function get_label() {
return esc_html__( 'Test element', 'bricks' );
}
// Set builder control groups
public function set_control_groups() {
$this->control_groups['text'] = [ // Unique group identifier (lowercase, no spaces)
'title' => esc_html__( 'Text', 'bricks' ), // Localized control group title
'tab' => 'content', // Set to either "content" or "style"
];
$this->control_groups['settings'] = [
'title' => esc_html__( 'Settings', 'bricks' ),
'tab' => 'content',
];
}
// Set builder controls
public function set_controls() {
$this->controls['content'] = [ // Unique control identifier (lowercase, no spaces)
'tab' => 'content', // Control tab: content/style
'group' => 'text', // Show under control group
'label' => esc_html__( 'Content', 'bricks' ), // Control label
'type' => 'text', // Control type
'default' => esc_html__( 'Content goes here ..', 'bricks' ), // Default setting
];
$this->controls['type'] = [
'tab' => 'content',
'group' => 'settings',
'label' => esc_html__( 'Type', 'bricks' ),
'type' => 'select',
'options' => [
'info' => esc_html__( 'Info', 'bricks' ),
'success' => esc_html__( 'Success', 'bricks' ),
'warning' => esc_html__( 'Warning', 'bricks' ),
'danger' => esc_html__( 'Danger', 'bricks' ),
'muted' => esc_html__( 'Muted', 'bricks' ),
],
'inline' => true,
'clearable' => false,
'pasteStyles' => false,
'default' => 'info',
];
}
// Enqueue element styles and scripts
public function enqueue_scripts() {
wp_enqueue_script( 'prefix-test-script' );
}
// Render element HTML
public function render() {
// Set element attributes
$root_classes[] = 'prefix-test-wrapper';
if ( ! empty( $this->settings['type'] ) ) {
$root_classes[] = "color-{$this->settings['type']}";
}
// Add 'class' attribute to element root tag
$this->set_attribute( '_root', 'class', $root_classes );
// Render element HTML
// '_root' attribute is required (contains element ID, class, etc.)
echo "<div {$this->render_attributes( '_root' )}>"; // Element root attributes
if ( ! empty( $this->settings['content'] ) ) {
echo "<div>{$this->settings['content']}</div>";
}
echo '</div>';
}
}
几个要点:
- 所有元素的设置值都存在
$this->settings里。想在render()里看当前元素有哪些设置,直接var_dump( $this->settings );打印即可; - 控件标识(如
content、type)全小写无空格,与控件组标识、元素 name 规则一致; $this->settings['content']就是用户在构建器里输入的内容,$this->settings['type']是下拉框选中的值,render 时用来拼color-xxx的 class。
控件组与控件
set_control_groups() 负责把控件归组。示例里定义了两个组:
text组(标题 Text,tab => 'content')——承载文本内容控件;settings组(标题 Settings,tab => 'content')——承载类型选择控件。
set_controls() 里每个控件数组的常用键如下(示例中用到的):tab(归属标签页 content/style)、group(归属哪个控件组)、label(控件显示名)、type(控件类型)、default(默认值),下拉类控件还有 options、inline、clearable、pasteStyles。
Bricks 的控件类型远不止 text 和 select——完整的控件清单、每个控件的全部参数,请查阅官方文档 Element Controls,页面里对每种控件都有参数表,直接照抄参数就能用。
前端渲染与动态数据
render() 是元素真正输出 HTML 的地方,规则很简单:
- 用
$this->set_attribute( '_root', 'class', $root_classes )给根标签设置属性——_root是必需的,它承载元素的 ID、class 等关键属性; - 用
$this->render_attributes( '_root' )输出这些属性; - 直接
echo输出 HTML 字符串。
如果元素里要渲染动态数据标签(比如 {post_title}),不要手动拼字符串,用官方提供的两个辅助方法:
$this->render_dynamic_data_tag( $tag, $context, $args )—— 渲染单个动态数据标签;$this->render_dynamic_data( $content )—— 渲染可能包含多个动态数据标签的内容字符串。
这两个方法会自动根据元素实际渲染的环境(文章页、归档页、循环内等)设置正确的 post ID,避免出现「在循环里取错文章标题」的经典问题。
加载与注册你的元素
写完类之后,还需要让 Bricks 知道它的存在。打开子主题的 functions.php,粘贴以下代码:
/**
* Register custom elements
*/
add_action( 'init', function() {
$element_files = [
__DIR__ . '/element-test.php',
];
foreach ( $element_files as $file ) {
\Bricks\Elements::register_element( $file );
}
}, 11 );
register_element 方法接受 3 个参数:
| 参数 | 必填 | 说明 |
|---|---|---|
$file |
✅ | 自定义元素 PHP 文件在服务器上的完整路径 |
$name |
— | 自定义元素的 name 字符串(如 prefix-element-test) |
$element_class |
— | 元素类名(如 Prefix_Element_Test),必须派生自 \Bricks\Element |
性能提示:带上
$name和$element_class两个可选参数能提升加载性能。多元素站点建议在$element_files数组里列出所有元素文件,一次注册完。
注册完成后,刷新构建器,就能在「General」分类(或你自定义的分类)里找到这个 Test element,拖进画布、设置内容、选择类型,前端会渲染出对应的 HTML。
代码签名:保护可执行代码
如果你的自定义元素涉及可执行代码(Code 元素的 PHP/HTML、SVG 代码、查询循环编辑器代码等),Bricks 还要求它们持有有效的代码签名才能运行。签名机制与元素开发直接相关——元素里的 PHP 代码再强大,签名缺失或失效时 Bricks 一律不执行。
原理:签名时 Bricks 用 WordPress 的 wp_hash() 对代码做哈希,并把签名和 Bricks 数据一起存储;运行时再次哈希比对,不一致就阻止执行。这样即使攻击者拿到数据库写入权限、塞进恶意代码,只要生成不了有效签名,代码就不会运行。
需要签名的代码位置:
- Code 元素启用了 Execute code 时的 PHP/HTML 代码;
- SVG 元素 Source 设为 Code 时;
- 查询循环(Query Loop)编辑器代码;
- 组件(Component)查询属性;
- 全局查询记录。
签名的前置条件:
- 必须在 Bricks → Settings → Custom code 中启用代码执行(Code execution);
- 用户必须拥有 Bricks 的 Execute code 能力(capability);
- 构建器内手动生成签名是管理员级别操作;全局重新生成签名需要 WordPress 的
manage_options权限; - 如果常量
BRICKS_LOCK_CODE_SIGNATURES为true,无论什么权限都无法生成新签名。
如何生成签名:
| 场景 | 操作 |
|---|---|
| 单个元素 | 构建器中打开代码编辑器,点代码框上方的 Sign code 按钮;光标在编辑器内时也可按 CMD/CTRL + R。签名后保存页面,代码与签名会一起存储 |
| 整页批量 | 构建器结构面板顶部的红色指纹图标会提示存在未签名代码,点它可查看并批量签名当前页所有未签名元素 |
| 全站 | 后台 Bricks → Settings → Custom code → Code signatures,点 Regenerate code signatures,会为所有页面、模板、全局元素、组件元素树、组件查询属性、全局查询记录生成签名 |
锁定签名生成(官方文档标注该常量自 Bricks 1.11.1 引入):高安全环境可以在签名前定义常量,此后任何生成签名的尝试都会返回「Code signatures are locked」错误:
if ( ! defined( 'BRICKS_LOCK_CODE_SIGNATURES' ) ) {
define( 'BRICKS_LOCK_CODE_SIGNATURES', true );
}
什么时候必须重新生成签名:
- 从 1.9.7 之前的版本升级 Bricks——官方文档明确:升级后必须到 Bricks → Settings → Custom code 生成签名,已签名的代码位置才会运行,建议先做一次代码审查;
- 修改过 WordPress salts(
wp-config.php里的密钥)——salts 一变,已有签名全部失效; - 站点迁移(换域名或换服务器)——新环境 salts 不同就需要重新签名;
- 编辑过已签名代码——内容变了签名就不匹配,需要重新签名后才能运行。
salts 是 WordPress 的哈希密钥,Bricks 的签名依赖它们,所以「同一份代码换环境签名就失效」是正常现象,重新签名即可。
常见问题(FAQ)
Q:自定义元素会出现在构建器哪个分类里?
A:由 $category 属性决定。填官方预置分类(如 general)就进对应分类;填自定义名称会创建新分类,记得用 bricks/builder/i18n 过滤器提供可翻译的分类名。
Q:元素注册了但构建器里看不到?
A:先确认 functions.php 里的注册代码生效(add_action( 'init', ... )),再确认元素类名正确派生自 \Bricks\Element 且文件路径正确。注册后需要刷新构建器页面。
Q:控件不显示是什么原因?
A:set_controls() 是必填方法,控件数组的键、label、type 必须完整;控件组没定义时控件会无分组显示在 Content 标签下,这是正常的。
Q:为什么升级 Bricks 或改密钥后,Code 元素不执行了? A:代码签名失效了。按上面的「什么时候必须重新生成签名」检查——改过 salts、迁移过站点、升级自 1.9.7 之前,都需要重新生成签名。
Q:自定义元素怎么加载自己的 CSS/JS?
A:用 enqueue_scripts() 方法,按需加载、只在用到该元素的页面加载;构建器内要跑的脚本则放进 $scripts 数组。
延伸阅读
- 元素里要展示动态内容?先看 Bricks 自定义动态数据标签入门
- 自定义元素常配合查询循环使用:给 Bricks Query Loop 接入任意自定义 WP_Query
- 元素输出前想按条件过滤内容?看 Bricks 条件输出教程
- 布局相关的基础元素体系见 Bricks Layout 布局详解
- 官方文档:Create Your Own Elements | Code signatures | Element Controls
- 相关阅读:Bricks Setup Guide
延伸阅读
Bricks Query Loop 高亮当前文章:给循环项加 data-current 属性
教程:Bricks Query Loop 高亮当前文章:给循环项加 data-current 属性——query loop 附完整代码可直接复用,适合外贸独立站与 WordPress 开发者。
tutorialBricks Query Loop:精选文章置顶且不重复(PHP 查询实现)
教程:Bricks Query Loop:精选文章置顶且不重复(PHP 查询实现)——query loop 附完整代码可直接复用,适合外贸独立站与 WordPress 开发者。
tutorialBricks Query Loop 按 Meta Box Group 的 Radio 子字段筛选文章
教程:Bricks Query Loop 按 Meta Box Group 的 Radio 子字段筛选文章——query loop 附完整代码可直接复用,适合外贸独立站与 WordPress 开发者。
tutorialBricks Query Loop 只输出自定义字段里指定的文章 ID
教程:Bricks Query Loop 只输出自定义字段里指定的文章 ID——query loop 附完整代码可直接复用,适合外贸独立站与 WordPress 开发者。
