Created
March 30, 2016 20:04
-
-
Save danielbachhuber/2b3ed549beb0984e2070979370a8650b to your computer and use it in GitHub Desktop.
A real-world controller for a WP REST API endpoint
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 | |
namespace LitART\LMS\REST; | |
use LitART\LMS\Query; | |
use WP_Error; | |
use WP_REST_Server; | |
class Records_Controller extends Posts_Controller { | |
protected static $schema_title = 'record'; | |
public function __construct( $post_type ) { | |
parent::__construct( $post_type ); | |
add_filter( 'rest_record_query', array( $this, 'filter_rest_record_query' ), 10, 2 ); | |
} | |
public function register_routes() { | |
register_rest_field( self::$schema_title, 'parent', array( | |
'schema' => array( | |
'description' => 'Associated quiz or activity of the record.', | |
'type' => 'array', | |
'required' => true, | |
'context' => array( 'embed', 'view', 'edit' ), | |
'arg_options' => array( | |
'validate_callback' => function( $value, $request, $field ) { | |
$parent = get_post( (int) $value ); | |
if ( $parent && in_array( $parent->post_type, array( 'activity', 'quiz' ) ) ) { | |
return true; | |
} | |
return false; | |
} | |
), | |
), | |
) ); | |
$sanitize_record_data = function( $value, $fields ) { | |
if ( ! is_array( $value ) ) { | |
return array(); | |
} | |
$cleaned_data = array(); | |
foreach( $value as $id => $dirty ) { | |
$field = false; | |
foreach( $fields as $f ) { | |
if ( $f['id'] === $id ) { | |
$field = $f; | |
break; | |
} | |
} | |
if ( empty( $field ) ) { | |
continue; | |
} | |
$clean = ''; | |
switch ( $field['type'] ) { | |
case 'true_false': | |
$clean = (bool) $dirty; | |
break; | |
case 'multiple_choice': | |
if ( in_array( $dirty, $field['multiple_choice_options'] ) ) { | |
$clean = $dirty; | |
} | |
break; | |
case 'short_answer': | |
$clean = sanitize_text_field( $dirty ); | |
break; | |
case 'essay': | |
$clean = wp_filter_nohtml_kses( $dirty ); | |
break; | |
} | |
$cleaned_data[ $id ] = $clean; | |
} | |
return $cleaned_data; | |
}; | |
register_rest_field( self::$schema_title, 'data', array( | |
'get_callback' => function( $response, $field ) { | |
if ( $data = get_post_meta( $response['id'], 'data', true ) ) { | |
return $data; | |
} | |
return array(); | |
}, | |
'update_callback' => function( $value, $post, $field ) use ( $sanitize_record_data ) { | |
$fields = get_post_meta( $post->post_parent, 'engagement_modules', true ); | |
update_post_meta( $post->ID, 'data', $sanitize_record_data( $value, $fields ) ); | |
}, | |
'schema' => array( | |
'description' => 'Data stored to the record', | |
'type' => 'array', | |
'context' => array( 'embed', 'view', 'edit' ), | |
), | |
) ); | |
parent::register_routes(); | |
} | |
public function get_items_permissions_check( $request ) { | |
if ( ! is_user_logged_in() ) { | |
return new WP_Error( 'rest_cannot_read', "Sorry, you aren't allowed to read records.", array( 'status' => 401 ) ); | |
} | |
if ( ! $request['author'] && ! $request['organization'] && ! current_user_can( 'edit_others_records' ) ) { | |
return new WP_Error( 'rest_cannot_read', "Sorry, you aren't allowed to read others' records.", array( 'status' => 403 ) ); | |
} | |
if ( $request['author'] && (int) $request['author'] !== get_current_user_id() && ! current_user_can( 'edit_user', $request['author'] ) ) { | |
return new WP_Error( 'rest_cannot_read', "Sorry, you aren't allowed to read others' records.", array( 'status' => 403 ) ); | |
} | |
if ( $request['organization'] && ! Query::is_facilitator_member_of_organization( get_current_user_id(), $request['organization'] ) ) { | |
return new WP_Error( 'rest_cannot_read', "Sorry, you aren't allowed to read others' records.", array( 'status' => 403 ) ); | |
} | |
return parent::get_items_permissions_check( $request ); | |
} | |
public function filter_rest_record_query( $prepared_args, $request ) { | |
if ( isset( $request['organization'] ) ) { | |
$student_ids = Query::get_organization_student_ids( (int) $request['organization'] ); | |
if ( ! empty( $student_ids ) ) { | |
$prepared_args['author__in'] = $student_ids; | |
} else { | |
$prepared_args['author__in'] = array( LITART_IMPOSSIBLY_HIGH_NUMBER ); | |
} | |
} | |
return $prepared_args; | |
} | |
public function create_item_permissions_check( $request ) { | |
$ret = parent::create_item_permissions_check( $request ); | |
if ( ! $ret || is_wp_error( $ret ) ) { | |
return $ret; | |
} | |
$existing = get_posts( array( | |
'post_parent' => (int) $request['parent'], | |
'post_type' => 'record', | |
'post_status' => 'any', | |
'author' => $request['author'] ? (int) $request['author'] : get_current_user_id(), | |
'fields' => 'ids', | |
) ); | |
if ( $existing ) { | |
return new WP_Error( 'rest_already_exists', 'Sorry, a record already exists for this activity or quiz.', array( 'status' => 400 ) ); | |
} | |
return true; | |
} | |
public function update_item_permissions_check( $request ) { | |
$ret = parent::update_item_permissions_check( $request ); | |
if ( ! $ret || is_wp_error( $ret ) ) { | |
return $ret; | |
} | |
return true; | |
} | |
public function get_item_schema() { | |
$schema = parent::get_item_schema(); | |
$schema['properties']['status']['arg_options']['default'] = 'draft'; | |
$schema['properties']['status']['context'] = array( 'embed', 'view', 'edit' ); | |
// Unset attributes we don't want to use. | |
$unused_attributes = array( | |
'date', | |
'date_gmt', | |
'link', | |
'password', | |
'modified', | |
'modified_gmt', | |
'slug', | |
); | |
foreach( $unused_attributes as $attribute ) { | |
if ( isset( $schema['properties'][ $attribute ] ) ) { | |
unset( $schema['properties'][ $attribute ] ); | |
} | |
} | |
return $this->add_additional_fields_schema( $schema ); | |
} | |
public function get_collection_params() { | |
$params = parent::get_collection_params(); | |
$params['order']['default'] = 'asc'; | |
$params['orderby']['default'] = 'id'; | |
$params['status']['default'] = 'any'; | |
$params['author']['type'] = 'integer'; | |
unset( $params['author']['validate_callback'] ); | |
$params['author']['sanitize_callback'] = 'absint'; | |
$params['organization'] = array( | |
'type' => 'integer', | |
'description' => 'Limit result set to records of a specific organization.', | |
'validate_callback' => 'rest_validate_request_arg', | |
); | |
$unused_params = array( | |
'after', | |
'before', | |
'author_exclude', | |
'filter', | |
); | |
foreach( $unused_params as $param ) { | |
if ( isset( $params[ $param ] ) ) { | |
unset( $params[ $param ] ); | |
} | |
} | |
return $params; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment