Last active
March 21, 2018 14:10
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?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 | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| [ | |
| 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 | |
| ] | |
| ] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?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 ); | |
| } | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?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 ), | |
| ) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?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(); | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?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 ); | |
| } | |
| // ... | |
| } | |
| // ... |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?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' ) ); | |
| // ... | |
| } | |
| // ... | |
| } | |
| // ... |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?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; | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?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