Create an FAQ Accordion for WordPress With jQuery UI

Create an FAQ Accordion for WordPress With jQuery UI

Tutorial Details
  • Program: WordPress
  • Version: 3.0+
  • Difficulty: Easy
  • Estimated Completion Time: 30 min

Creating an FAQ section for your WordPress website is incredibly simple. We’re going to use WordPress Custom Post Types for the questions & answers. Then we’ll use a jQuery UI accordion to make a nice cross-browser accordion widget. Finally we’ll assign a shortcode so that we can put our FAQ on any page or post.

We’ll be creating this:


Step 1 Create the Directory and Files

  1. Create a new folder inside your theme folder called faq
  2. Inside the ‘faq‘ folder, create a new file called faq.php
  3. Create another file called faq.js

Step 2 Include the faq.php File

In your functions.php (located in the root directory of your theme) – include the faq.php file you created at the top.

/* functions.php */
include('faq/faq.php');

Step 3 Create the Custom Post Type

  1. To register the Custom Post Type, we are going to hook into the init action. We are using an anonymous function as the second parameter to help keep everything encapsulated in one place. This helps with readability and maintainability.
  2. Set up $labels and $args as seen below.
  3. At the end we call register_post_type('FAQ', $args)
  4. Now if you go into your Admin area you will see a new option in the menu – FAQ (as seen in the image below)
  5. Click Add New Question and enter a few Questions and Answers so that we have something to work with later on. Use the title field for the question, and the main content field for the answer. This allows us to enter any type of content into our answer (such as images & videos) as well as text.
/* Register the Custom Post Type */
/* faq.php */
add_action('init', function() {

	$labels = array(
		'name' => _x('FAQ', 'post type general name'),
		'singular_name' => _x('Question', 'post type singular name'),
		'add_new' => _x('Add New Question', 'Question'),
		'add_new_item' => __('Add New Question'),
		'edit_item' => __('Edit Question'),
		'new_item' => __('New Question'),
		'all_items' => __('All FAQ Questions'),
		'view_item' => __('View Question'),
		'search_items' => __('Search FAQ'),
		'not_found' => __('No FAQ found'),
		'not_found_in_trash' => __('No FAQ found in Trash'),
		'parent_item_colon' => '',
		'menu_name' => 'FAQ'
	);

	$args = array(
		'labels' => $labels,
		'public' => true,
		'publicly_queryable' => true,
		'show_ui' => true,
		'show_in_menu' => true,
		'query_var' => true,
		'rewrite' => true,
		'capability_type' => 'post',
		'has_archive' => true,
		'hierarchical' => false,
		'menu_position' => null,
		'supports' => array('title', 'editor', 'page-attributes')
	);
	register_post_type('FAQ', $args);
});

Step 4 Include jQuery, jQuery UI, and faq.js

  1. Load jQuery
  2. Load jQuery UI
  3. Load the stylesheet for the jQuery UI library
  4. Load our custom script faq.js
