Advertisement
Plugins

Integrating Multiple Choice Quizzes in WordPress – Creating the Frontend

by

This is the second part of the series on developing a multiple choice quiz plugin for WordPress. In the first part we created the backend of our plugin to capture the necessary data to store in the database.

In this final part, we will be creating the frontend of the plugin where the users can take quizzes and evaluate their knowledge.

The following topics will be covered in this part of completing our plugin:

  • Create a Shortcode to Display a Quiz
  • Integrating a jQuery Slider to Display Questions and Navigation
  • Completing a Quiz and Generating Results
  • Creating a Quiz Timer

We will need a considerable amount of questions in the backend to generate random quizzes. I hope that you already worked with the backend and stored enough questions for quizzes.

So let's get started.


Create a Shortcode to Display a Quiz

First we should have a post or page which loads the display elements of the quiz. This can be achieved by using either a shortcode or page template. In this plugin, a shortcode will be used to make it independent from the theme.

Shortcodes allow us to use the plugin as an independent component while page templates depend on the theme. On the other hand, a page template is much more secure than shortcodes as there is a possibility of deleting shortcodes inside pages by mistake.

Initially, the shortcode should output the available quiz categories so that the users can select a category to generate the quiz. A shortcode will be added in the constructor using the add_shortcode function as given in the following code.

add_shortcode( 'wpq_show_quiz', array( $this, 'wpq_show_quiz' ) );

Now, let's look at the implementation for the shortcode by retrieving available quiz categories from the database.

function wpq_show_quiz( $atts ) {

	global $post;

	$html = '<div id="quiz_panel"><form action="" method="POST">';

	$html .= '<div class="toolbar">';

	$html .= '<div class="toolbar_item"><select name="quiz_category" id="quiz_category">';

	// Retrive the quiz categories from database

	$quiz_categories = get_terms( 'quiz_categories', 'hide_empty=1' );

	foreach ( $quiz_categories as $quiz_category ) {

		$html .= '<option value="' . $quiz_category->term_id . '">' . $quiz_category->name . '</option>';

	}

	$html .= '</select></div>';

	$html .= '<input type="hidden" value="select_quiz_cat" name="wpq_action" />';

	$html .= '<div class="toolbar_item"><input type="submit" value="Select Quiz Category" /></div>';

	$html .= '</form>';

	$html .= '<div class="complete toolbar_item" ><input type="button" id="completeQuiz" value="Get Results" /></div>';

	// Implementation of Form Submission

	// Displaying the Quiz as unorderd list

	return $html;

}

Our shortcode will generate the HTML form and necessary controls used for the quiz. We retrieve the list of available quiz categories into a drop down field to let the user select the prefered category. We can use the get_terms function with hide_empty=1 to get the quiz categories which have at least one question.

A hidden field called wpq_action is used to check the $_POST values after submission.

After you insert the shortcode into a page or post, output will look like the following screen.

Screenshot-204

Now the user can select a quiz category and submit the form in order to get the quiz. So we are going to handle the form submission inside a shorcode to get the selected category and retrieve random questions for quizzes.

The following code contains the implementation of retrieving questions from a selected category.

$questions_str = "";

if ( isset( $_POST['wpq_action'] ) && 'select_quiz_cat' == $_POST['wpq_action'] ) {

	$html .= '<div id="timer" style="display: block;"></div>';
	$html .= '<div style="clear: both;"></div></div>';

	$quiz_category_id = $_POST['quiz_category'];
	$quiz_num = get_option( 'wpq_num_questions' );
	$args = array(
		'post_type' => 'wptuts_quiz',
		'tax_query' => array(
			array(
				'taxonomy' => 'quiz_categories',
				'field' => 'id',
				'terms' => $quiz_category_id
			)
		),
		'orderby' => 'rand',
		'post_status' => 'publish',
		'posts_per_page' => $quiz_num
	);

	$query = new WP_Query( $args );

	$quiz_index = 1;
	while ( $query->have_posts() ) : $query->the_post();

		// Generating the HTML for Questions

	endwhile;
	wp_reset_query();

	// Embedding Slider
}
else {
	$html .= '<div id="timer" style="display: none;"></div>';
	$html .= '<div style="clear: both;"></div></div>';
}

