EP032. “用 ACF 插件加 Event Date 自定义字段”
🔒 登录后可标记已读首页和归档页的日期圈到目前为止一直是写死的 Mar 25,这一讲要把它换成真数据。核心问题是:event 帖子本身自带的「发布日期」跟大家真正关心的「活动举办日期」是两码事——没人在乎这篇活动帖是什么时候写的。WordPress 原生的 Custom Fields(自定义字段)功能可以做到,但让编辑者自己手打字段名(比如 event_date)是很糟糕的体验,容易打错、也没人会记住这些字段名。所以这一讲改用业界标准插件 Advanced Custom Fields(ACF),用它建一个「Event Date」字段组,给编辑者一个真正的日期选择器(date picker),然后在前端用 get_field() 把这个值取出来,配合 PHP 内建的 DateTime 类格式化成月/日显示。
📌 2026 现状:2024 年 10 月 WordPress.org(Automattic)跟插件所属公司 WP Engine 起了商标纠纷,把 ACF 强制 fork 出一个新插件 Secure Custom Fields(SCF),移除了付费升级引导。两个插件现在并存维护:ACF(WP Engine 出品,含付费 Pro 版)继续在 wordpress.org 上架,SCF 是官方免费分支。get_field()/the_field() 这套 API 两边都兼容,装哪个插件、这一讲的代码都能照跑,只是装插件时会看到两个类似名字的选项,别装错。
涉及文件
wp-content/mu-plugins/university-post-types.php(修改:supports里短暂加过又拿掉了custom-fields,因为改用插件后不需要原生自定义字段 UI)- ACF 插件「Custom Fields → Add New」建立的
Event Date字段组(数据库层面的插件配置,不是代码文件,但等同于本讲的「新建」产出物) wp-content/themes/fictional-university-theme/front-page.php(修改:日期圈从写死的Mar/25换成动态取值)
代码实现
1. mu-plugins/university-post-types.php —— 曾经加过 custom-fields,随后又移除
这一讲一开始为了看到原生 Custom Fields 面板,先在 supports 里加了 'custom-fields':
'supports' => array('title', 'editor', 'excerpt', 'custom-fields'), // 曾经临时加过
但装好 ACF 插件后,字段的显示和存储完全交给插件管理,不需要原生 custom-fields UI,所以这一讲结束时又把它拿掉了,最终这个文件恢复成跟 EP031 一样:
// wp-content/mu-plugins/university-post-types.php(本讲结束时的状态,跟 EP031 相同)
function university_post_types() {
register_post_type('event', array(
'show_in_rest' => true,
'supports' => array('title', 'editor', 'excerpt'),
'rewrite' => array('slug' => 'events'),
'has_archive' => true,
'public' => true,
'labels' => array(
'name' => 'Events',
'add_new_item' => 'Add New Event',
'edit_item' => 'Edit Event',
'all_items' => 'All Events',
'singular_name' => 'Event'
),
'menu_icon' => 'dashicons-calendar'
));
}
add_action('init', 'university_post_types');
2. 安装并配置 Advanced Custom Fields 插件(后台操作,非代码)
- 插件 → 安装插件,搜索 "Advanced Custom Fields"(作者 Elliot,装机量超百万),安装并启用。
- 侧边栏出现「Custom Fields」,点进去 Add New 建一个字段组,取名
Event Date。 - 组里加一个字段:Label 填
Event Date(人类可读),Name 会自动转成event_date(这就是代码里要用的字段名)。 - 字段类型选 Date Picker(不是纯文字输入框),设为必填(Required)。
- 关键设置:Return Format 一定要选
Y m d,这样返回的字符串格式才能跟后面 PHP 的DateTime类配合。 - 拉到最下面的 Location(位置)设置:
Post Type等于Event,让这个字段只出现在 event 文章的编辑画面,不影响普通 post/page。 - 保存后,编辑任意一个 event 文章,正文下方会出现「Event Date」字段,点开是个迷你日历,可以选日期。
[截图:ACF"Custom Fields → Add New"字段组编辑画面,Event Date 字段类型选 Date Picker、Location 规则设为 Post Type = Event 的设置画面]
[截图:编辑某个 event 文章时,正文下方出现的 Event Date 日期选择器(点开显示迷你日历)]
3. front-page.php —— 用 get_field() + DateTime 显示真实日期
// wp-content/themes/fictional-university-theme/front-page.php
// Upcoming Events 循环里,日期圈那部分,从写死的 Mar / 25 改成:
<a class="event-summary__date t-center" href="#">
<span class="event-summary__month"><?php
$eventDate = new DateTime(get_field('event_date'));
echo $eventDate->format('M')
?></span>
<span class="event-summary__day"><?php echo $eventDate->format('d') ?></span>
</a>
要点:
get_field('event_date')是 ACF 插件提供的函数,专门用来返回(不直接输出)某个自定义字段的值,跟the_field()相对(the_field()会直接 echo,这里不需要)。- PHP 内建
DateTime类:不传参数时代表「现在」,传一个日期字符串就代表那个具体日期。这里把 ACF 返回的日期字符串传进去,生成一个日期对象。 $eventDate->format('M')返回三个字母的月份缩写(如Jul),format('d')返回两位数的日期(如20)。这两行共用同一个$eventDate变量,所以两个<span>之间不用重复创建DateTime对象。- 已经存在的旧 event 帖子(比如之前几讲手打的示例文章)不会自动补上
event_date,需要手动一个个回去编辑补上,否则DateTime拿不到值会 fallback 成「今天」。
Hook / Function 速查
| 名称 | 类型 | 用途 |
|---|---|---|
get_field($field_name) | ACF 插件 function(返回值,需 echo) | 返回某个自定义字段的值,本讲取 event_date |
the_field($field_name) | ACF 插件 function(直接输出) | 跟 get_field() 类似但直接 echo,本讲没用到,只是对照说明 |
DateTime | PHP 内建 class(非 WordPress) | new DateTime($dateString) 创建一个日期对象,不传参数默认代表当前日期 |
$dateTimeObj->format($format) | DateTime 类方法 | 按指定格式(如 M 月份缩写、d 两位日期)格式化输出该日期对象 |
常见坑
- 原生 Custom Fields 让编辑者自己手打 name/value(比如
event_date=July 1st 2017),字段名容易记错或打错,这是这一讲特地演示后否决掉的做法。 - ACF 字段的 Return Format 一定要选跟 PHP 兼容的
Y m d格式,不然DateTime解析会出问题。 - 已经存在的旧 event 帖子(EP028 建的示例)不会自动有
event_date值,必须手动逐个补上,否则显示的日期会 fallback 成「当前日期」而不是报错,容易被忽略。 - 建字段组时 Location 规则一定要设成只在
event文章类型显示,不然会污染到普通文章/页面的编辑画面。
延伸 / 后续讲座会用到
下一讲会开始讲怎么依据这个 event_date 来排序和过滤活动(比如只显示还没过去的活动、按最近的活动日期排序),这是 Section 7 后半段的重点。
Sources
Udemy:
- Become a WordPress Developer: Unlocking Power With Code — Section 7, EP032