自定义字段
自定义字段概述
自定义字段(Custom Fields)是 WordPress 内置的元数据存储机制,允许为文章、页面添加额外信息。
基本使用场景
- 文章阅读数
- 产品价格
- 项目链接
- 作者信息
- SEO 元描述
- 特色内容标记
使用自定义字段
在后台启用
- 在文章编辑页面,点击右上角 "三个点" 菜单
- 选择 "选项"
- 启用 "自定义字段"
- 刷新页面即可看到自定义字段面板
基础操作
php
<?php
// 添加自定义字段
add_post_meta($post_id, 'key', $value, $unique = false);
// 获取自定义字段
$value = get_post_meta($post_id, 'key', $single = true);
// $single = true 返回字符串,false 返回数组
// 更新自定义字段
update_post_meta($post_id, 'key', $new_value, $old_value = '');
// 删除自定义字段
delete_post_meta($post_id, $key, $value = '');
?>高级自定义字段 (ACF)
ACF 是最流行的自定义字段插件,提供图形化界面创建复杂字段组。
安装 ACF
bash
# 通过 WP-CLI 安装
wp plugin install advanced-custom-fields
wp plugin activate advanced-custom-fields字段类型
| 字段类型 | 说明 |
|---|---|
| Text | 单行文本 |
| Textarea | 多行文本 |
| Number | 数字 |
| 邮箱地址 | |
| URL | 网址 |
| Password | 密码 |
| Wysiwyg Editor | 富文本编辑器 |
| Image | 图片上传/选择 |
| File | 文件上传/选择 |
| Gallery | 多图画廊 |
| Select | 下拉选择 |
| Checkbox | 复选框 |
| Radio Button | 单选按钮 |
| True / False | 布尔值开关 |
| Date Picker | 日期选择 |
| Date Time Picker | 日期时间选择 |
| Color Picker | 颜色选择器 |
| Google Map | 地图选择 |
| Relationship | 关联文章/页面 |
| Post Object | 文章对象选择 |
| User | 用户选择 |
| Taxonomy | 分类选择 |
| Repeater | 重复器(循环字段) |
| Flexible Content | 灵活内容 |
| Clone | 克隆字段组 |
注册字段组
php
<?php
// functions.php 或插件文件
if (function_exists('acf_add_local_field_group')) {
acf_add_local_field_group(array(
'key' => 'group_portfolio_details',
'title' => '作品详情',
'fields' => array(
array(
'key' => 'field_client_name',
'label' => '客户名称',
'name' => 'client_name',
'type' => 'text',
),
array(
'key' => 'field_project_url',
'label' => '项目链接',
'name' => 'project_url',
'type' => 'url',
),
array(
'key' => 'field_project_year',
'label' => '项目年份',
'name' => 'project_year',
'type' => 'number',
),
array(
'key' => 'field_featured',
'label' => '精选项目',
'name' => 'featured',
'type' => 'true_false',
),
array(
'key' => 'field_gallery',
'label' => '项目画廊',
'name' => 'gallery',
'type' => 'gallery',
'mime_types' => 'jpg, png, webp',
),
),
'location' => array(
array(
array(
'param' => 'post_type',
'operator' => '==',
'value' => 'portfolio',
),
),
),
));
}
?>条件逻辑
php
<?php
array(
'key' => 'field_conditional_field',
'label' => '项目类型',
'name' => 'project_type',
'type' => 'select',
'choices' => array(
'website' => '网站',
'app' => '应用程序',
'other' => '其他',
),
),
array(
'key' => 'field_app_store_url',
'label' => 'App Store 链接',
'name' => 'app_store_url',
'type' => 'url',
'conditional_logic' => array(
array(
array(
'field' => 'field_project_type',
'operator' => '==',
'value' => 'app',
),
),
),
),
?>Repeater 字段(重复器)
php
<?php
acf_add_local_field_group(array(
'key' => 'group_team_members',
'title' => '团队成员',
'fields' => array(
array(
'key' => 'field_team_section_title',
'label' => '章节标题',
'name' => 'section_title',
'type' => 'text',
),
array(
'key' => 'field_team_members',
'label' => '成员列表',
'name' => 'members',
'type' => 'repeater',
'layout' => 'row', // row, block, table
'sub_fields' => array(
array(
'key' => 'field_member_name',
'label' => '姓名',
'name' => 'name',
'type' => 'text',
),
array(
'key' => 'field_member_avatar',
'label' => '头像',
'name' => 'avatar',
'type' => 'image',
'preview_size' => 'thumbnail',
'return_format' => 'array',
),
array(
'key' => 'field_member_role',
'label' => '职位',
'name' => 'role',
'type' => 'text',
),
array(
'key' => 'field_member_bio',
'label' => '简介',
'name' => 'bio',
'type' => 'textarea',
),
),
),
),
'location' => array(
array(
array(
'param' => 'page',
'operator' => '==',
'value' => 'about-us',
),
),
),
));
?>在模板中使用
php
<?php
// 基础字段
$client = get_field('client_name');
$url = get_field('project_url');
$featured = get_field('featured');
// 图片字段
$image = get_field('featured_image');
if ($image) {
echo '<img src="' . $image['sizes']['medium'] . '" alt="' . $image['alt'] . '">';
}
// 重复器字段
if (have_rows('members')): ?>
<div class="team-members">
<?php while (have_rows('members')): the_row(); ?>
<div class="member">
<?php
$avatar = get_sub_field('avatar');
if ($avatar): ?>
<img src="<?php echo $avatar['sizes']['thumbnail']; ?>" alt="">
<?php endif; ?>
<h3><?php the_sub_field('name'); ?></h3>
<p><?php the_sub_field('role'); ?></p>
</div>
<?php endwhile; ?>
</div>
<?php endif; ?>灵活内容(Flexible Content)
php
<?php
// 定义灵活内容字段
acf_add_local_field_group(array(
'key' => 'group_page_builder',
'title' => '页面构建器',
'fields' => array(
array(
'key' => 'field_page_content',
'name' => 'page_content',
'type' => 'flexible_content',
'layouts' => array(
array(
'key' => 'layout_hero',
'label' => 'Hero 区域',
'name' => 'hero',
'sub_fields' => array(
array(
'key' => 'field_hero_title',
'label' => '标题',
'name' => 'title',
'type' => 'text',
),
array(
'key' => 'field_hero_image',
'label' => '背景图',
'name' => 'background_image',
'type' => 'image',
),
),
),
array(
'key' => 'layout_features',
'label' => '功能列表',
'name' => 'features',
'sub_fields' => array(
array(
'key' => 'field_features_title',
'label' => '标题',
'name' => 'title',
'type' => 'text',
),
array(
'key' => 'field_features_list',
'label' => '功能列表',
'name' => 'list',
'type' => 'repeater',
'sub_fields' => array(
array(
'key' => 'field_feature_icon',
'label' => '图标',
'name' => 'icon',
'type' => 'text',
),
array(
'key' => 'field_feature_text',
'label' => '文字',
'name' => 'text',
'type' => 'text',
),
),
),
),
),
),
),
),
'location' => array(
array(
array(
'param' => 'page_template',
'operator' => '==',
'value' => 'template-builder.php',
),
),
),
));
?>灵活内容模板
php
<?php
// page-builder.php
if (have_rows('page_content')) {
while (have_rows('page_content')) {
the_row();
if (get_row_layout() === 'hero') {
$title = get_sub_field('title');
$bg = get_sub_field('background_image');
?>
<section class="hero-section" style="background-image: url(<?php echo $bg['url']; ?>)">
<h1><?php echo esc_html($title); ?></h1>
</section>
<?php
}
elseif (get_row_layout() === 'features') {
$title = get_sub_field('title');
?>
<section class="features-section">
<h2><?php echo esc_html($title); ?></h2>
<div class="features-grid">
<?php while (have_rows('list')): the_row(); ?>
<div class="feature-item">
<span class="icon"><?php the_sub_field('icon'); ?></span>
<span class="text"><?php the_sub_field('text'); ?></span>
</div>
<?php endwhile; ?>
</div>
</section>
<?php
}
}
}
?>选项页面
php
<?php
// 注册选项页面
acf_add_options_page(array(
'page_title' => '网站设置',
'menu_title' => '网站设置',
'menu_slug' => 'site-settings',
'capability' => 'manage_options',
'redirect' => false,
));
// 注册子选项页面
acf_add_options_sub_page(array(
'page_title' => '联系信息',
'menu_title' => '联系信息',
'parent_slug' => 'site-settings',
));
?>获取选项页面数据
php
<?php
// 获取选项值
$phone = get_field('phone', 'option');
$email = get_field('email', 'option');
$address = get_field('address', 'option');
// 或使用简写
$settings = get_fields('option');
// 在模板中使用
echo get_option('phone', 'option'); // 需使用 get_option
?>高级查询
php
<?php
// 查询有特定自定义字段的文章
$args = array(
'post_type' => 'product',
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'price',
'value' => array(100, 500),
'compare' => 'BETWEEN',
'type' => 'NUMERIC',
),
array(
'key' => 'featured',
'value' => '1',
'compare' => '=',
),
),
'orderby' => 'meta_value_num',
'meta_key' => 'price',
);
$query = new WP_Query($args);
// meta_query 类型
// =, !=, >, <, >=, <=, LIKE, NOT LIKE, IN, NOT IN, BETWEEN, NOT BETWEEN
?>CMB2(轻量替代方案)
CMB2 是 ACF 的免费替代品,适合不需要完整 ACF 功能的场景。
php
<?php
// 注册 CMB2 字段
function cmb2_portfolio_fields() {
$cmb = new_cmb2_box(array(
'id' => 'portfolio_details',
'title' => '作品详情',
'object_types' => array('portfolio'),
));
$cmb->add_field(array(
'name' => '客户名称',
'id' => 'client_name',
'type' => 'text',
));
$cmb->add_field(array(
'name' => '项目链接',
'id' => 'project_url',
'type' => 'text_url',
));
$cmb->add_field(array(
'name' => '项目年份',
'id' => 'project_year',
'type' => 'text_small',
));
}
add_action('cmb2_init', 'cmb2_portfolio_fields');
?>自定义字段最佳实践
- 使用有意义的键名 - 如
project_year而非year - 添加前缀 - 避免与其他插件冲突,如
mfp_client_name - 选择正确的字段类型 - 如 URL 用
url类型而非text - 设置默认值 - 提供合理的默认值
- 添加验证规则 - 确保数据完整性
- 使用选项页面 - 存储全局设置
- 清理数据 - 删除插件时清理相关数据