The code given should be included into the Implementation of Form Submission section of the previous code.

Once the form is submitted, we check whether the form contains the required action using the hidden field we generated earlier. Then we get the selected quiz category from the $_POST array.

Then we query the database for wptuts_quiz posts with the selected quiz category.

It's important to set orderby as rand to generate random questions for quizzes, which otherwise will generate the same set of questions each time. Also, make sure to set posts_per_page to set the maximum number of questions per any given quiz.

Once the results are generated we need to add the questions into the necessary HTML elements and we will be implementing it in the next section.


Integrating a jQuery Slider to Display Questions and Navigation

Quizzes can be generated as a screen which contains all the questions at once, or screen which contains one question at a time with navigation controls. I believe that the latter technique is the favorite among most people. Therefore, we are going to display this quiz with a single question and navigation for traversing to previous and next questions.

Generating this functionality from scratch can be a time consuming task as well as reinventing the wheel. A jQuery slider will be the perfect solution for this situation and I'll be using RhinoSlider, as it's my favorite, so grab a copy.

Inside the downloaded folder, you will see three folders called img, js, and css. Copy the img and css folders into our plugin and copy the files inside the js folder to the existing js folder we have on our quiz plugin. Now we can get started on including the necessary scripts and styles for the slider.

Including Frontend Scripts

In the first part, we created the necessary scripts for the backend. In this part we are going to include the necessary scripts for RhinoSlider as well as quiz.js for custom functionality.

For larger applications, we can use separate script files for both frontend and backend. I'll be using one script file to make things simpler.

Consider the following code for including scripts and necessary configuration data.

function wpq_frontend_scripts() {

	wp_register_script( 'rhino', plugins_url( 'js/rhinoslider-1.05.min.js', __FILE__ ), array( 'jquery' ) );

	wp_register_script( 'rhino-mousewheel', plugins_url( 'js/mousewheel.js', __FILE__ ), array( 'jquery' ) );

	wp_register_script( 'rhino-easing', plugins_url( 'js/easing.js', __FILE__ ), array( 'jquery' ) );

	wp_register_script( 'quiz', plugins_url( 'js/quiz.js', __FILE__ ), array( 'jquery', 'rhino', 'rhino-mousewheel', 'rhino-easing' ) );

	wp_enqueue_script( 'quiz' );

	$quiz_duration = get_option( 'wpq_duration' );

	$quiz_duration = ( ! empty( $quiz_duration ) ) ? $quiz_duration : 300;

	$config_array = array(

		'ajaxURL' => admin_url( 'admin-ajax.php' ),

		'quizNonce' => wp_create_nonce( 'quiz-nonce' ),

		'quizDuration' => $quiz_duration,

		'plugin_url' => $this->plugin_url

	);

	wp_localize_script( 'quiz', 'quiz', $config_array );

}

Here we have three JavaScript files used for the RhinoSlider and the quiz.js file for custom functionality. In the previous part, we configured the duration of the quiz. We can retrieve the duration using the get_option function and assign it to the $config array. Also, we have to include common configurations in the config array.

Finally we can use the wp_localize_script function to assign the config data in the quiz.js file.

Including Frontend Styles

Similarly we can include the CSS files required for Rhino Slider using the following code.

function wpq_frontend_styles() {

	wp_register_style( 'rhino-base', plugins_url( 'css/rhinoslider-1.05.css', __FILE__ ) );

	wp_enqueue_style( 'rhino-base' );

}

Finally we need to update the plugin constructor to add the necessary actions for including scripts and styles as given in the following code.

add_action( 'wp_enqueue_scripts', array( $this, 'wpq_frontend_scripts' ) );

add_action( 'wp_enqueue_scripts', array( $this, 'wpq_frontend_styles' ) );

Everything is ready to integrate the slider with questions into the shortcode we created earlier. Let's move forward.

Embedding the Slider Into the Shortcode

We currently have two comments inside the shortcode function, mentioning "Generating HTML for Questions" and "Embedding Slider". Those sections need to be updated with respective code to generate a slider. First we need to update the while loop as follows.