add_action( 'wp_enqueue_scripts', 'wptuts_enqueue' );
function wptuts_enqueue() {
	wp_register_style('wptuts-jquery-ui-style', 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.21/themes/south-street/jquery-ui.css');
	wp_enqueue_style('wptuts-jquery-ui-style');

	wp_register_script('wptuts-custom-js', get_template_directory_uri() . '/faq/faq.js', 'jquery-ui-accordion', '', true);
	wp_enqueue_script('wptuts-custom-js');
}

You’ll notice we only used one wp_enqueue_script call, because it’s important the JavaScript files are loaded in order as they are dependent on each other. Setting jquery-ui-accordion as a dependency makes sure this happens.


Step 5 Setup the Shortcode

Because we want to be able to put our FAQ Accordion on any page/post, we’re going to generate a shortcode. Using a shortcode means that we only have to type [faq] inside any post/page in the WordPress Editor to display our FAQ.

add_shortcode('faq', function() {
	return "Shortcode test";
});

Step 6 Get the FAQ Questions & Answers

We can get the data from our custom post type by using the get_posts() function.

  1. numberposts – Here you can limit how many FAQ questions are retrieved
  2. orderby and order – Allows us to change the order of the questions
  3. post_type – This is how we tell WordPress to only fetch our custom post type
add_shortcode('faq', function() {
	$posts = get_posts( array(
		'numberposts' => 10,
		'orderby' => 'menu_order',
		'order' => 'ASC',
		'post_type' => 'faq'
	)); //array of objects returned
});
/* example */
echo $posts[0]->post_content; // will output the answer from the first faq question.

Step 7 Generate the Markup for the jQuery UI Accordion

This is the markup needed for the jQuery UI Accordion :


<div id="wptuts-accordion">
	<h3><a href="">Question Will Go Here</a></h3>
	<div>Answer will be in this div.</div>
</div>

We can generate this by looping over the $posts array.

  1. First we use $faq to store the start of our HTML – we open up a div with an id of wptuts-accordion
  2. Next we start looping through all the posts and adding the result of sprintf to the $faq variable.
  3. sprintf will replace %1$s with the value retrieved from $post->post_title and %2$s with the value returned from $post->post_content
  4. We run $post->post_content through wpautop() to ensure it displays as it was authored in the admin area.
  5. Finally we close off the div and return $faq to output the HTML onto our page.
	$faq  = '<div id="wptuts-accordion">'; // the container, before the loop

	foreach ( $posts as $post ) {
		$faq .= sprintf(('<h3><a href="">%1$s</a></h3><div>%2$s</div>'),
			$post->post_title,
			wpautop($post->post_content)
		);
	}

	$faq .= '</div>'; // finish off by closing the container

	return $faq;

The Full Shortcode

add_shortcode('faq', function() {

	$posts = get_posts(array(  //Get the FAQ Custom Post Type
		'numberposts' => 10,
		'orderby' => 'menu_order',
		'order' => 'ASC',
		'post_type' => 'faq',
	));

	$faq  = '<div id="wptuts-accordion">'; //Open the container
	foreach ( $posts as $post ) { // Generate the markup for each Question
		$faq .= sprintf(('<h3><a href="">%1$s</a></h3><div>%2$s</div>'),
			$post->post_title,
			wpautop($post->post_content)
		);
	}
	$faq .= '</div>'; //Close the container

	return $faq; //Return the HTML.
});

Final Step

Phew! If you have got this far, well done – you’re nearly there! At the moment we’ve managed to output all the data needed for our accordion, all that’s left to do is place this in faq.js:

(function(){
	jQuery("#wptuts-accordion").accordion();
})();
Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • Don Atkinson

    Thanks heaps for this, very nice. Looking forward to getting stuck into it.

    • Shane Osbourne
      Author

      Happy to help :) Thanks for the kind words.

  • Pingback: Create an FAQ Accordion for WordPress With jQuery UI | Qtiva

  • http://www.jsxtech.com Jaspal Singh

    Great! tutorial.
    Thanks for sharing.

  • http://www.jahan24.com Mostafa

    Great! tutorial.
    thank you,

    • Shane Osbourne
      Author

      Glad you enjoyed it :)

  • Andrew

    This is a pretty awesome tutorial, thanks for sharing.

    • Shane Osbourne
      Author

      Thanks Andrew :)

  • http://stephenharris.info Stephen Harris

    Great tutorial! One suggestion: as you’ve done, register the scripts/styles on the wp_enqueue_scripts – but enqueue the scripts inside the shortcode callback. The same works for widgets. This means that your faq.js (and associated scripts/styles) are only enqueued when the shortcode is present on the page and not on every front-end page, regardless of whether the shortcode is being used on it or not.

    • Shane Osbourne
      Author

      That’s a great point! Certainly a best practice. Thanks.

    • http://maorchasen.com Maor Chasen

      Indeed a best practice. You rock, Stephen!

    • tracersa

      @Stephen. I am new to wordpress and still in learning phase so couldn’t really implement what you just said. Sorry if it sounds dumb can you explain where would I add it and how? Maybe a code will help?

  • Lucas Rolff

    Why would we do this in the functions.php file? And not making a plugin out of it? It would make more sense I think.

    • http://www.leachcreative.com Andrew

      I’m sure you could do it that way if you wanted, that’s just the way he chose to do it.

      • Lucas Rolff

        True, but afaik, normal ‘design rules’ in wordpress would be, to make it a plugin, instead of having something really theme specific.

        And especially on a tuts site about wordpress. It should be best practice to make it a plugin.

    • Shane Osbourne
      Author

      Well that depends!

      If you would like to create something that you can distribute easily to others – go ahead and make it into a plugin.

      We have not ‘hard-coded’ anything into the functions.php file (apart from including the faq.php file) and this means the FAQ directory could be picked up and dropped into another project very easily.

      In effect, this creates the same portability of a plugin, without the need to activate/reactivate in the plug-ins page.

      All down to personal preference I suppose, but on larger projects I swear it becomes an absolute PAIN to write all of your code as plug-ins!

      :)

    • dj

      Agree wholeheartedly! WP isn’t always an intuitive system to learn and I find it increasingly difficult to sort out when tuts on an “opinion leader” site such as Envato’s do not follow established “best-practices.” It would seem, to me at least, that an important part of an editors job would be to either kick back a tut for revisions when it didn’t follow them OR, at very least, mention the dalliance in the text and what the “best practice” should be. Being sort of new to this I’d really have to think about how to “plug-in-ify” it myself; but wouldn’t think it would be much (if any) extra work for a knowledgeable author (although I could be wrong.)

      • Shane Osbourne
        Author

        Hi DJ

        As mentioned above, the functionality provided here is encapsulated within its own directory. This means it can be transferred from project to project very easily.

        I like to add small features in this way to remove the need to activate/re-activist anything in the plugins admin panel.

        This is not uncommon. If you take a look at some of the premium WordPress themes available on ThemeForest, you’ll see that a lot of developers like to put most of the sites functionality directly in the
        Theme folder.

        I hope this helps you understand my reasoning a little better. :)

  • http://pippinsplugins.com Pippin

    Please don’t use anonymous functions for setting up your post types or short code. When you use anonymous functions, it makes it much harder for developers to unregister your post type or short code when needed. There’s absolutely no benefit to anonymous functions in this case, so just don’t do it.

    Good tutorial otherwise :)

    • Shane Osbourne
      Author

      That’s a good point if you have other people working on a project, or if you are using other people’s plug-ins also.

      You have a strong opinion based on your own experience, but this is not representative of every WordPress developer on the planet – I’m afraid.

      If you are the sole developer of a website and have control over it, there’s absolutely nothing wrong with coding in this way.

      “There’s absolutely no benefit to anonymous functions in this case, so just don’t do it.” – again this is a projection based on your own experiences – not entirely true for every person reading this article.

      Thanks for your feedback. :)

    • Shane Osbourne
      Author

      To clarify my point Pippin –

      I find it very useful to write code in his way because it’s more compact and readable at the same time. I also find it easier to maintain too, because everything associated with an action is encapsulated in 1 place.

      I do realise however, that this may not be the best solution in all cases and it’s only my ‘opinion’.

      Thanks again for your feedback :)

    • http://pippinsplugins.com Pippin

      I can see your point for code that is only used by you, but as a public tutorial, it’s definitely best to be avoided, especially since many users simply cut and paste without really understanding it :)

      • Shane Osbourne
        Author

        Ah, that’s a good point actually, I never thought about it that way :)

  • http://ednailor.com Ed Nailor

    With WP 3.4. I tried the anonymous function (creating a specific theme for a client, not mass production) and got an error. Seems maybe the newest version of WP does not like the anonymous function added this way? Oh well, just the same. Keeps me in good habits on other projects… adding an extra line of code does not hurt me.

    Good Tutorial overall.

    • Shane Osbourne
      Author

      When writing this tutorial, I actually tested in Version 3.4 and didn’t encounter any problems. Could you post a code snippet?

    • http://stephenharris.info Stephen Harris

      Anonymous functions aren’t supported in PHP 5.2 – that’s probably the issue.

  • Mark

    Thanks for clear tutorial, but you might want to check where you’ve registered your post type as ‘FAQ’ (all caps but passed it into your query as ‘faq’ lowercase, this could cause an error?

    • Shane Osbourne
      Author

      Hi Mark

      All Custom Post Types end up being stored/called as all lowercase characters – so you shouldn’t get an error. I can see how this might be misleading though. Apologies for any confusion. (my bad :) )

  • http://www.netprofitmarketing.com/ Jared

    This is great! I’ve wanted to add a FAQ to my site as it’s good for visitors to answer some simple questions and it’s good for SEO. This implementation will make it nice and easy to use instead of having it all spread out over the page. Thanks for the example!

    • Shane Osbourne
      Author

      Hi Jared – Glad you liked the tutorial :)

  • http://www.greenflagseo.com Joe

    Question about the faq.php

    Do I start the code with

    And then in the functions.php the include should be within the of the document as well, right?

    Is it ok to have a <?php within another <?php

    I'm getting a T_function error and I am using HostGator with is PHP 5.2 so I'm going to try to change that to PHP 5.3 but I still want to make sure everything else is correct.

    Thank!

    • Alex

      I am also having this error, from what I know it should be okay but my theory is it has to do with the anonymous function which is in the faq.php , but I have no idea

    • Alex

      I found a solution. For some reason I had to declare the function for my Theme to accept it.

      add_action(‘init’, ‘faq_accordian’);

      function faq_accordian() {

      }

      oppose to

      add_action(‘init’, function() {
      ..
      });

      Hope it helped.

      • http://wp.envato.com/ Japh Thomson
        Staff

        Hey Alex, anonymous functions aren’t supported in PHP 5.2, so you would need to have been using a more recent version of PHP for it to work as shown. For example, PHP 5.3 or 5.4

      • http://inventikasolutions.com Pritesh Desai

        Thanks, I too faced that same problem. I cannot believe Green Geeks still haven’t upgraded to 5.3

      • http://inventikasolutions.com Pritesh Desai

        Warning: call_user_func_array() [function.call-user-func-array]: First argument is expected to be a valid callback, ‘‘faq_accordian’’ was given in /home/aaaa/public_html/example.com/wp-includes/plugin.php on line 403

        I got this error after declaring the functions.

        • http://inventikasolutions.com Pritesh Desai

          Solved the error. I had copied
          add_action(‘init’, ‘faq_accordian’);

          and the tiny ‘ character as opposed to the ‘ character caused the error :D

          and the faq accordian is simply brilliant!
          Thanks for the tutorial!

          • Shane Osbourne
            Author

            Hi there Pritesh Desai.

            I’m glad you like it & you’re welcome!

            :)

  • Joe

    Might be a dumb question – but do I have to also add jQuery and the jQuery UI source to the head of my site?

    • http://wp.envato.com/ Japh Thomson
      Staff

      No, WordPress does that for you because of this line:

      wp_register_script('wptuts-custom-js', get_template_directory_uri() . '/faq/faq.js', 'jquery-ui-accordion', '', true);
      

      We’re listing ‘jquery-ui-accordion‘ as a dependency of our script, so WordPress knows to load that, which depends on jQuery UI, which depends on jQuery. So they all get loaded in by WordPress to fulfil the dependencies. Neat huh? ;)

  • James

    This looks like it is exactly what I need and I have it working on site, except that the ‘accordian’ is not displaying.

    The faq.js is being called on the page, so I cannot work out what is causing the issue.

    Has anyone else experienced this problem?

    • James

      Sorted.

      It was child theme issue.

      Thanks for sharing.

  • Alex

    I received a “Parse error: syntax error, unexpected T_FUNCTION” error in the faq.php … I was frustrated to the point where I copy and pasted everything to make sure there were no syntax errors, and still there is a syntax error. Any reasons why this error appears?

    • http://onestarrynight.com Sarah @ OneStarryNight

      I’m also getting that error.

      Parse error: syntax error, unexpected T_FUNCTION in /faq/faq.php on line 3

  • Pingback: Tweet-Parade (no.25 June 2012) | gonzoblog.nl

  • Bekim

    How to make thumbnail on the right side of title? please help… everything else is great… i just have this little problem.

  • Pingback: Best of Tuts+ in June 2012 | Shadowtek Hosting and Design Solutions

  • Pingback: Create an FAQ Accordion for WordPress With jQuery UI | Apuntes WordPress

  • http://vedezevalnica-klepetalnica.si/ Bekim Lutolli

    I managed to finish site… just dont know how to make accordian to close first post which is open by default?

    Help please :(

    regards from Slovenia

    • Shane Osbourne
      Author

      Hi Bekim

      Try using this in your `faq.js` instead of what is provided in the tutorial

      (function(){
      jQuery(“#wptuts-accordion”).accordion({
      collapsible: true,
      active: false
      });
      })();

      I haven’t tested this code, I just researched the info on the jQuery UI website. Let me know if it works.

    • Shane Osbourne
      Author

      Hi again Bekim

      I looked at your site and it seems that you have managed to implement this successfully using the modified code I provided. That’s great, I’m glad it was useful to you :)

  • Pingback: Best of Tuts+ in June 2012 | How to Web

  • Pingback: Best of Tuts+ in June 2012 - Tutorial Barn

  • http://t.tt Cloud

    Hello, Nice work! I wanna konw how to display the scripts like you do in the WordPress? Does it need some plugins? Hope you can answer me.

  • http://rakateja.wordpress.com Made Raka Teja

    Its not work, jquery ui is not work

    • Parvez

      It is working fine

  • Suresh

    great tutorial…I am not very good at CSS. Could you help that how I can change the color from green to some othe colour of thsi FAQ?

  • http://walthamstowtimes.co.uk/ Serge

    Hi there,

    Many thanks for this neat tutorial.

    I was wondering if you could give me a hint of what am I doing wrong with the code as I am getting the same error as Alex above.

  • http://walthamstowtimes.co.uk/ Serge

    Oh, nevermind, thanks for the eventual intention. I have read all the comments above and made the change suggested by Alex .

    Thanks!

  • Wiggy

    This is the perfect tutorial I need but I’ve got a problem – I had to update to version 5.3 of php for this to work but in doing so it has caused errors in my site. Whenever I try to save an FAQ question or even try to create/ edit a post I get this error:

    Warning: Cannot modify header information – headers already sent by (output started at /home/wp-content/themes/bueno/faq/faq.php:1) in /home/wp-includes/pluggable.php on line 881

    I’m very new to WP so don’t know how to fix this. I’ve looked around and found whitespace in wp-config.php could cause this problem but i’ve checked it and there isn’t any.

    Any help would be great. Thanks.

  • Paul Bolger

    Nice tutorial. It’d be really useful to extend it – or do another – to show how to add new fields to a custom post type.

  • Bogdan

    Hello, Shane!
    In your tutorial (which is very useful), you mentioned “To register the Custom Post Type, we are going to hook into the init action” with the following code.
    As i’m beginner in WordPress, i can’t make it out how should i “to hook into the init action”. I tried to include the following code in functions.php and in faq.php, but no result. Could you pls explain where should i paste that code?
    Thanks a lot,
    Bogdan (Ukraine).

  • http://deaddroid.com Graham Morley

    Any idea why WordPress wouldn’t load the dependency? I’m finding it isn’t loading jquery-ui-accordion and it isn’t appearing when I view the source of the page. It loads several other UIs based on other plugins.. Is there possibly a conflict?

    • http://deaddroid.com Graham Morley

      I fixed it by adding the accordion ui manually..

      One other thing.. For those who just copy and paste, the .js file needs to look like this:

      jQuery(document).ready(function() {
      jQuery(“#my-accordion”).accordion();
      });

      Otherwise, fantastic tutorial. Saved me a ton of time. Thank you so much!

  • http://www.bazish.net Bazish

    Nice tutorial.

    thanks shane..

    i have few questions…

    we need to have faq’s on two different pages for two different categories. e.g. one page will be about web development questions and other will be regarding SEO faq’s,
    so my questions is how we implement two different faq’s for these two pages or two type of faq’s.?

    another questions is regarding fetching faq’s, you mentioned in faq.php to include 10 questions, yes we can increase it by editing the file, but can we have a setup page at wordpress admin or we implement a way to fetch all questions from faq to display on the page.

    regards
    Bazish

  • Giu

    I was looking for a tutorial like that, thanks!

    I would like to use it for displaying categories instead of faq titles and related children categories instead of faq text.

    I managed to make it work for categories, but I can’t figure out how to get the children categories to show up in the second div (%2$s) (bear with me please, I’m a new to this ;-)

    $args=array(
    ‘orderby’ => ‘name’,
    ‘include’ => ’34,15,45,35,82,16′,
    ‘order’ => ‘ASC’
    );

    $categories=get_categories($args);

    $faq = ”; ///Open the container
    foreach ( $categories as $category ){

    $faq .= sprintf((‘%1$s%2$s’), // Generate the markup for each Question
    $category->name,
    $category->Children categories ????,
    wpautop($categories->post_content)
    );
    }

    $faq .= ”; //Close the Container

    Any help would be much appreciated, thanks!

  • Brett

    Where does this script go?

    add_action( ‘wp_enqueue_scripts’, ‘wptuts_enqueue’ );
    function wptuts_enqueue() {
    wp_register_style(‘wptuts-jquery-ui-style’, ‘http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.21/themes/south-street/jquery-ui.css’);
    wp_enqueue_style(‘wptuts-jquery-ui-style’);
    wp_register_script(‘wptuts-custom-js’, get_template_directory_uri() . ‘/faq/faq.js’, ‘jquery-ui-accordion’, ”, true);
    wp_enqueue_script(‘wptuts-custom-js’);
    }

    I am guessing in the functions.php file? When I add it the website will not load at all.

    Thanks Brett!

  • Parvez

    O my god …..this is really cool………..I am grateful to you….please tell me anything I can do for you

  • http://kloningspoon.com/ Darto KLoning

    It’s great plugin that what i’m looking for but when i tried to follow your tutorial or download the file as you gave the link, it’s not working. I try with wordpress 3.4.2. It’s always gave me error 500. Could you help me?

  • anithedesigner

    Its a very nice…appreciate..But it does not working to me.

  • Pingback: 转载-Create an FAQ Accordion for WordPress With jQuery UI | iluther-专注web技术

  • http://twitter.com/sigmawebmktg Sigma Web Marketing

    Shane, Thanks so much for posting this. I want the height of the panels to fit the size of the content, so have beed trying:

    (function(){
    jQuery("#wptuts-accordion").accordion({
    icons: false,
    heightStyle: "content"
    });
    })();

    and it turns off the icons, but apparently leaves the height set to default (auto).

    How can I get the height to only be the height of the content in that panel? Thanks!!

  • Catherina Lucy

    I am very poor in programming side.I didn’t to know what the information.For every code you have provided can you provide the detailed explanation?

    http://www.accordionguide.info

  • Khan

    Great tut!
    PD: setting the function on the top with name works for me:

    function Faq() {

    $labels = array(
    ‘name’ => _x(‘FAQ’, ‘post type general name’),
    ‘singular_name’ => _x(‘Question’, ‘post type singular name’),
    ‘add_new’ => _x(‘Add New Question’, ‘Question’),
    ‘add_new_item’ => __(‘Add New Question’),
    ‘edit_item’ => __(‘Edit Question’),
    ‘new_item’ => __(‘New Question’),
    ‘all_items’ => __(‘All FAQ Questions’),
    ‘view_item’ => __(‘View Question’),
    ‘search_items’ => __(‘Search FAQ’),
    ‘not_found’ => __(‘No FAQ found’),
    ‘not_found_in_trash’ => __(‘No FAQ found in Trash’),
    ‘parent_item_colon’ => ”,
    ‘menu_name’ => ‘FAQ’
    );

    $args = array(
    ‘labels’ => $labels,
    ‘public’ => true,
    ‘publicly_queryable’ => true,
    ‘show_ui’ => true,
    ‘show_in_menu’ => true,
    ‘query_var’ => true,
    ‘rewrite’ => true,
    ‘capability_type’ => ‘post’,
    ‘has_archive’ => true,
    ‘hierarchical’ => false,
    ‘menu_position’ => null,
    ‘supports’ => array(‘title’, ‘editor’, ‘page-attributes’)
    );

    register_post_type(‘FAQ’, $args);
    };

    add_action(‘init’, ‘Faq’);