Creating a FAQ Page in WordPress using ACF and jQuery

How to create a FAQ page in WordPress using Advanced Custom Fields and jQuery.

ACF (Advanced Custom Fields) Pro comes with a great inclusion called the Repeater field which allows a user to continually add additional rows of data of certain custom fields to a page or post (or custom post type) in WordPress.

This can be an ideal client solution for adding repetitive data without having to enter code or risk user error on inadvertently messing up code.

This tutorial uses the repeater field on a Genesis theme but the process would be roughly the same on any WordPress theme

Setting up Advanced Custom Fields

Download and install ACF Pro (the Pro version is a paid plugin) create a new page/post in WordPress called FAQs then create a new custom field group also called faqs – this will have 2 sub-fields called faq_question and faq_answer.

 

acf faq page

Also in the location area you can target which post/page that you want the custom fields to appear in.

Target post

Target post

Doing it via a Post

Setting up a Custom Post Template

You can add the code conditionally to a single post and position it using a hook.

<?php //<~ don't add in functions.php
add_action( 'fl_post_bottom_meta_open', 'wpb_faq_repeater_page', 10 );//Position FAQs after post content - change your hook to suit
function wpb_faq_repeater_page () {
if( is_single( 11321 )) { //change post id to suit
// My ACF Fields for reference
// faqs - field group
// faq_question - sub-field
// faq_answer - sub-field
// check if the repeater field has rows of data
if( have_rows('faq') ):
// loop through the rows of data
while ( have_rows('faq') ) : the_row();
// display a sub field value
echo'<div id="faq_container">
<div class="faq">
<div class="faq_question"> <span class="question">' . get_sub_field('faq_question') . '</span><span class="accordion-button-icon fa fa-plus"></span></div>
<div class="faq_answer_container">
<div class="faq_answer"><span>' . get_sub_field('faq_answer') . '</span></div>
</div>
</div>
</div>';
endwhile;
else :
// no rows found
endif;
}
}

I have added some extra HTML mark up to allow for the FAQ question and answer to be put in containers that will be manipulated by jQuery.

 

So far, the custom fields for the FAQs are created and will publish to the page, what is now needed is some jQuery open/close effects and some CSS for styling.

Doing it via a Page

Targeting a Page Template

If you were targeting a page template instead, you would use instead…

<?php
/*
Template Name:FAQ Page
*/
add_action( 'genesis_entry_content', 'wpb_faq_repeater_page', 10 );//Position FAQs after post content
function wpb_faq_repeater_page () {
//My ACF Fields for reference
//faqs - field group
//faq_question - sub-field
//faq_answer - sub-field
// check if the repeater field has rows of data
if( have_rows('faq') ):
// loop through the rows of data
while ( have_rows('faq') ) : the_row();
// display a sub field value
echo'<div id="faq_container">
<div class="faq">
<div class="faq_question"> <span class="question">' . get_sub_field('faq_question') . '</span><span class="accordion-button-icon fa fa-plus"></span></div>
<div class="faq_answer_container">
<div class="faq_answer"><span>' . get_sub_field('faq_answer') . '</span></div>
</div>
</div>
</div>';
endwhile;
else :
// no rows found
endif;
}
genesis();

Setting Up the jQuery & CSS

The jQuery will open/close the container based on a click function. Create a file called faq.js and file in your themes js folder.

jQuery(document).ready(function($) {
$('.faq_question').click(function() {
if ($(this).parent().is('.open')){
$(this).closest('.faq').find('.faq_answer_container').animate({'height':'0'},500);
$(this).closest('.faq').removeClass('open');
$(this).parent().find('.accordion-button-icon').removeClass('fa-minus').addClass('fa-plus');
}
else{
var newHeight =$(this).closest('.faq').find('.faq_answer').height() +'px';
$(this).closest('.faq').find('.faq_answer_container').animate({'height':newHeight},500);
$(this).closest('.faq').addClass('open');
$(this).parent().find('.accordion-button-icon').removeClass('fa-plus').addClass('fa-minus');
}
});
});
view raw faq.js hosted with ❤ by GitHub