while ( $query->have_posts() ) : $query->the_post();

	$question_id = get_the_ID();

	$question = the_title( '', '', FALSE ) . ' ' . get_the_content();

	$question_answers = json_decode( get_post_meta( $question_id, '_question_answers', true ) );

	$questions_str .= '<li>';

	$questions_str .= '<div class="ques_title"><span class="quiz_num">' . $quiz_index . '</span>' . $question . '</div>';

	$questions_str .= '<div class="ques_answers" data-quiz-id="' . $question_id . '">';

	$quiestion_index = 1;

	foreach ( $question_answers as $key => $value ) {

		if ( '' != $value ) {

			$questions_str .= $quiestion_index . ' <input type="radio" value="' . $quiestion_index . '" name="ans_' . $question_id . '[]" />' . $value . '<br/>';

		}

		$quiestion_index++;

	}

	$questions_str .= '</div></li>';

	$quiz_index++;

endwhile;

Code Explanation

  • Inside the loop, first we get the question by concatenating the title and content field for questions.
  • Then we retrieve the answers of each question by using the get_post_meta function.
  • Inside the foreach loop, all the answers will be assigned to the radio buttons with necessary values.
  • Necessary list items will be assigned inside the loop including the HTML data attributes, which will come in handy in the next section.
  • Final output of the while loop will be a string variable which contains the list of questions and their answers embedded in HTML.

Next we need to create the containers for the slider in the section commented as "Embedding Slider". The following code contains the HTML code for creating containers.

$html .= '<ul id="slider">' . $questions_str;

$html .= '<li id="quiz_result_page"><div class="ques_title">Quiz Results <span id="score"></span></div>';

$html .= '<div id="quiz_result"></div>';

$html .= '</li></ul></div>';

We will be using an unordered list called slider as the container for Rhino Slider. Initially we include the set of questions and answers generated inside the loop, using $questions_str. It will contain a collection of list items.

Then we have to manually create another list item to show the results of the quiz and the score.

Now all the data and slides required for the quiz application are configured. We can initialize Rhino Slider in quiz.js to see the quiz in action.

jQuery(document).ready(function($) {

	$('#slider').rhinoslider( {

		controlsMousewheel: false,

		controlsPlayPause: false,

		showBullets: 'always',

		showControls: 'always'

	} );

} );

I have used some custom CSS styles to improve the look and feel. You can find all the modified CSS under the wp_quiz section of the rhinoslider-1.05.css file. Now you should have something like the following image.

Screenshot-206

Completing the Quiz and Generating Results

Once the quiz is loaded, you can use the navigation controls to move between questions and select the answers. You should click the "Get Results" button once all questions are answered. Now we need to create the quiz results using an AJAX request.

Let's implement the jQuery code for making the AJAX request.

$("#completeQuiz").click(function() {

	wpq_quiz_results();

});

var wpq_quiz_results = function() {

	var selected_answers = {};

	$(".ques_answers").each(function() {

		var question_id = $(this).attr("data-quiz-id");

		var selected_answer = $(this).find('input[type=radio]:checked');

		if ( selected_answer.length != 0 ) {

			var selected_answer = $(selected_answer).val();

			selected_answers["qid_"+question_id] = selected_answer;

		}
		else {

			selected_answers["qid_"+question_id] = '';

		}

	} );

	// AJAX Request

};

Once the "Get Results" button is clicked, we call the wpq_quiz_results function using jQuery. Each question was added to the slider with a special CSS class called ques_answers.

While traversing through each element with the ques_answers class, we retrieve the question ID using the HTML data-attribute called data-quiz-id and the selected radio button using jQuery.

Finally we assign all the questions and the selected answers into an array called selected_answers, to be passed into the AJAX request.

Take a look at the following code for implementation of the AJAX request.

$.post(quiz.ajaxURL, {

	action: "get_quiz_results",

	nonce: quiz.quizNonce,

	data: selected_answers,

}, function(data) {

	// AJAX result handling code

}, "json" );

First we create the AJAX request using the configuration data assigned from the wpq_frontend_scripts function. The answers list generated in the previous section will be sent as the data parameter. Before handling the result, we have to look at the implementation of server side code in the following section.

Creating an AJAX Handler on the Server Side

First we have to update the constructor with the actions necessary for using AJAX for both logged in users and normal users as shown in the following code.

add_action( 'wp_ajax_nopriv_get_quiz_results', array( $this, 'get_quiz_results' ) );

