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.
This plugin won't take you through to creating quizzes for building a business, but we have to start somewhere to get where we want to go. So this would be a good start for creating quizzes and making profits out of it.
So let's get started.
Functionality of the Plugin
First we need to gather the requirements of the plugin before going to design or implementation. Basically, we should be able to create multiple choice quizzes and allow users to take the quizzes and get results.
So let's take a look at the detailed requirements and components of our plugin:
- The plugin should have a backend where we can insert questions and answers dynamically. Also it's ideal to have quiz categories to group quizzes into specific sections.
- Site admin should be able to configure the quizzes through a settings page.
- Users should have a frontend where they can take a quiz.
- Once a quiz is completed users should be able to get the scores and results.
This tutorial is going to be constructed as a two part series, where we develop the backend of the plugin in the first part, followed by the plugin frontend in the second part.
Planning the Plugin Backend
In this part we are going to focus on developing the backend of the plugin where we develop the required data for quizzes.
Usually there is a list of quizzes, each of them containing a specific list of questions. With this plugin we are not going to create quizzes. We will be creating individual questions and assigning them dynamically to quizzes when requested.
Now we can take time to identify the components required for implementing the backend as listed in the following section.
- Questions need to be created in the backend with the answers. A custom post type will be the best solution for implementing the questions. So we are going to use a custom post type called
wptuts_quiz
. - Each question should have multiple answers and one correct answer. Fields for answers will be created inside a meta box in the custom post creation screen.
- Questions will be categorized into various sub-topics hence we need a custom taxonomy called
quiz_categories
for thewptuts_quiz
post type. - Then we need to validate the question creation process. We will be using client side jQuery validations when necessary in question creation.
- Finally we need a plugin settings page to store the number of questions per quiz and the duration for a quiz.
Having identified the necessary WordPress components, we can directly move into implementing the backend of the quiz plugin.
Creating Questions
The question creation process consists of four main sections: defining custom post type, defining custom taxonomy, assigning custom fields, and validations. Each of these sections will be discussed with detailed code in the upcoming sections.
1. Creating the Questions Custom Post Type
We need the most basic form of custom post type for questions without any advanced configurations. The only thing we need to consider is the selection of the right field for the question.
The default post creation screen contains two fields for title and content. You can choose any of those fields for the question. I am going to choose concatenation of both title and content fields considering advanced possibilities.
We will be creating an object-oriented plugin instead of a functional plugin, so all of the necessary actions, shortcodes and initializations will be done inside the constructor. The following contains the code for implementing the wptuts_quiz
post type.
class WP_Quiz { public $plugin_url; public function __construct() { $this->plugin_url = plugin_dir_url( __FILE__ ); add_action( 'init', array( $this, 'wpq_add_custom_post_type' ) ); } public function wpq_add_custom_post_type() { $labels = array( 'name' => _x( 'Questions', 'wptuts_quiz' ), 'menu_name' => _x( 'WPTuts Quiz', 'wptuts_quiz' ), 'add_new' => _x( 'Add New ', 'wptuts_quiz' ), 'add_new_item' => _x( 'Add New Question', 'wptuts_quiz' ), 'new_item' => _x( 'New Question', 'wptuts_quiz' ), 'all_items' => _x( 'All Questions', 'wptuts_quiz' ), 'edit_item' => _x( 'Edit Question', 'wptuts_quiz' ), 'view_item' => _x( 'View Question', 'wptuts_quiz' ), 'search_items' => _x( 'Search Questions', 'wptuts_quiz' ), 'not_found' => _x( 'No Questions Found', 'wptuts_quiz' ), ); $args = array( 'labels' => $labels, 'hierarchical' => true, 'description' => 'WP Tuts Quiz', 'supports' => array( 'title', 'editor' ), 'public' => true, 'show_ui' => true, 'show_in_menu' => true, 'show_in_nav_menus' => true, 'publicly_queryable' => true, 'exclude_from_search' => false, 'has_archive' => true, 'query_var' => true, 'can_export' => true, 'rewrite' => true, 'capability_type' => 'post' ); register_post_type( 'wptuts_quiz', $args ); } }
We have enabled both title and editor fields in the custom post type to use for the question. Since the functions are located inside a class, we have to use $this
in our WordPress actions, filters, and shortcodes to call the functions.
Apart from that all the parameters mentioned in the code are initialized with their default values.
2. Creating the Question Categories
In order to group questions into specific sections, we need something similar to default WordPress categories. Hence we will be using a custom taxonomy called quiz_categories
. We need to call the custom taxonomy generation function on the init
action as we did earlier. So the constructor of our plugin class needs to be updated with the following code.
add_action( 'init', array( $this,'wpq_create_taxonomies' ), 0 );
Then we can implement the wpq_create_taxonomies
function on the wptuts_quiz
post type as shown in the following code.
function wpq_create_taxonomies() { register_taxonomy( 'quiz_categories', 'wptuts_quiz', array( 'labels' => array( 'name' => 'Quiz Category', 'add_new_item' => 'Add New Quiz Category', 'new_item_name' => "New Quiz Category" ), 'show_ui' => true, 'show_tagcloud' => false, 'hierarchical' => true ) ); }
I have used the default option parameters to create this custom taxonomy. Once the plugin is activated your custom post type and taxonomy will be displayed as shown in the following screen.
3. Creating the Question Answers
Next, we have to create multiple answers for each question. In this plugin the maximum number of answers per single question will be limited to five.
You can dynamically assign 1-5 answers for any question. Also we need to specify the correct answer from the provided list of answers. Since this data is associated with our questions, we can use a meta box with custom fields to generate the necessary fields.
As usual we need to update the constructor with the following code:
add_action( 'add_meta_boxes', array( $this,'wpq_quiz_meta_boxes' ) );
Consider the following code for the implementation of meta boxes with answers fields.
function wpq_quiz_meta_boxes() { add_meta_box( 'quiz-answers-info', 'Quiz Answers Info', array( $this, 'wpq_quiz_answers_info' ), 'wptuts_quiz', 'normal', 'high' ); } function wpq_quiz_answers_info() { global $post; $question_answers = get_post_meta( $post->ID, '_question_answers', true ); $question_answers = ( $question_answers == '' ) ? array( '', '', '', '', '' ) : json_decode( $question_answers ); $question_correct_answer = trim( get_post_meta( $post->ID, '_question_correct_answer', true ) ); $html = '<input type="hidden" name="question_box_nonce" value="' . wp_create_nonce( basename( __FILE__ ) ) . '" />'; $html .= '<table class="form-table">'; $html .= '<tr><th style=""><label for="Price">Correct Answer</label></th><td><select class="widefat" name="correct_answer" id="correct_answer" >'; for ( $i = 1; $i <= 5; $i++ ) { if ( $question_correct_answer == $i ) { $html .= '<option value="' . $i . '" selected >Answer ' . $i . '</option>'; } else { $html .= '<option value="' . $i . '">Answer ' . $i . '</option>'; } } $html .= '</select></td></tr>'; $index = 1; foreach ( $question_answers as $question_answer ) { $html .= '<tr><th style=""><label for="Price">Answer ' . $index . '</label></th>'; $html .= '<td><textarea class="widefat" name="quiz_answer[]" id="quiz_answer' . $index . '" >' . esc_textarea( trim( $question_answer ) ) . '</textarea></td></tr>'; $index++; } $html .= '</tr>'; $html .= '</table>'; echo $html; }
4. Code Explanation
- Answers of each question will be stored in a JSON encoded string in the
post_meta
table with the key_question_answers
. So we access this field using theget_post_meta
function to get the current values. - Then we get the correct answer of the question using a similar method. The correct answer will be stored as a string in the
post_meta
table with the key_question_correct_answer
. - Finally, we create the HTML form, which contains the correct answer as a dropdown box and the possible answers as five text area fields.
- All the existing values retrieved using the
get_post_meta
function will be assigned to the respective fields.
You should see something similar to the following screen, once you create the meta box.
Now we have all the data required for our quiz generation plugin. Next step is to save the question data into the database.
But we need some validations prior to that. So let's move into validations.
Validating Question Creation
We don't have complex validation rules at this stage in the question creation process. Therefore we are going to use client side jQuery validations before submission.
Here we need the admin_enqueue_scripts
action to be included into the constructor of our plugin.
So update the constructor with following code before we get started.
add_action( 'admin_enqueue_scripts', array( $this, 'wpq_admin_scripts' ) );
Now look at the following code for including necessary script files for validation.
function wpq_admin_scripts() { wp_register_script( 'quiz-admin', plugins_url( 'js/quiz.js', __FILE__ ), array( 'jquery' ) ); wp_enqueue_script( 'quiz-admin' ); }
Using wp_register_script
and wp_enqueue_script
, we have a plugin-specific JS file called quiz.js for handling validations. Validation will be done using the jQuery library and hence we have set the built-in jQuery library as a dependency for our plugin-specific JavaScript.
Having included the scripts, let's implement the actual validations in the quiz.js file as shown in the following code.
jQuery(document).ready(function($) { $("#post-body-content").prepend('<div id="quiz_error" class="error" style="display:none" ></div>'); $('#post').submit(function() { if ( $("#post_type").val() =='wptuts_quiz' ) { return wpq_validate_quizes(); } }); });
First, we assign an empty div
element to the post creation screen to display any errors. Then we can call a custom JS function on the post publish action by checking the correct post type using the #post_type
hidden field value.
The following code contains the implementation of the wpq_validate_quizes
function.
var wpq_validate_quizes = function() { var err = 0; $("#quiz_error").html(""); $("#quiz_error").hide(); if ( $("#title").val() == '' ) { $("#quiz_error").append("<p>Please enter Question Title.</p>"); err++; } var correct_answer = $("#correct_answer").val(); if ( $("#quiz_answer"+correct_answer).val() == "" ) { $("#quiz_error").append("<p>Correct answer cannot be empty.</p>"); err++; } if ( err > 0 ) { $("#publish").removeClass("button-primary-disabled"); $(".spinner").hide(); $("#quiz_error").show(); return false; } else { return true; } };
Code Explanation
- First we have to hide the error container and set its current error message to empty.
- Then we check whether the title exists, as title is mandatory for questions.
- Next we get the selected correct answer and check whether the answer field related to the correct answer is empty.
- When validation errors are generated we display the errors in the specified error container and prevents the submission of the post.
The following image shows the post creation screen with custom validation messages.
Once the form is successfully validated without errors, we can move onto saving the question details to the database.
Saving Question Details
WordPress provides an action called save_post
, which will be executed just after the post creation. We can define a custom function on the save_post
action to save the custom field details into the database.
As usual update the constructor with the save_post
action code.
add_action( 'save_post', array( $this, 'wpq_save_quizes' ) );
Implementation of the wpq_save_quizes
function is given in the following code.
function wpq_save_quizes( $post_id ) { if ( ! wp_verify_nonce( $_POST['question_box_nonce'], basename( __FILE__ ) ) ) { return $post_id; } if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { return $post_id; } if ( 'wptuts_quiz' == $_POST['post_type'] && current_user_can( 'edit_post', $post_id ) ) { $question_answers = isset( $_POST['quiz_answer'] ) ? ( $_POST['quiz_answer'] ) : array(); $filtered_answers = array(); foreach ( $question_answers as $answer ) { array_push( $filtered_answers, sanitize_text_field( trim( $answer ) ) ); } $question_answers = json_encode( $filtered_answers ); $correct_answer = isset( $_POST['correct_answer'] ) ? sanitize_text_field( $_POST['correct_answer'] ) : ""; update_post_meta( $post_id, "_question_answers", $question_answers ); update_post_meta( $post_id, "_question_correct_answer", $correct_answer ); } else { return $post_id; } }
The post ID is passed automatically to this function. Initially we execute validations for nonce value and autosave. The most important thing before saving is the validation of post type.
If you omit the post type check, this code will be executed for all the post types in your WordPress installation including normal posts, which can result in inconsistent data.
Finally we get the values of our answers fields and correct answer field to be saved to the database using the update_post_meta
function. All the custom fields details will be saved to the post_meta
table.
Now we have completed the question creation process. Since we are using randomly generated quizzes, you might need lots of questions to see this plugin in action. So get ready by adding additional questions before we implement the quiz in the next part.
Quiz Settings Page
Even though it's not mandatory, it's ideal to have a settings page for our plugin so that the admin can customize according to their preferences.
So let's implement a simple settings page to contain the quiz duration and number of questions per quiz. We need to implement the admin_menu
action in the constructor.
add_action( 'admin_menu', array( $this, 'wpq_plugin_settings' ) );
function wpq_plugin_settings() { //create new top-level menu add_menu_page( 'WPTuts Quiz Settings', 'WPTuts Quiz Settings', 'administrator', 'quiz_settings', array( $this, 'wpq_display_settings' ) ); } function wpq_display_settings() { $html = '<div class="wrap"> <form method="post" name="options" action="options.php"> <h2>Select Your Settings</h2>' . wp_nonce_field( 'update-options' ) . ' <table width="100%" cellpadding="10" class="form-table"> <tr> <td align="left" scope="row"> <label>Number of Questions</label><input type="text" name="wpq_num_questions" value="' . get_option( 'wpq_num_questions' ) . '" /> </td> </tr> <tr> <td align="left" scope="row"> <label>Duration (Mins)</label><input type="text" name="wpq_duration" value="' . get_option( 'wpq_duration' ) . '" /> </td> </tr> </table> <p class="submit"> <input type="hidden" name="action" value="update" /> <input type="hidden" name="page_options" value="wpq_num_questions,wpq_duration" /> <input type="submit" name="Submit" value="Update" /> </p> </form> </div>'; echo $html; }
We can use the add_menu_page
function to add a settings page to the admin area. The wpq_display_settings
function is used to implement the display elements of the settings page.
We have used two text fields for duration and questions per quiz. Form submission and data saving can be handled manually using custom code, but WordPress provides us a simplified method for updating options.
In this method you have to set the form action to the options.php file. Then you have to create a hidden field called action to contain the value of 'update
'. Finally we need to have another hidden field called page_options
to contain the names of the two text fields to be updated.
Make sure to use these built-in options update techniques in scenarios where the requirements for saving the fields are not complex.
Once the submit button is clicked, form details will be updated automatically without any custom code.
What's Next
We have completed the backend of our quiz plugin. Now you can create questions and get ready for the next part where we will use these questions to dynamically generate quizzes.
Until then let me know the best possible way to implement a dynamic quiz on the frontend. Keep in mind that only one question will be displayed at a time. When the user requests a question, he can move to the next question.
Looking forward to your suggestions.
Comments