For CSS create a faq.css and add into your themes css folder

#faq_container {
border: 1px solid #e5e5e5;
margin-bottom: 10px;
padding: 10px 15px;
}
.faq_question {
margin: 0px;
padding: 0px 0px 5px 0px;
display: inline-block;
cursor: pointer;
font-weight: bold;
display: table;
}
.question {
margin-bottom: 5px;
display: table-cell;
width: 100%;
}
.faq_answer_container {
height: 0px;
overflow: hidden;
padding: 0px;
}
.accordion-button-icon {
display: table-cell;
line-height: inherit;
opacity: .5;
filter: alpha(opacity = 50);
padding-left: 15px;
vertical-align: middle;
}
view raw faq.css hosted with ❤ by GitHub

Set the jQuery script and CSS to fire only on this particular post by enqueing the script and style in your functions.php file. I also have enqueued fontawesome from a CDN as I want to use it’s + and – symbols.

<?php // <- don't add the opening php tag in
function themprefix_faq_script() {
if(is_single('11321')) {//add in your Post/Page ID - if this is a page use - is_page - instead of is_single
wp_enqueue_script( 'faq-js', get_stylesheet_directory_uri() . '/js/faq.js', array('jquery'), '1', true );
wp_enqueue_style ( 'faq-css' , get_stylesheet_directory_uri() . '/css/faq.css', '', '1', 'all' );
wp_enqueue_style ( 'fontawesome' , '//maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css', '' , '4.3.0', 'all' );
}
}
add_action( 'wp_enqueue_scripts', 'themprefix_faq_script' );

So above the jQuery and CSS is set to load and also fontawesome is referenced for the icons. I have styled the format to be similar to the FAQ module from the Beaver Builder plugin.

Some examples below.

6 Comments

  1. Toon van der Struijk on October 12, 2016 at 1:29 pm

    Haha, I just went one step further with this one.
    I added a checkbox field (‘faq_kind’) in ACF to the FAQ repeater, with three options: ‘option-a’, ‘option-b’ and ‘option-c’.
    Now you can assign one or multiple of these options to a single FAQ, and filter the output, like this:

    if( have_rows('faq') ){
    while ( have_rows('faq') ) : the_row();
    $faq_kind = get_sub_field('faq_kind');
    if ($faq_kind[0] == 'option-a') {
    echo '';
    echo '';
    echo ' ' . get_sub_field('faq_question') .'';
    echo '';
    echo '' . get_sub_field('faq_answer') . '';
    echo '';
    echo '';
    echo '';
    }
    endwhile;
    }


    This way you only see the FAQ’s with ‘option-a’ selected.

    • Toon van der Struijk on October 12, 2016 at 1:38 pm

      Hmmm,
      The code didn’t come through as expected, but you’ll get the idea.

  2. Toon van der Struijk on October 12, 2016 at 8:04 am

    Very Nice!
    And the beauty of using ACF is that you can manually sort the FAQ’s, or do it via PHP. A lot of flexibility here.
    I also put it into a shortcode, so you can use it anywhere in your site (page, post, widget):
    Just put this in your functions.php:

    function whd_faq_public () {
    $faq_id = 1485; // the id of the post or page where you handle the faqs
    if( have_rows('faq', $faq_id) ):
    while ( have_rows('faq', $faq_id) ) : the_row();
    echo'

    ' . get_sub_field('faq_question', $faq_id) . '

    ' . get_sub_field('faq_answer', $faq_id) . '

    ';
    endwhile;
    else :
    endif;
    }

    add_shortcode('faq-client', 'whd_faq_public');
    // The shortcode to use is [faq-client]

    Thank you Neil for a great tutorial!

  3. seematt on July 15, 2016 at 2:57 pm

    THANK YOU SO MUCH.

    I have been trying to find a simple way of incorporating the ACF repeater field into Genesis and I have struggled to find anything until now.

Leave a Comment





%d bloggers like this: