Статьи

Интеграция тестов с несколькими вариантами ответов в WordPress — Создание бэкенда

Вопросы с множественным выбором — это то, с чем большинство из нас сталкивалось хотя бы раз в жизни. Мы любим их, потому что можем дать правильные ответы, логически думая о предоставляемых возможностях, даже если мы не знаем точного ответа. Кроме того, ответ занимает меньше времени, что делает его таким популярным.

Создание викторины с множественным выбором в WordPress может быть очень интересной и прибыльной задачей. Вы можете использовать его в своем личном блоге, чтобы привлечь больше посетителей, или вы можете создать премиальный раздел с расширенными тестами, или вы можете создавать тесты, посвященные популярным сертификационным экзаменам. Есть множество возможностей сделать его прибыльным.

Этот плагин не поможет вам в создании тестов для построения бизнеса, но мы должны начать с чего-то, чтобы попасть туда, куда мы хотим идти. Так что это было бы хорошим началом для создания тестов и получения прибыли от этого.

Итак, начнем.


Сначала нам нужно собрать требования плагина, прежде чем приступить к разработке или реализации. По сути, мы должны иметь возможность создавать тесты с несколькими вариантами ответов и позволять пользователям проходить тесты и получать результаты.

Итак, давайте посмотрим на подробные требования и компоненты нашего плагина:

  • Плагин должен иметь бэкэнд, в который мы можем вставлять вопросы и ответы динамически. Также идеально иметь категории викторины, чтобы группировать тесты в определенные разделы.
  • Администратор сайта должен иметь возможность настраивать тесты через страницу настроек.
  • У пользователей должен быть веб-интерфейс, где они могут пройти тест.
  • После того, как тест завершен, пользователи должны иметь возможность получать оценки и результаты.

Этот урок будет построен в виде серии из двух частей, в которой мы разработаем бэкэнд плагина в первой части, а затем внешний интерфейс плагина во второй части.


В этой части мы собираемся сосредоточиться на разработке серверной части плагина, где мы разрабатываем необходимые данные для тестов.

Обычно есть список тестов, каждый из которых содержит определенный список вопросов. С этим плагином мы не собираемся создавать викторины. Мы будем создавать индивидуальные вопросы и назначать их динамически для тестов по запросу.

Теперь мы можем потратить некоторое время на определение компонентов, необходимых для реализации бэкэнда, как указано в следующем разделе.

  • Вопросы должны быть созданы в бэкэнде с ответами. Пользовательский тип сообщения будет лучшим решением для реализации вопросов. Поэтому мы собираемся использовать пользовательский тип записи под названием wptuts_quiz .
  • Каждый вопрос должен иметь несколько ответов и один правильный ответ. Поля для ответов будут созданы внутри мета-поля на пользовательском экране создания постов.
  • Вопросы будут quiz_categories на различные wptuts_quiz поэтому нам нужна специальная таксономия quiz_categories для wptuts_quiz поста wptuts_quiz .
  • Затем нам нужно проверить процесс создания вопроса. Мы будем использовать клиентскую проверку jQuery, когда это необходимо при создании вопроса.
  • Наконец, нам нужна страница настроек плагина для хранения количества вопросов на тест и продолжительности теста.

Определив необходимые компоненты WordPress, мы можем перейти непосредственно к реализации бэкенда плагина викторины.


Процесс создания вопроса состоит из четырех основных разделов: определение пользовательского типа сообщения, определение пользовательской таксономии, назначение пользовательских полей и проверки. Каждый из этих разделов будет обсуждаться с подробным кодом в следующих разделах.

Нам нужна самая основная форма настраиваемого типа сообщений для вопросов без каких-либо дополнительных настроек. Единственное, что нам нужно учитывать, — это выбор правильного поля для вопроса.

Экран создания записей по умолчанию содержит два поля для заголовка и содержимого. Вы можете выбрать любое из этих полей для вопроса. Я собираюсь выбрать объединение полей заголовка и контента с учетом расширенных возможностей.

Мы будем создавать объектно-ориентированный плагин вместо функционального, поэтому все необходимые действия, шорткоды и инициализации будут выполняться внутри конструктора. Ниже приведен код для реализации типа записи wptuts_quiz .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
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 );
    }
}

Мы включили поля заголовка и редактора в пользовательский тип сообщения, чтобы использовать его для вопроса. Поскольку функции расположены внутри класса, мы должны использовать $this в наших действиях, фильтрах и шорткодах WordPress для вызова функций.

