【WordPress】FAQを簡単に追加・編集できるようにする為にSmart Custom Fieldsを使う方法
 つい先日タイトルの内容を実装しましたので、その方法を紹介します
完成イメージ
今回実装したいFAQのイメージです。
(画像なので動きません)

よく見かけるタイプの、開閉(アコーディオン)式QandAです。
QやAをカスタムフィールドで編集可能にし、さらに、質問が増える可能性も考慮し項目を増減できるようにしてあげる方が親切です。
ミッション
Q・Aをカスタムフィールド化
Q・Aを簡単に追加、削除できる
これが今回のミッションです。
考察
今回は、カスタム投稿タイプを作るまでは指定がなかった為、特定の固定ページを作成し、そのページ編集画面にQとA用のカスタムフィールドを追加することにしました。
余程苦手な方が触るとかではない限り、固定ページや投稿を使用してのカスタムフィールドで問題ないかと思います。
項目を自由に追加、削除できるという点で、今回はカスタムフィールドプラグイン、「Smart Custom Fields」を使用しました。
Advanced Custom Fieldsもよく使われる有名なプラグインですが、Smart Custom Fieldsを使ってみるとその名の通りスマートで、いいやん
という感じです。
では実際にどんな風に作ったかを見ていきます。
Smart Custom Fieldsの使い方
設定、超簡単なんですけど![]()

まず、「繰り返し」にチェックを入れたフィールドグループを作成します。
グループ名は「faq_group」にしていますが任意です。
次に、中に入れる項目の設定です。

今回は、QとAですが、Qは「テキスト」Aは「テキストエリア」にしてみました。
Aに改行が入ったり、長い文章になると予想する場合はテキストエリアにした方が良いと思います。
プラグイン側の設定はもうこれで終了です。
Q(質問)用設定
- タイプ:テキスト
 - ラベル:質問
 - 名前:question
 
A(回答)用設定
- タイプ:テキストエリア
 - ラベル:回答
 - 名前:answer
 
この項目以外は空白でOKです。
さらに、どこにこのカスタムフィールドを出すかですが、今回は「FAQ」というタイトルの固定ページを作成したので、右側に出てくるサイドメニューから、この固定ページIDを選択します。

ということで、該当の固定ページの編集画面を見てみると…

こんな風に質問と回答の入力欄が出現しております。
「繰り返し」にチェックを入れただけで、項目追加したり削除したりできるのめっちゃ便利。
Smart Custom Fieldsの出力
では、いざ出力していこうじゃありませんか。
今回、開閉式のアコーディオンなので、あらかじめそれはコーディングしておいたとします。
- 
スプラトゥーン3で好きな武器は何ですか?
 - 
ロングブラスター・シャープマーカーネオです。
 - 
第6回Abemaトーナメントが始まりましたが、どの チームを応援しますか?
 - 
もちろん今年もチーム菅井を応援しますが、エントリーチームに郷田真隆九段が入ったのでエントリーチームも真剣に応援します。
 
こんな感じです。
今回は、1つ目だけ開いておいて、2つ目以降は閉じておくという指定がありました。
一応htmlとか貼っておきます。
<div class="faq">
	<dl class="accordion js-accordion">
		<div class="accordion__item js-accordion-trigger is-active">
			<dt class="accordion__title">
				<p>スプラトゥーン3で好きな武器は何ですか?</p>
			</dt>
			<dd class="accordion__content is-open">
				<div class="txt-area">ロングブラスター・シャープマーカーネオです。 </div>
			</dd>
		</div>
		<div class="accordion__item js-accordion-trigger is-active">
			<dt class="accordion__title">
				<p>第6回Abemaトーナメントが始まりましたが、どの チームを応援しますか?</p>
			</dt>
			<dd class="accordion__content is-open">
				<div class="txt-area">もちろん今年もチーム菅井を応援しますが、エントリーチームに郷田真隆九段が入ったのでエントリーチームも真剣に応援します。 </div>
			</dd>
		</div>
	</dl>