add_action( 'wp_ajax_get_quiz_results', array( $this, 'get_quiz_results' ) );

Then we can move into the implementation of the get_quiz_results function as shown in the following code.

function get_quiz_results() {

	$score = 0;

	$question_answers = $_POST["data"];

	$question_results = array();

	foreach ( $question_answers as $ques_id => $answer ) {

		$question_id = trim( str_replace( 'qid_', '', $ques_id ) ) . ',';

		$correct_answer = get_post_meta( $question_id, '_question_correct_answer', true );

		if ( $answer == $correct_answer ) {

			$score++;

			$question_results["$question_id"] = array( "answer" => $answer, "correct_answer" => $correct_answer, "mark" => "correct" );

		}
		else {

			$question_results["$question_id"] = array( "answer" => $answer, "correct_answer" => $correct_answer, "mark" => "incorrect" );

		}

	}

	$total_questions = count( $question_answers );

	$quiz_result_data = array(

		"total_questions" => $total_questions,

		"score" => $score,

		"result" => $question_results

	);

	echo json_encode( $quiz_result_data );

	exit;

}

Code Explanation

  • Selected answers for all the questions will be received using the data parameter inside the $_POST array.
  • Then we retrieve the question ID of each question by replacing the qid_ prefix.
  • Next we receive the correct answer of each question from the database using the get_post_meta function.
  • Next we check whether the provided answer matches the correct answer and create $question_results based on the status of the result.
  • While checking the answers, we need to update the quiz score using the $score variable.
  • Finally we assign the quiz results and scores to the $quiz_result_data array to be sent as the response.

Up to now, we created the AJAX request and implemented the server side response. In the next section we are going to complete the quiz results generation process by handling the AJAX response.

Handling AJAX Response Data

In the response handling part, we have quite a few tasks including the display of quiz results and scores. So I am going to separate the code into a few sections to make the explanation clear. Consider the following code which contains the complete AJAX request.

$.post(
	quiz.ajaxURL,
	{

		action: 'get_quiz_results',

		nonce: quiz.quizNonce,

		data: selected_answers

	},
	function(data) {

		// Section 1

		var total_questions = data.total_questions;

		$('#slider').data('rhinoslider').next($('#rhino-item' + total_questions));

		$('#score').html( data.score + '/' + total_questions);

		// Section 2

		var result_html = '<table>';

		result_html += '<tr><td>Question</td><td>Answer</td><td>Correct Answer</td><td>Result</td></tr>';

		var quiz_index = 1;

		$.each(data.result, function( key, ques ) {

			result_html += '<tr><td>' + quiz_index + '</td><td>' + ques.answer + '</td><td>' + ques.correct_answer + '</td>';

			result_html += '<td><img src="' + quiz.plugin_url + 'img/' + ques.mark + '.png" /></td></tr>';

			quiz_index++;

		});

		result_html += '<tr><td>&nbsp;</td><td></td><td></td>';

		result_html += '<td></td></tr>';

		// Section 3

		$('#quiz_result').parent().css('overflow-y','scroll');

		$('#quiz_result').html(result_html);

		$('#timer').hide();

	},
	'json'
);

Explanation of Section 1

First, we retrieve the total questions of the quiz from the response received from the server. Then we use the next function of Rhino Slider to redirect the user to the results slide. Then we set the user score with the total questions inside the #score container.

Explanation of Section 2

The initial part of this code generates the HTML table with necessary headings to display the results. Then we assign the questions to the table inside the jQuery each loop. We have used two images to display the success or failure status of the question.

Explanation of Section 3

Initially we have to allow scrolling in the results page as it can be quite long for quizzes with a large number of questions. The CSS overflow-y attribute is used to allow scrolling. Finally we set the quiz results table into the #quiz_result container and hide the timer, which we will be implementing in the next section.

Once the quiz is completed, your screen should look like something similar to the following image.

Screenshot-207

Creating a Quiz Timer

Usually any exam or quiz has a predefined time frame. So we are going to use the duration we configured in the settings page of our plugin to generate the quiz timer. We have already configured the timer to be hidden on initial page load, and to be visible on form submission, in the shortcode.

Let's focus on the dynamically changing timer using jQuery code as shown in the following.

var duration = quiz.quizDuration * 60;

