'GET', 'callback' => array( __CLASS__, 'rest_list' ), 'permission_callback' => function () { return current_user_can( 'edit_posts' ); }, ), array( 'methods' => 'POST', 'callback' => array( __CLASS__, 'rest_create' ), 'permission_callback' => function () { return current_user_can( 'manage_options' ); }, 'args' => array( 'name' => array( 'type' => 'string', 'required' => true, ), 'type' => array( 'type' => 'string', 'enum' => $typen, 'required' => true, ), 'scale' => array( 'type' => 'string', 'enum' => array_keys( ThreeRB_Score::scales() ), 'default' => 'p10', ), 'step' => array( 'type' => 'number', 'enum' => array( 0.1, 0.5, 1 ), 'default' => 0.1, ), 'criteria' => array( 'type' => 'array', 'required' => true, 'minItems' => 1, 'maxItems' => 12, 'items' => array( 'type' => 'object', 'additionalProperties' => false, 'properties' => array( 'label' => array( 'type' => 'string', 'maxLength' => 60, ), 'weight' => array( 'type' => 'integer', 'minimum' => 0, 'maximum' => 100, ), ), ), ), ), ), ) ); register_rest_route( 'threerb/v1', '/templates/(?P[a-z0-9_-]{1,40})', array( 'methods' => 'DELETE', 'callback' => array( __CLASS__, 'rest_delete' ), 'permission_callback' => function () { return current_user_can( 'manage_options' ); }, ) ); } /** * REST: alle Vorlagen. * * @return WP_REST_Response */ public static function rest_list() { return rest_ensure_response( array_values( self::all() ) ); } /** * REST: eigene Vorlage anlegen. * * @param WP_REST_Request $request Anfrage. * @return WP_REST_Response|WP_Error */ public static function rest_create( $request ) { $vorlage = self::save( array( 'name' => $request['name'], 'type' => $request['type'], 'scale' => $request['scale'], 'step' => $request['step'], 'criteria' => $request['criteria'], ) ); if ( is_wp_error( $vorlage ) ) { return $vorlage; } $antwort = rest_ensure_response( $vorlage ); $antwort->set_status( 201 ); return $antwort; } /** * REST: eigene Vorlage löschen. * * @param WP_REST_Request $request Anfrage. * @return WP_REST_Response|WP_Error */ public static function rest_delete( $request ) { $eigene = self::own(); $key = (string) $request['key']; if ( ! isset( $eigene[ $key ] ) ) { return new WP_Error( 'threerb_template_missing', __( 'This template does not exist or cannot be deleted.', '3task-review-box' ), array( 'status' => 404 ) ); } unset( $eigene[ $key ] ); update_option( self::OPTION, $eigene, false ); return rest_ensure_response( array( 'deleted' => $key ) ); } /** * Mitgelieferte und eigene Vorlagen. * * @return array */ public static function all() { $alle = array(); foreach ( self::builtin() as $key => $v ) { $alle[ $key ] = self::form( $key, $v, true ); } foreach ( self::own() as $key => $v ) { $alle[ $key ] = self::form( $key, $v, false ); } return $alle; } /** * Eigene Vorlagen, geprüft gelesen. * * @return array */ public static function own() { $roh = get_option( self::OPTION, array() ); $out = array(); if ( ! is_array( $roh ) ) { return $out; } foreach ( $roh as $key => $v ) { if ( is_string( $key ) && preg_match( '/^own[a-z0-9]{10}$/', $key ) && is_array( $v ) ) { $sauber = self::clean( $v ); if ( ! is_wp_error( $sauber ) ) { $out[ $key ] = $sauber; } } } return $out; } /** * Eigene Vorlage speichern. * * @param array $roh Eingabe. * @return array|WP_Error Gespeicherte Vorlage. */ public static function save( array $roh ) { $eigene = self::own(); if ( count( $eigene ) >= self::MAX ) { return new WP_Error( 'threerb_template_limit', __( 'You can keep up to 50 own templates. Delete one first.', '3task-review-box' ), array( 'status' => 400 ) ); } $sauber = self::clean( $roh ); if ( is_wp_error( $sauber ) ) { return $sauber; } do { $key = 'own' . strtolower( wp_generate_password( 10, false, false ) ); } while ( isset( $eigene[ $key ] ) ); $eigene[ $key ] = $sauber; update_option( self::OPTION, $eigene, false ); return self::form( $key, $sauber, false ); } /** * Prüft eine Vorlage: Name 1 bis 60 Zeichen, Typ aus der Liste, 1 bis 12 Kriterien, Gewichte 0 bis 100. * * @param array $roh Eingabe. * @return array|WP_Error */ public static function clean( array $roh ) { $fehler = new WP_Error( 'threerb_template_invalid', __( 'The template is not valid: name 1 to 60 characters, 1 to 12 criteria with weights from 0 to 100.', '3task-review-box' ), array( 'status' => 400 ) ); $name = isset( $roh['name'] ) && is_string( $roh['name'] ) ? trim( sanitize_text_field( $roh['name'] ) ) : ''; $typ = isset( $roh['type'] ) && is_string( $roh['type'] ) ? $roh['type'] : ''; $scale = isset( $roh['scale'] ) && null !== ThreeRB_Score::max( $roh['scale'] ) ? $roh['scale'] : 'p10'; $step = isset( $roh['step'] ) && is_numeric( $roh['step'] ) ? (float) $roh['step'] : 0.1; if ( '' === $name || mb_strlen( $name ) > 60 || ( 'none' !== $typ && ! array_key_exists( $typ, ThreeRB_Schema::types() ) ) ) { return $fehler; } if ( ! in_array( $step, ThreeRB_Score::scales()[ $scale ]['steps'], true ) ) { $step = ThreeRB_Score::scales()[ $scale ]['steps'][0]; } $kriterien = array(); foreach ( isset( $roh['criteria'] ) && is_array( $roh['criteria'] ) ? $roh['criteria'] : array() as $k ) { $label = is_array( $k ) && isset( $k['label'] ) && is_string( $k['label'] ) ? trim( sanitize_text_field( $k['label'] ) ) : ''; $gewicht = is_array( $k ) && isset( $k['weight'] ) && is_numeric( $k['weight'] ) ? (float) $k['weight'] : -1; if ( '' === $label || mb_strlen( $label ) > 60 || $gewicht < 0 || $gewicht > 100 || floor( $gewicht ) !== $gewicht ) { return $fehler; } $kriterien[] = array( 'label' => $label, 'weight' => (int) $gewicht, ); } if ( count( $kriterien ) < 1 || count( $kriterien ) > 12 ) { return $fehler; } return array( 'name' => $name, 'type' => $typ, 'scale' => $scale, 'step' => $step, 'criteria' => $kriterien, ); } /** * Mitgelieferte Vorlagen je Typ (Gewichte ergeben 100). * * @return array */ public static function builtin() { $k = function ( array $paare ) { $out = array(); foreach ( $paare as $paar ) { $out[] = array( 'label' => $paar[0], 'weight' => $paar[1], ); } return $out; }; return array( 'product' => array( 'name' => __( 'Product', '3task-review-box' ), 'type' => 'product', 'scale' => 'p10', 'step' => 0.1, 'criteria' => $k( array( array( __( 'Performance', '3task-review-box' ), 30 ), array( __( 'Build quality', '3task-review-box' ), 25 ), array( __( 'Handling', '3task-review-box' ), 25 ), array( __( 'Value for money', '3task-review-box' ), 20 ), ) ), ), 'movie' => array( 'name' => __( 'Movie', '3task-review-box' ), 'type' => 'movie', 'scale' => 's10', 'step' => 0.1, 'criteria' => $k( array( array( __( 'Story', '3task-review-box' ), 30 ), array( __( 'Acting', '3task-review-box' ), 25 ), array( __( 'Visuals', '3task-review-box' ), 25 ), array( __( 'Sound and music', '3task-review-box' ), 20 ), ) ), ), 'series' => array( 'name' => __( 'TV series', '3task-review-box' ), 'type' => 'series', 'scale' => 's10', 'step' => 0.1, 'criteria' => $k( array( array( __( 'Story', '3task-review-box' ), 30 ), array( __( 'Characters', '3task-review-box' ), 30 ), array( __( 'Pacing', '3task-review-box' ), 20 ), array( __( 'Production', '3task-review-box' ), 20 ), ) ), ), 'game' => array( 'name' => __( 'Video game', '3task-review-box' ), 'type' => 'game', 'scale' => 'p10', 'step' => 0.1, 'criteria' => $k( array( array( __( 'Gameplay', '3task-review-box' ), 35 ), array( __( 'Graphics', '3task-review-box' ), 20 ), array( __( 'Sound', '3task-review-box' ), 15 ), array( __( 'Story', '3task-review-box' ), 15 ), array( __( 'Value for money', '3task-review-box' ), 15 ), ) ), ), 'software' => array( 'name' => __( 'Software or app', '3task-review-box' ), 'type' => 'software', 'scale' => 'p10', 'step' => 0.1, 'criteria' => $k( array( array( __( 'Ease of use', '3task-review-box' ), 30 ), array( __( 'Features', '3task-review-box' ), 25 ), array( __( 'Speed', '3task-review-box' ), 20 ), array( __( 'Privacy', '3task-review-box' ), 15 ), array( __( 'Value for money', '3task-review-box' ), 10 ), ) ), ), 'book' => array( 'name' => __( 'Book', '3task-review-box' ), 'type' => 'book', 'scale' => 's5', 'step' => 0.5, 'criteria' => $k( array( array( __( 'Content', '3task-review-box' ), 35 ), array( __( 'Writing style', '3task-review-box' ), 30 ), array( __( 'Structure', '3task-review-box' ), 20 ), array( __( 'Value for money', '3task-review-box' ), 15 ), ) ), ), 'recipe' => array( 'name' => __( 'Recipe', '3task-review-box' ), 'type' => 'recipe', 'scale' => 's5', 'step' => 0.5, 'criteria' => $k( array( array( __( 'Taste', '3task-review-box' ), 40 ), array( __( 'Effort', '3task-review-box' ), 20 ), array( __( 'Ingredients', '3task-review-box' ), 20 ), array( __( 'Reliability', '3task-review-box' ), 20 ), ) ), ), 'course' => array( 'name' => __( 'Course', '3task-review-box' ), 'type' => 'course', 'scale' => 'p10', 'step' => 0.1, 'criteria' => $k( array( array( __( 'Content', '3task-review-box' ), 35 ), array( __( 'Teaching', '3task-review-box' ), 30 ), array( __( 'Materials', '3task-review-box' ), 15 ), array( __( 'Value for money', '3task-review-box' ), 20 ), ) ), ), 'event' => array( 'name' => __( 'Event', '3task-review-box' ), 'type' => 'event', 'scale' => 'p10', 'step' => 0.1, 'criteria' => $k( array( array( __( 'Programme', '3task-review-box' ), 35 ), array( __( 'Organisation', '3task-review-box' ), 25 ), array( __( 'Venue', '3task-review-box' ), 20 ), array( __( 'Value for money', '3task-review-box' ), 20 ), ) ), ), 'music' => array( 'name' => __( 'Music', '3task-review-box' ), 'type' => 'music', 'scale' => 's5', 'step' => 0.5, 'criteria' => $k( array( array( __( 'Songwriting', '3task-review-box' ), 35 ), array( __( 'Performance', '3task-review-box' ), 25 ), array( __( 'Production', '3task-review-box' ), 25 ), array( __( 'Lyrics', '3task-review-box' ), 15 ), ) ), ), 'local' => array( 'name' => __( 'Local business (not your own)', '3task-review-box' ), 'type' => 'local', 'scale' => 's5', 'step' => 0.5, 'criteria' => $k( array( array( __( 'Service', '3task-review-box' ), 30 ), array( __( 'Quality', '3task-review-box' ), 30 ), array( __( 'Atmosphere', '3task-review-box' ), 20 ), array( __( 'Value for money', '3task-review-box' ), 20 ), ) ), ), ); } /** * Ausgabeform einer Vorlage. * * @param string $key Schlüssel. * @param array $v Vorlage. * @param bool $builtin Mitgeliefert. * @return array */ private static function form( $key, array $v, $builtin ) { return array( 'key' => $key, 'name' => $v['name'], 'type' => $v['type'], 'scale' => $v['scale'], 'step' => (float) $v['step'], 'criteria' => $v['criteria'], 'builtin' => (bool) $builtin, ); } }