Кроме того, все параметры, упомянутые в коде, инициализируются значениями по умолчанию.

Чтобы сгруппировать вопросы в определенные разделы, нам нужно нечто похожее на стандартные категории WordPress. Следовательно, мы будем использовать пользовательскую таксономию под названием quiz_categories . Нам нужно вызвать функцию генерации пользовательской таксономии для действия init как мы это делали ранее. Таким образом, конструктор нашего класса плагина должен быть обновлен следующим кодом.

1
add_action( ‘init’, array( $this,’wpq_create_taxonomies’ ), 0 );

Затем мы можем реализовать функцию wptuts_quiz типа wptuts_quiz как показано в следующем коде.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
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
        )
    );
 
}

Я использовал параметры по умолчанию для создания этой пользовательской таксономии. После того, как плагин активирован, ваш тип поста и таксономия будут отображаться, как показано на следующем экране.

Далее нам нужно создать несколько ответов на каждый вопрос. В этом плагине максимальное количество ответов на один вопрос будет ограничено пятью.

Вы можете динамически назначать 1-5 ответов на любой вопрос. Также нам необходимо указать правильный ответ из предоставленного списка ответов. Поскольку эти данные связаны с нашими вопросами, мы можем использовать мета-поле с настраиваемыми полями для создания необходимых полей.

Как обычно, нам нужно обновить конструктор следующим кодом:

1
add_action( ‘add_meta_boxes’, array( $this,’wpq_quiz_meta_boxes’ ) );

Рассмотрим следующий код для реализации мета-блоков с полями ответов.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
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 == » ) ?
 
    $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 ‘ .
        }
        else {
            $html .= ‘<option value=»‘ . $i . ‘»>Answer ‘ .
        }
 
    }
 
    $html .= ‘</select></td></tr>’;
 
    $index = 1;
 
    foreach ( $question_answers as $question_answer ) {
 
        $html .= ‘<tr><th style=»»><label for=»Price»>Answer ‘ .
        $html .= ‘<td><textarea class=»widefat» name=»quiz_answer[]» id=»quiz_answer’ . $index . ‘» >’ .
 
        $index++;
 
    }
 
    $html .= ‘</tr>’;
 
    $html .= ‘</table>’;
 
    echo $html;
}
  • Ответы на каждый вопрос будут храниться в виде строки в кодировке JSON в таблице post_meta с ключом _question_answers . Таким образом, мы получаем доступ к этому полю, используя функцию get_post_meta чтобы получить текущие значения.
  • Тогда мы получим правильный ответ на вопрос, используя аналогичный метод. Правильный ответ будет сохранен в виде строки в таблице post_meta с ключом _question_correct_answer .
  • Наконец, мы создаем HTML-форму, которая содержит правильный ответ в виде выпадающего списка и возможные ответы в виде пяти полей текстовой области.
  • Все существующие значения, полученные с get_post_meta функции get_post_meta будут присвоены соответствующим полям.

После создания мета-блока вы должны увидеть нечто похожее на следующий экран.

quiz1

Теперь у нас есть все данные, необходимые для нашего плагина генерации тестов. Следующим шагом является сохранение данных вопроса в базу данных.

Но нам нужно несколько проверок до этого. Итак, давайте перейдем к валидации.


На данном этапе в процессе создания вопроса у нас нет сложных правил проверки. Поэтому мы собираемся использовать проверки JQuery на стороне клиента перед отправкой.

Здесь нам нужно, admin_enqueue_scripts действие admin_enqueue_scripts было включено в конструктор нашего плагина.

Так что обновите конструктор следующим кодом, прежде чем мы начнем.

1
add_action( ‘admin_enqueue_scripts’, array( $this, ‘wpq_admin_scripts’ ) );

Теперь посмотрите на следующий код для включения необходимых файлов сценариев для проверки.

1
2
3
4
5
6
7
function wpq_admin_scripts() {
 
    wp_register_script( ‘quiz-admin’, plugins_url( ‘js/quiz.js’, __FILE__ ), array( ‘jquery’ ) );
 
    wp_enqueue_script( ‘quiz-admin’ );
 
}

Используя wp_register_script и wp_enqueue_script , у нас есть специфичный для плагина JS-файл quiz.js для обработки проверок . Проверка будет выполняться с использованием библиотеки jQuery, и поэтому мы установили встроенную библиотеку jQuery в качестве зависимости для нашего специфичного для плагина JavaScript.

