EP057. “Campus 信息窗口 + 单页模板 + 与 Program 的双向关联”
🔒 登录后可标记已读做三件事:① 给归档页地图的 pin 加信息窗口(点了显示校区标题+地址,标题可点进详情页);② 新建 single-campus.php(复制 single-program.php 改),展示这个校区自己的地图 + 「Programs Available At This Campus」列表;③ 用 ACF 的 Relationship 字段类型建一个 program → campus 的关联字段,并且在 single-program.php 底部加一段反向展示「这个 Program 在哪些校区开设」。跟前面 professor ↔ program 的关联写法(meta_query + LIKE)是同一套思路。
涉及文件
wp-content/themes/fictional-university-theme/archive-campus.php(修改,marker 里塞标题链接+地址;删掉不需要的分页链接)wp-content/themes/fictional-university-theme/single-campus.php(新建,复制single-program.php改)wp-content/themes/fictional-university-theme/single-program.php(修改,底部新增「这个 Program 在哪些校区」区块)- ACF 后台新建字段组「Related Campus(es)」(挂在 program 文章类型上,见下面说明)
代码实现
1. archive-campus.php:marker 塞进信息窗口内容 + 删掉分页
<!-- wp-content/themes/fictional-university-theme/archive-campus.php -->
<!-- 修改前:<div class="marker" data-lat="..." data-lng="..."></div> 后面紧跟 echo paginate_links(); -->
<div class="marker" data-lat="<?php echo $mapLocation['lat'] ?>" data-lng="<?php echo $mapLocation['lng']; ?>">
<h3><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
<?php echo $mapLocation['address']; ?>
</div>
<?php } ?>
GoogleMap.js(EP056 就写好了)本来就有「marker 元素如果有 HTML 内容就自动生成 infoWindow」的逻辑,这里只是往 marker 的 div 里塞进标题链接和地址,不用再改 JS。同时把 echo paginate_links(); 删掉——校区归档页不需要分页链接。
[截图:前台 Campuses 归档页点击某个图钉后弹出的信息窗口,显示校区标题链接和地址的画面]
2. single-campus.php(新建,复制 single-program.php 改)
<?php
// wp-content/themes/fictional-university-theme/single-campus.php
get_header();
while(have_posts()) {
the_post();
pageBanner();
?>
<div class="container container--narrow page-section">
<div class="metabox metabox--position-up metabox--with-home-link">
<p><a class="metabox__blog-home-link" href="<?php echo get_post_type_archive_link('campus'); ?>"><i class="fa fa-home" aria-hidden="true"></i> All Campuses</a> <span class="metabox__main"><?php the_title(); ?></span></p>
</div>
<div class="generic-content"><?php the_content(); ?></div>
<?php
$mapLocation = get_field('map_location');
?>
<div class="acf-map">
<div class="marker" data-lat="<?php echo $mapLocation['lat'] ?>" data-lng="<?php echo $mapLocation['lng']; ?>">
<h3><?php the_title(); ?></h3>
<?php echo $mapLocation['address']; ?>
</div>
</div>
<?php
$relatedPrograms = new WP_Query(array(
'posts_per_page' => -1,
'post_type' => 'program',
'orderby' => 'title',
'order' => 'ASC',
'meta_query' => array(
array(
'key' => 'related_campus',
'compare' => 'LIKE',
'value' => '"' . get_the_ID() . '"'
)
)
));
if ($relatedPrograms->have_posts()) {
echo '<hr class="section-break">';
echo '<h2 class="headline headline--medium">Programs Available At This Campus</h2>';
echo '<ul class="min-list link-list">';
while($relatedPrograms->have_posts()) {
$relatedPrograms->the_post(); ?>
<li>
<a href="<?php the_permalink(); ?>"><?php the_title(); ?></a>
</li>
<?php }
echo '</ul>';
}
wp_reset_postdata();
?>
</div>
<?php }
get_footer();
?>
要点:
- 面包屑(metabox)的「All Programs」改成「All Campuses」,链接换成
get_post_type_archive_link('campus')。 - 单校区只有一个点,直接复用 archive-campus 里 marker 那段代码,但不需要外层
<a>链接(已经在这个校区自己的详情页了,点标题链接回自己没意义),所以标题只留<?php the_title(); ?>,没有包<a>。 - 复制
single-program.php时是连同整份文件复制的,包括原本查 professor 和 event 的两段WP_Query;这里只保留改造后的$relatedPrograms查询(用related_campus这个 meta_key 找出关联到当前校区的 program),事件那段留到 EP058 才清掉(那一讲的内容)。
3. ACF 后台:新建 program → campus 的关联字段
- 自定义字段 → 新建字段组,命名 Related Campus(es)。
- 新增字段:字段标题可以叫
Related Campuses,变量名(Field Name)改成related_campus(去掉括号方便记和打字)。 - 字段类型选 Relationship。
- Filters(过滤器)里,Post Type 只留 campus 相关的可选,其余(Taxonomy 等)取消勾选,只留搜索框。
- 显示规则(Location):文章类型等于
program。 - 保存/发布,然后去某个 program 的编辑页把
related_campus关联到对应校区。
4. single-program.php:底部加「这个 Program 在哪些校区」
加在原本 events 查询那段 wp_reset_postdata() 之后:
// wp-content/themes/fictional-university-theme/single-program.php
// 加在原本 events 相关代码的 wp_reset_postdata() 之后
wp_reset_postdata();
$relatedCampuses = get_field('related_campus');
if ($relatedCampuses) {
echo '<hr class="section-break">';
echo '<h2 class="headline headline--medium">' . get_the_title() . ' is Available At These Campuses:</h2>';
echo '<ul class="min-list link-list">';
foreach($relatedCampuses as $campus) {
?> <li><a href="<?php echo get_the_permalink($campus); ?>"><?php echo get_the_title($campus) ?></a></li> <?php
}
echo '</ul>';
}
要点:
- Relationship 字段的值直接存在当前 program 这篇文章上,不需要再发一次
WP_Query,直接get_field('related_campus')拿到关联的校区文章数组即可,配合foreach遍历。 get_the_permalink($campus)/get_the_title($campus)传入具体的 post(这里是数组里的每个校区对象),不依赖全局的 The Loop 状态,所以这里不需要the_post()。- 加这段之前先调用
wp_reset_postdata(),避免上面 events 那个自定义查询的全局数据状态没清干净,影响get_field()读到的是哪篇文章。
[截图:前台某个 campus 详情页,含该校区自己的定位地图和下方"Programs Available At This Campus"列表的画面]
Hook / Function 速查
| 名称 | 类型 | 用途 |
|---|---|---|
WP_Query + meta_query(LIKE + 当前 ID) | 组合用法(复用 program↔professor 的写法) | 从 campus 这边反查关联到自己的 program |
get_field('related_campus') | ACF function | Relationship 字段直接在当前文章上取值,得到关联文章数组,不用额外查询 |
get_the_permalink($post) / get_the_title($post) | WP 内建 function | 传入具体 post 对象/ID 取链接和标题,不依赖 The Loop 全局状态 |
常见坑
single-campus.php是复制single-program.php整份文件再删改的,删掉原来查 professor 用的 while 循环开头时,一不小心把里面创建$mapLocation变量的那行也删掉了,导致地图定位到经纬度 (0,0)(画面直接跑去大西洋中间)。修复方法是重新在合适位置补上$mapLocation = get_field('map_location');。
延伸 / 后续讲座会用到
single-campus.php 里还留着从 single-program.php 复制过来、没用到的 events 相关 WP_Query 和 while 循环,EP058 会把这段没用的代码删掉,同时修一下 campus 归档页只查 10 篇文章(WordPress 默认分页数)的问题。
Sources
Udemy:
- Become a WordPress Developer: Unlocking Power With Code — Section 12, EP057