$(document).ready(function($) {

	setTimeout("startPuzzleCount()",1000);

});

var startPuzzleCount = function() {

	duration--;

	$('#timer').html(duration+" Seconds Remaining");

	if ( duration == '0' ) {

		$('#timer').html("Time Up");

		wpq_quiz_results();

		return;

	}

	setTimeout("startPuzzleCount()",1000);

};

Quiz duration is retrieved using the configuration array passed using the wp_localize_script function. Duration is then converted into seconds by multiplying by 60.

Then we create a setTimeout function to start the timer. Inside the function, we reduce the duration by 1 and assign to the #timer container. When the time gets down to zero, we call the wpq_quiz_results function to automatically complete the quiz and generate the results.

Finally, we call the setTimeout function recursively to update the remaining time. We have completed the implementation of the timer and your quiz should look like the following image with the timer.

Screenshot-205

Wrap Up

Throughout this two-part series, we developed a simple and complete multiple choice quiz plugin for WordPress. You can extend the functionality of this plugin to suit the requirements of your application. I suggest you could improve the plugin by trying out the following:

  • Create a way to assign questions to quizzes instead of generating random quizzes.
  • Save the quiz results for logged in users.
  • Create a quiz competition between users.

Let me know your suggestions and how it goes with the plugin extending process.

Looking forward to hearing from you.

Related Posts
  • Web Design
    HTML & CSS
    Build a Dynamic Grid with Salvattore and Bootstrap in 10 MinutesSalvatorre thumb
    Today, we will use Salvattore in combination with Twitter Bootstrap 3 to make a responsively awesome flowing grid structure.Read More…
  • Code
    Theme Development
    Custom Controls in the Theme CustomizerTheme customizer custom control 400
    In the last article, we explored the advanced controls available in the Theme Customizer, and how to implement them. We’re going to look at how to create our own custom control, allowing you to choose which Category of Posts are displayed on the home page. To get started, download version 0.6.0 of our Theme Customizer Example.Read More…
  • Code
    HTML5
    HTML5: Battery Status APIPdl54 preview image@2x
    The number of people browsing the web using mobile devices grows every day. It's therefore important to optimize websites and web applications to accommodate mobile visitors. The W3C (World Wide Web Consortium) is well aware of this trend and has introduced a number of APIs that help with this challenge. In this article, I will introduce you to one of these APIs, the Battery Status API.Read More…
  • Code
    JavaScript & AJAX
    Working With IndexedDB - Part 3Indexeddb retina preview
    Welcome to the final part of my IndexedDB series. When I began this series my intent was to explain a technology that is not always the most... friendly one to work with. In fact, when I first tried working with IndexedDB, last year, my initial reaction was somewhat negative ("Somewhat negative" much like the Universe is "somewhat old."). It's been a long journey, but I finally feel somewhat comfortable working with IndexedDB and I respect what it allows. It is still a technology that can't be used everywhere (it sadly missed being added to iOS7), but I truly believe it is a technology folks can learn and make use of today. In this final article, we're going to demonstrate some additional concepts that build upon the "full" demo we built in the last article. To be clear, you must be caught up on the series or this entry will be difficult to follow, so you may also want to check out part one.Read More…
  • Code
    JavaScript & AJAX
    Working With IndexedDB - Part 2Indexeddb retina preview
    Welcome to the second part of my IndexedDB article. I strongly recommend reading the first article in this series, as I'll be assuming you are familiar with all the concepts covered so far. In this article, we're going to wrap up the CRUD aspects we didn't finish before (specifically updating and deleting content), and then demonstrate a real world application that we will use to demonstrate other concepts in the final article.Read More…
  • Code
    Plugins
    Integrating Multiple Choice Quizzes in WordPress - Creating the BackendIntegrating multiple choice quizzes in wordpress
    Multiple choice questions are something that most of us have faced at least once in our life. We love them because we can provide correct answers by logically thinking about provided possibilities, even if we don't exactly know the correct answer. Also answering takes less time which makes it so popular. Creating a multiple choice quiz in WordPress can be a very exciting and profitable task. You can use it in your personal blog to attract more visitors, or you can create a premium section with advanced quizzes, or you can create quizzes focusing on popular certification exams. There are numerous possibilities for making it profitable.Read More…