ACF(SCF)のくり返しフィールド(リピーター)は、have_rows()・the_row()・get_sub_field()の3点セットで出します。投稿ループとそっくりな形なので、パターンを一度覚えれば使い回せます。
<?php if (have_rows('items')) : ?>
<?php while (have_rows('items')) : the_row(); ?>
<?php the_sub_field('title'); ?>
<?php endwhile; ?>
<?php endif; ?>べんりワザACFとSCF、どっちを入れればいい?ACFとSCFの違いと選び方はこちら1くり返しフィールドは「行の集まり」
くり返しフィールドは、同じ入力欄のセット(行)を何個でも増やせるフィールドです。たとえば「よくある質問」なら、質問と答えのセットを行として何個でも追加できます。
よくある質問(くり返しフィールド:faq)
├── 1行目 question: 送料はいくら? answer: 全国一律500円です
├── 2行目 question: 返品できる? answer: 到着後7日以内なら…
└── 3行目 question: ギフト包装は? answer: 無料で承ります外側の名前(faq)がくり返し全体、中の名前(question)がサブフィールド。この親子関係が、そのままコードの形になります。
基本の型:3点セットで書く
<?php if (have_rows('faq')) : ?>
<dl class="faq">
<?php while (have_rows('faq')) : the_row(); ?>
<dt><?php the_sub_field('question'); ?></dt>
<dd><?php the_sub_field('answer'); ?></dd>
<?php endwhile; ?>
</dl>
<?php endif; ?>3つの役割はこう分かれています。
have_rows('faq')——行があるかを調べる(ifとwhileの両方で使う)the_row()——次の行へ進める。これが無いと無限ループthe_sub_field('question')——今の行の中の値を出す(値を変数に入れたいときはget_sub_field())
ifで囲むのは、行が0個のときに空の<dl>だけが残るのを防ぐためです。見出しやラッパー要素ごと出さないようにするのが定番の書き方です。
画像やリンクを含む行
サブフィールドの型が画像・リンクでも、取り出し方は同じget_sub_field()です。
<?php if (have_rows('members')) : ?>
<ul class="members">
<?php while (have_rows('members')) : the_row(); ?>
<li>
<?php echo wp_get_attachment_image(get_sub_field('photo'), 'medium'); ?>
<p class="name"><?php the_sub_field('name'); ?></p>
<?php if ($url = get_sub_field('sns')) : ?>
<a href="<?php echo esc_url($url); ?>">SNS</a>
<?php endif; ?>
</li>
<?php endwhile; ?>
</ul>
<?php endif; ?>画像フィールドは返り値の設定(ID・URL・配列)で書き方が変わる点だけ注意します。
べんりワザACFで画像を表示する方法画像フィールドの返り値ごとの書き方はこちら入れ子のくり返し(くり返しの中のくり返し)
くり返しフィールドの中に、さらにくり返しフィールドを入れられます。内側でも書き方はまったく同じ——名前だけ変えて3点セットを重ねます。
<?php while (have_rows('plans')) : the_row(); ?>
<section>
<h3><?php the_sub_field('plan_name'); ?></h3>
<?php if (have_rows('features')) : ?> <!-- 内側のくり返し -->
<ul>
<?php while (have_rows('features')) : the_row(); ?>
<li><?php the_sub_field('feature_text'); ?></li>
<?php endwhile; ?>
</ul>
<?php endif; ?>
</section>
<?php endwhile; ?>内側のhave_rows('features')は、今の行(the_row()で進んだ行)の中を見るので、親の名前を書き足す必要はありません。
行数を数える・何行目かを知る
<?php $rows = get_field('faq'); ?>
<p>ぜんぶで<?php echo count($rows); ?>件</p>
<?php while (have_rows('faq')) : the_row(); ?>
<p>Q<?php echo get_row_index(); ?>:<?php the_sub_field('question'); ?></p>
<?php endwhile; ?>count(get_field('faq'))——行数(0件のときはget_field()がfalseを返すので、count()の前にifで確認すると安全)get_row_index()——今が何行目か(1から始まる)
foreachで書く方法もある
get_field()でくり返し全体を受け取ると、普通のPHPの配列として扱えます。have_rows()の形が読みにくいときはこちらでも同じ結果になります。
<?php $faq = get_field('faq'); ?>
<?php if ($faq) : ?>
<?php foreach ($faq as $row) : ?>
<dt><?php echo esc_html($row['question']); ?></dt>
<dd><?php echo esc_html($row['answer']); ?></dd>
<?php endforeach; ?>
<?php endif; ?>配列のキーはサブフィールドの名前です。ただしこの書き方では画像フィールドなどの整形(返り値の変換)がかからない場合があるため、基本はhave_rows()、単純なテキストだけならforeachと使い分けるのが無難です。
ほかの投稿のくり返しを出す
一覧ページなどで「別の投稿のくり返し」を出したいときは、第2引数に投稿IDを渡します。
<?php while (have_rows('faq', 123)) : the_row(); ?>固定ページのオプション欄をトップページで使う、といった場面で役立ちます。optionを渡すとオプションページの値を読めます。
まとめ
- くり返しフィールドは
have_rows()/the_row()/get_sub_field()の3点セット。投稿ループと同じ形 if (have_rows(...))で囲めば、0件のときに空のリストが残らない- 入れ子も同じ書き方を重ねるだけ。行数は
count(get_field())、何行目かはget_row_index() the_row()忘れ=無限ループ、get_field()とサブ用関数の取り違え=値が空——この2つが定番のつまずき
行を増やすだけでコンテンツが伸びる作りにしておくと、更新をおまかせできるサイトになります。