Skip to content

Instantly share code, notes, and snippets.

@igorbenic
Last active March 21, 2018 14:10
Show Gist options
  • Select an option

  • Save igorbenic/ff52afa0a05dc6d41d8922d6bdb3c0a3 to your computer and use it in GitHub Desktop.

Select an option

Save igorbenic/ff52afa0a05dc6d41d8922d6bdb3c0a3 to your computer and use it in GitHub Desktop.
Building a Quiz with React and WordPress REST API: CPT and REST API Routes | https://ibenic.com/quiz-react-wordpress-rest-api-routes
<?php
// ... Rest of the code
class WPQR {
// ... Rest of the code
/**
* Load everything
* @return void
*/
public function load() {
add_action( 'init', array( $this, 'load_cpts' ) );
}
/**
* Load all CPTs
* @return void
*/
public function load_cpts() {
$labels = array(
'name' => _x( 'Questions', 'Post Type General Name', 'wpqr' ),
'singular_name' => _x( 'Question', 'Post Type Singular Name', 'wpqr' ),
'menu_name' => __( 'Questions', 'wpqr' ),
'name_admin_bar' => __( 'Question', 'wpqr' ),
'archives' => __( 'Item Archives', 'wpqr' ),
'attributes' => __( 'Item Attributes', 'wpqr' ),
'parent_item_colon' => __( 'Parent Item:', 'wpqr' ),
'all_items' => __( 'All Items', 'wpqr' ),
'add_new_item' => __( 'Add New Item', 'wpqr' ),
'add_new' => __( 'Add New', 'wpqr' ),
'new_item' => __( 'New Item', 'wpqr' ),
'edit_item' => __( 'Edit Item', 'wpqr' ),
'update_item' => __( 'Update Item', 'wpqr' ),
'view_item' => __( 'View Item', 'wpqr' ),
'view_items' => __( 'View Items', 'wpqr' ),
'search_items' => __( 'Search Item', 'wpqr' ),
'not_found' => __( 'Not found', 'wpqr' ),
'not_found_in_trash' => __( 'Not found in Trash', 'wpqr' ),
'featured_image' => __( 'Featured Image', 'wpqr' ),
'set_featured_image' => __( 'Set featured image', 'wpqr' ),
'remove_featured_image' => __( 'Remove featured image', 'wpqr' ),
'use_featured_image' => __( 'Use as featured image', 'wpqr' ),
'insert_into_item' => __( 'Insert into item', 'wpqr' ),
'uploaded_to_this_item' => __( 'Uploaded to this item', 'wpqr' ),
'items_list' => __( 'Items list', 'wpqr' ),
'items_list_navigation' => __( 'Items list navigation', 'wpqr' ),
'filter_items_list' => __( 'Filter items list', 'wpqr' ),
);
$args = array(
'label' => __( 'Question', 'wpqr' ),
'description' => __( 'Questions for Quiz', 'wpqr' ),
'labels' => $labels,
'supports' => array( 'title', 'editor' ),
'hierarchical' => false,
'public' => true,
'show_ui' => true,
'show_in_menu' => true,
'menu_icon' => 'dashicons-testimonial',
'menu_position' => 5,
'show_in_admin_bar' => true,
'show_in_nav_menus' => true,
'show_in_rest' => false,// Don't support Gutenberg
'can_export' => true,
'has_archive' => false,
'exclude_from_search' => true,
'publicly_queryable' => true,
'capability_type' => 'page',
);
register_post_type( 'question', $args );
}
}
// ... Rest of the code
<?php
if( ! defined( 'ABSPATH' ) ) {
return;
}
class WPQR_Metaboxes {
/**
* Renders the metabox for answers.
* We will display saved answers and have the form to add new or delete old.
*
* @param WP_Post $post
* @return void
*/
public static function answers( $post ) {
$post_id = $post->ID;
// Get our answers
$answers = get_post_meta( $post_id, '_wpqr_answers', true );
?>
<table class="wpqr-answers form-table">
<thead>
<tr>
<td><strong><?php esc_html_e( 'Answer', 'wpqr' ); ?></strong></td>
<td><strong><?php esc_html_e( 'Points', 'wpqr' ); ?></strong></td>
</tr>
</thead>
<tbody>
<?php
for ( $i = 0; $i < 3; $i++ ) {
?>
<tr>
<td><input type="text" name="wpqr_answers[]" value="<?php echo isset( $answers[ $i ] ) && $answers[ $i ]['text'] ? $answers[ $i ]['text'] : ''; ?>" class="widefat"/></td>
<td><input type="number" name="wpqr_points[]" value="<?php echo isset( $answers[ $i ] ) && $answers[ $i ]['points'] ? $answers[ $i ]['points'] : 0; ?>"/></td>
</tr>
<?php
}
?>
</tbody>
</table>
<?php
}
}
[
wpqr_answers: [
0: 'Text of the first answer',
1: 'Text of the second answer',
2: 'Text of the third answer',
],
wpqr_points: [
0: 0,
1: 15,
2: 10
]
]
<?php
if( ! defined( 'ABSPATH' ) ) {
return;
}
class WPQR_Metaboxes {
// ...
/**
* Save Method.
* @param integer $post_id
* @param WP_Post $post
* @return void
*/
public static function save( $post_id, $post ) {
if( 'question' !== get_post_type( $post ) ) {
return;
}
if ( wp_is_post_autosave( $post ) ) {
return;
}
if ( defined( 'WP_AJAX' ) && WP_AJAX ) {
return;
}
if ( ! current_user_can( 'edit_posts' ) ) {
return;
}
if ( isset( $_POST['wpqr_answers'] ) && isset( $_POST['wpqr_points'] ) ) {
$answers = array();
// For each answer, get it's order (index) and the text
foreach ( $_POST['wpqr_answers'] as $order => $answer) {
$array = array( 'text' => $answer, 'points' => 0 );
if ( isset( $_POST['wpqr_points'][ $order ] ) ) {
// If we have points inside with the same order (index), set it.
$array['points'] = floatval( $_POST['wpqr_points'][ $order ] );
}
$answers[ $order ] = $array;
}
update_post_meta( $post_id, '_wpqr_answers', $answers );
}
}
}
<?php
// The saved array
array(
0: array( 'text' => 'Text of the first answer', 'points' => 0 ),
1: array( 'text' => 'Text of the second answer', 'points' => 15 ),
2: array( 'text' => 'Text of the third answer', 'points' => 10 ),
)
<?php
/**
* Plugin Name: WordPress Quiz with React
* Description: Quiz Plugin made by tutorial on ibenic.com
* Plugin URI: https://ibenic.com
*/
if( ! defined( 'ABSPATH' ) ) {
return;
}
class WPQR {
public function includes() {
include 'inc/class-wpqr-metaboxes.php';
include 'inc/class-wpqr-rest-api.php';
}
/**
* Load everything
* @return void
*/
public function load() {}
/**
* Load all CPTs
* @return void
*/
public function load_cpts() {}
}
add_action( 'plugins_loaded', 'wpqr_load' );
/**
* Loading our plugin
* @return void
*/
function wpqr_load() {
$plugin = new WPQR();
$plugin->includes();
$plugin->load();
}
<?php
// ... rest of the code
class WPQR {
// ... rest of the code
/**
* Load everything
* @return void
*/
public function load() {
add_action( 'init', array( $this, 'load_cpts' ) );
if ( is_admin() ) {
add_action( 'add_meta_boxes', array( $this, 'register_metaboxes' ) );
}
}
/**
* Register all metaboxes
* @return void
*/
public function register_metaboxes() {
add_meta_box( 'question-answers', __( 'Answers', 'wpqr' ), array( 'WPQR_Metaboxes', 'answers' ), 'question' );
}
// ... rest of the code
}
// ... rest of the code
<?php
// ...
class WPQR {
// ...
/**
* Load everything
* @return void
*/
public function load() {
add_action( 'init', array( $this, 'load_cpts' ) );
if ( is_admin() ) {
add_action( 'add_meta_boxes', array( $this, 'register_metaboxes' ) );
add_action( 'save_post', array( $this, 'save_metaboxes' ), 20, 2 );
}
}
/**
* Save all metaboxes if needed.
* @param integer $post_id
* @param WP_Post $post
* @return void
*/
public function save_metaboxes( $post_id, $post ) {
WPQR_Metaboxes::save( $post_id, $post );
}
// ...
}
// ...
<?php
// ...
class WPQR {
// ...
/**
* Load everything
* @return void
*/
public function load() {
add_action( 'init', array( $this, 'load_cpts' ) );
add_action( 'rest_api_init', array( 'WPQR_REST_API', 'register_routes' ) );
// ...
}
// ...
}
// ...
<?php
if( ! defined( 'ABSPATH' ) ) {
return;
}
/**
* Class used to define how rest api works.
*/
class WPQR_REST_API {
/**
* Registering routes
* @return void
*/
public static function register_routes() {
register_rest_route( 'wpqr/v1', '/questions', array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( __CLASS__, 'get_questions' ),
) );
}
/**
* Get the Questions with answers for the REST API Route
* @return mixed
*/
public static function get_questions() {
$questions = get_transient( 'wpqr_rest_questions' );
if ( false === $questions ) {
$questions = array();
$args = array(
//Type & Status Parameters
'post_type' => 'question',
'post_status' => 'publish',
//Order & Orderby Parameters
'order' => 'ASC',
'orderby' => 'date',
//Pagination Parameters
'posts_per_page' => 500,
//Parameters relating to caching
'no_found_rows' => true,
'cache_results' => true,
'update_post_term_cache' => false,
'update_post_meta_cache' => false,
);
// Get all the questions.
$query = new WP_Query( $args );
if ( $query->have_posts() ) {
while( $query->have_posts() ) {
$query->the_post();
$q_array = array();
$q_array['id'] = get_the_id();
$q_array['title'] = get_the_title();
$q_array['content'] = get_the_content();
$q_array['answers'] = get_post_meta( get_the_id(), '_wpqr_answers', true );
if ( is_array( $q_array['answers'] ) ) {
// Filter and return only the answer text.
// By including points, the user could know which gives more points using console
$q_array['answers'] = array_map(
function( $item ) {
return $item['text'];
},
$q_array['answers']);
}
if ( $q_array['answers'] ) {
$questions[] = $q_array;
}
}
wp_reset_postdata();
}
set_transient( 'wpqr_rest_questions', $questions, 24 * HOUR_IN_SECONDS );
}
return $questions;
}
}
<?php
if( ! defined( 'ABSPATH' ) ) {
return;
}
/**
* Class used to define how rest api works.
*/
class WPQR_REST_API {
/**
* Registering routes
* @return void
*/
public static function register_routes() {
// ...
register_rest_route( 'wpqr/v1', '/result', array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => array( __CLASS__, 'get_result' ),
) );
}
// ...
/**
* Get the result
* @param WP_REST_Request $request
* @return array
*/
public static function get_result( $request ) {
$parameters = $request->get_body_params();
if ( ! isset( $parameters['answers'] ) ) {
return new WP_Error( 'no-answers', __( 'There are no answers. Please answer the questions.', 'wpqr' ) );
}
// Default variables to hold the score and the possible top score
$score = 0;
$top = 0;
$percentage = 0;
foreach ( $parameters['answers'] as $question_id => $answer ) {
$answers = get_post_meta( $question_id, '_wpqr_answers', true );
if( $answers ) {
// If there are answers, let's define the default top and score for the current question
$question_top = 0;
$question_score = 0;
foreach ( $answers as $order => $array ) {
// If the current answer's points are bigger than the current question's top
// replace it
if( $array['points'] > $question_top ) {
$question_top = $array['points'];
}
// If the current answer is the one selected from the user register it as the question score
if( absint( $order ) === absint( $answer ) ) {
$question_score = $array['points'];
}
}
// Add both the question defaults to the 'global' defaults.
$top += $question_top;
$score += $question_score;
}
}
if( $top > 0 && $score > 0 ) {
$percentage = floatval( $score / $top ) * 100;
}
return array( 'top' => $top, 'score' => $score, 'percentage' => $percentage );
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment