WP DEVELOP

EP057. “Campus 信息窗口 + 单页模板 + 与 Program 的双向关联”

首页 WordPress 开发课程 GOOGLE MAPS 互动地图 · EP057
约 20 分钟· #EP057#GOOGLE MAPS 互动地图
🔒 登录后可标记已读

做三件事:① 给归档页地图的 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 的关联字段

  1. 自定义字段 → 新建字段组,命名 Related Campus(es)
  2. 新增字段:字段标题可以叫 Related Campuses,变量名(Field Name)改成 related_campus(去掉括号方便记和打字)。
  3. 字段类型选 Relationship
  4. Filters(过滤器)里,Post Type 只留 campus 相关的可选,其余(Taxonomy 等)取消勾选,只留搜索框。
  5. 显示规则(Location):文章类型等于 program
  6. 保存/发布,然后去某个 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_queryLIKE + 当前 ID)组合用法(复用 program↔professor 的写法)从 campus 这边反查关联到自己的 program
get_field('related_campus')ACF functionRelationship 字段直接在当前文章上取值,得到关联文章数组,不用额外查询
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