Включив сценарии, давайте реализуем фактические проверки в файле quiz.js, как показано в следующем коде.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
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();
 
        }
 
    });
 
});

Во-первых, мы назначаем пустой элемент div экрану создания записей, чтобы отобразить любые ошибки. Затем мы можем вызвать пользовательскую функцию JS для действия публикации после публикации, проверив правильный тип сообщения, используя #post_type скрытого поля #post_type .

Следующий код содержит реализацию функции wpq_validate_quizes .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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;
 
    }
};
  • Сначала мы должны скрыть контейнер ошибок и установить его текущее сообщение об ошибке пустым.
  • Затем мы проверяем, существует ли заголовок, так как заголовок обязателен для вопросов.
  • Затем мы получаем выбранный правильный ответ и проверяем, является ли поле ответа, связанное с правильным ответом, пустым.
  • Когда генерируются ошибки проверки, мы отображаем ошибки в указанном контейнере ошибок и предотвращаем отправку сообщения.

На следующем рисунке показан экран создания поста с пользовательскими сообщениями проверки.

wpquiz2

Как только форма успешно подтверждена без ошибок, мы можем перейти к сохранению деталей вопроса в базе данных.


WordPress предоставляет действие save_post , которое будет выполнено сразу после создания записи. Мы можем определить пользовательскую функцию в действии save_post для сохранения сведений о настраиваемом поле в базе данных.

Как обычно, обновите конструктор save_post действия save_post .

1
add_action( ‘save_post’, array( $this, ‘wpq_save_quizes’ ) );

Реализация функции wpq_save_quizes приведена в следующем коде.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
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’] ) ?
 
        $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’] ) ?
 
        update_post_meta( $post_id, «_question_answers», $question_answers );
 
        update_post_meta( $post_id, «_question_correct_answer», $correct_answer );
 
    }
    else {
 
        return $post_id;
 
    }
}

Идентификатор сообщения автоматически передается в эту функцию. Первоначально мы выполняем проверки для одноразового значения и автосохранения. Самое важное перед сохранением — это проверка типа записи.

Если вы пропустите проверку типов записей, этот код будет выполняться для всех типов записей в вашей установке WordPress, включая обычные записи, что может привести к несогласованности данных.

Наконец, мы получаем значения полей наших ответов и поля правильных ответов для сохранения в базе данных с update_post_meta функции update_post_meta . Все пользовательские поля будут сохранены в таблицу post_meta .

Теперь мы завершили процесс создания вопроса. Поскольку мы используем произвольно сгенерированные тесты, вам может понадобиться много вопросов, чтобы увидеть этот плагин в действии. Так что будьте готовы, добавив дополнительные вопросы, прежде чем мы реализуем тест в следующей части.


Несмотря на то, что это не является обязательным, идеально иметь страницу настроек для нашего плагина, чтобы администратор мог настроить в соответствии со своими предпочтениями.

Итак, давайте реализуем простую страницу настроек, которая будет содержать продолжительность теста и количество вопросов на тест. Нам нужно реализовать действие admin_menu в конструкторе.

1
add_action( ‘admin_menu’, array( $this, ‘wpq_plugin_settings’ ) );
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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>’ .
 
            <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;
}

Мы можем использовать функцию add_menu_page чтобы добавить страницу настроек в add_menu_page . Функция wpq_display_settings используется для реализации элементов отображения страницы настроек.

Мы использовали два текстовых поля для продолжительности и вопросов для теста. Отправка формы и сохранение данных могут быть обработаны вручную с помощью пользовательского кода, но WordPress предоставляет нам упрощенный метод обновления параметров.

В этом методе вы должны установить действие формы для файла options.php . Затем вам нужно создать скрытое поле с именем action, которое будет содержать значение update . Наконец, нам нужно другое скрытое поле с именем page_options будет содержать имена двух текстовых полей, которые нужно обновить.

Обязательно используйте эти встроенные методы обновления параметров в тех случаях, когда требования для сохранения полей не являются сложными.

После нажатия кнопки «Отправить» данные формы будут автоматически обновляться без какого-либо специального кода.


Мы завершили бэкэнд нашего плагина викторины. Теперь вы можете создавать вопросы и готовиться к следующей части, где мы будем использовать эти вопросы для динамической генерации тестов.

А пока дайте мне знать, как лучше всего реализовать динамический тест на веб-интерфейсе. Имейте в виду, что за один раз будет отображаться только один вопрос. Когда пользователь запрашивает вопрос, он может перейти к следующему вопросу.

Ждем ваших предложений.