</div>.border-box p {
	padding-left: 0;
}
.faq {
	margin-top: 60px;
	max-width: 500px;
	margin-bottom: 60px;
}
.faq dt {
	background: #466a92;
	color: #fff;
	font-size: 18px;
	padding: 10px;
	margin-bottom: 20px;
	padding-right: 30px;
	display: flex;
	flex-wrap: wrap;
	position: relative;
	cursor: pointer;
}
.faq .is-active dt {
	margin-bottom: 0;
}
.faq dt::before {
	content: "Q.";
	display: block;
	width: 25px;
}
.faq dt p {
	width: calc(100% - 25px);
	padding-bottom: 0;
}
.faq dd {
	padding: 30px;
	background: white;
	display: none;
	cursor: pointer;
}
.faq dd .txt-area::before {
	content: "A.";
	padding-right: 10px;
}
.faq dd .txt-area p {
	margin-bottom: 10px;
}
.faq dt::after {
	font-family: fontawesome;
	content: "\f077";
	font-size: 20px;
	right: 10px;
	display: block;
	position: absolute;
	margin: auto;
	transition: .4s;
}
.accordion__content.is-open {
	display: block;
}
.accordion__item.is-active .accordion__title::after {
	transform: rotate(180deg);
}const slideUp = (el, duration = 300) => {
  el.style.height = el.offsetHeight + "px";
  el.offsetHeight;
  el.style.transitionProperty = "height, margin, padding";
  el.style.transitionDuration = duration + "ms";
  el.style.transitionTimingFunction = "ease";
  el.style.overflow = "hidden";
  el.style.height = 0;
  el.style.paddingTop = 0;
  el.style.paddingBottom = 0;
  el.style.marginTop = 0;
  el.style.marginBottom = 0;
  setTimeout(() => {
    el.style.display = "none";
    el.style.removeProperty("height");
    el.style.removeProperty("padding-top");
    el.style.removeProperty("padding-bottom");
    el.style.removeProperty("margin-top");
    el.style.removeProperty("margin-bottom");
    el.style.removeProperty("overflow");
    el.style.removeProperty("transition-duration");
    el.style.removeProperty("transition-property");
    el.style.removeProperty("transition-timing-function");
    el.classList.remove("is-open");
  }, duration);
};
const slideDown = (el, duration = 300) => {
  el.classList.add("is-open");
  el.style.removeProperty("display");
  let display = window.getComputedStyle(el).display;
  if (display === "none") {
    display = "block";
  }
  el.style.display = display;
  let height = el.offsetHeight;
  el.style.overflow = "hidden";
  el.style.height = 0;
  el.style.paddingTop = 0;
  el.style.paddingBottom = 0;
  el.style.marginTop = 0;
  el.style.marginBottom = 0;
  el.offsetHeight;
  el.style.transitionProperty = "height, margin, padding";
  el.style.transitionDuration = duration + "ms";
  el.style.transitionTimingFunction = "ease";
  el.style.height = height + "px";
  el.style.removeProperty("padding-top");
  el.style.removeProperty("padding-bottom");
  el.style.removeProperty("margin-top");
  el.style.removeProperty("margin-bottom");
  setTimeout(() => {
    el.style.removeProperty("height");
    el.style.removeProperty("overflow");
    el.style.removeProperty("transition-duration");
    el.style.removeProperty("transition-property");
    el.style.removeProperty("transition-timing-function");
  }, duration);
};
const slideToggle = (el, duration = 300) => {
  if (window.getComputedStyle(el).display === "none") {
    return slideDown(el, duration);
  } else {
    return slideUp(el, duration);
  }
};
/* =================================================== */
// DOM操作
/* =================================================== */
// アコーディオンを全て取得
const accordions = document.querySelectorAll(".js-accordion");
// 取得したアコーディオンをArrayに変換(IE対策)
const accordionsArr = Array.prototype.slice.call(accordions);
accordionsArr.forEach((accordion) => {
  // Triggerを全て取得
  const accordionTriggers = accordion.querySelectorAll(".js-accordion-trigger");
  // TriggerをArrayに変換(IE対策)
  const accordionTriggersArr = Array.prototype.slice.call(accordionTriggers);
  accordionTriggersArr.forEach((trigger) => {
    // Triggerにクリックイベントを付与
    trigger.addEventListener("click", () => {
      // '.is-active'クラスを付与or削除
      trigger.classList.toggle("is-active");
      // 開閉させる要素を取得
      const content = trigger.querySelector(".accordion__content");
      // 要素を展開or閉じる
      slideToggle(content);
    });
  });
});今回のアコーディオンのjsはhttps://web-dev.tech/front-end/javascript/accordion/さんからお借りしました!
ここに、カスタムフィールドを組み込んでいく訳です。
カスタムフィールドのプラグインは、出力タグが決まっているので、検索したら大体答えは拾えます。
試してうまくいかなくても、他の方法を試したり、試行錯誤してみてください![]()
今回使ったコードはこちらです。
<dl class="accordion js-accordion">
	<?php
			$free_item = SCF::get('faq_group',13);
			foreach ($free_item as $fields) { 
	?>
	 <div class="accordion__item js-accordion-trigger">
				<dt class="accordion__title"><p><?php echo $fields['question']; ?></p></dt>
				<dd class="accordion__content">
					<div class="txt-area">
				 	<?php echo nl2br($fields['answer']); ?>
				 </div>
		 	</dd>
		</div>
	<?php } ?>
</dl>まず、
$free_item = SCF::get('faq_group',13);
foreach ($free_item as $fields) {
固定ページID13の、faq_groupというカスタムフィールドグループを使いますよ、という呪文です。
出力は、質問のテキストが入っていたところに<?php echo $fields['question']; ?>を入れ、答えが入っていたところに<?php echo nl2br($fields['answer']); ?>を入れています。
nl2brを追加することで、テキストエリアに入力した改行が適用されるようになります。
ここで、あれ?と思った方は天才です。
これだと、このまま繰り返しになります。
最初の1つ目を開けておくための、is-openとis-activeというclassが付けられていないので、1つ目が開いていない状態になってしまいます。
javascriptを書き換えるとか、cssを工夫するとかありますが、一番シンプルな方法にしました。
なんでしょう?
jQueryで無理やり一つ目にclassを追加しました!
$(function () {
  $('dl.accordion div.accordion__item:first-child').addClass('is-active');
  $('dl.accordion div.accordion__item:first-child .accordion__content').addClass('is-open');
});どうやったら分かりやすくて、最速で終われるかを考えるのが好きです。
こういう案件が来たら、ぜひ試してみてくださいね![]()
いいなと思ったら
TAPしてね♡↓
twitterの代わりにWordPressを使って今の気持ちを投稿してみる WordPress標準カラムを横スクロールにする【CSS】カスタマイズコード

 
 
 
 
 
 
 
 
コメントは承認後に表示されます。