WP_REST_Server::READABLE, 'callback' => array( $this, 'index' ), 'permission_callback' => array( $this, 'can_manage' ), 'args' => array( 'page' => array( 'type' => 'integer', 'default' => 1, 'minimum' => 1, ), 'per_page' => array( 'type' => 'integer', 'default' => 20, 'minimum' => 1, 'maximum' => 100, ), 'search' => array( 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field', ), 'status' => array( 'type' => 'string', 'enum' => array( '', 'published', 'draft' ), ), 'has' => array( 'type' => 'string', 'enum' => array( '', 'unread', 'entries', 'empty' ), ), 'orderby' => array( 'type' => 'string', 'enum' => array( 'updated', 'created', 'title', 'entries', 'unread', 'views' ), 'default' => 'updated', ), 'order' => array( 'type' => 'string', 'enum' => array( 'asc', 'desc' ), 'default' => 'desc', ), ), ), array( 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'create' ), 'permission_callback' => array( $this, 'can_manage' ), ), ) ); register_rest_route( self::NS, '/forms/(?P\d+)', array( 'args' => $this->id_arg(), array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'show' ), 'permission_callback' => array( $this, 'can_manage' ), ), array( 'methods' => WP_REST_Server::EDITABLE, 'callback' => array( $this, 'update' ), 'permission_callback' => array( $this, 'can_manage' ), ), array( 'methods' => WP_REST_Server::DELETABLE, 'callback' => array( $this, 'delete' ), 'permission_callback' => array( $this, 'can_manage' ), ), ) ); register_rest_route( self::NS, '/forms/(?P\d+)/duplicate', array( 'args' => $this->id_arg(), 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'duplicate' ), 'permission_callback' => array( $this, 'can_manage' ), ) ); register_rest_route( self::NS, '/forms/export', array( 'args' => array( 'ids' => array( 'type' => 'array', 'items' => array( 'type' => 'integer' ), 'required' => true, 'maxItems' => 100, ), ), 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'export' ), 'permission_callback' => array( $this, 'can_manage' ), ) ); register_rest_route( self::NS, '/forms/import', array( 'args' => array( 'forms' => array( 'type' => 'array', 'required' => true, 'maxItems' => 100, ), ), 'methods' => WP_REST_Server::CREATABLE, 'callback' => array( $this, 'import' ), 'permission_callback' => array( $this, 'can_manage' ), ) ); register_rest_route( self::NS, '/forms/(?P\d+)/stats', array( 'args' => array_merge( $this->id_arg(), array( 'days' => array( 'type' => 'integer', 'default' => 30, 'minimum' => 1, 'maximum' => 365, ), ) ), 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'stats' ), 'permission_callback' => array( $this, 'can_manage' ), ) ); register_rest_route( self::NS, '/templates', array( 'methods' => WP_REST_Server::READABLE, 'callback' => array( $this, 'templates' ), 'permission_callback' => array( $this, 'can_manage' ), ) ); } /** * GET /forms. * * @param WP_REST_Request $request Request. * @return \WP_REST_Response */ public function index( WP_REST_Request $request ) { $result = FormRepository::query( array( 'page' => $request['page'], 'per_page' => $request['per_page'], 'search' => $request['search'], 'status' => $request['status'], 'has' => $request['has'], 'orderby' => $request['orderby'], 'order' => $request['order'], ) ); $items = array_map( array( $this, 'summary' ), $result['items'] ); $response = $this->paged( $items, $result['total'], (int) $request['per_page'] ); $response->header( 'X-PF-Counts', (string) wp_json_encode( FormRepository::counts() ) ); $response->header( 'X-PF-Totals', (string) wp_json_encode( FormRepository::totals() ) ); return $response; } /** * POST /forms. Accepts a template id or a full definition. * * @param WP_REST_Request $request Request. * @return \WP_REST_Response|\WP_Error */ public function create( WP_REST_Request $request ) { $params = (array) $request->get_json_params(); $data = array(); if ( ! empty( $params['template'] ) ) { $templates = Templates::all(); $key = sanitize_key( (string) $params['template'] ); if ( ! isset( $templates[ $key ] ) ) { return new \WP_Error( 'fillaro_template', __( 'Unknown template.', 'fillaro' ), array( 'status' => 400 ) ); } $data = $templates[ $key ]; $data['title'] = 'blank' === $key ? __( 'Untitled form', 'fillaro' ) : $data['title']; } $data = array_merge( $data, array_intersect_key( $params, array_flip( array( 'title', 'status', 'fields', 'settings', 'theme' ) ) ) ); $id = FormRepository::create( $data ); if ( ! $id ) { return new \WP_Error( 'fillaro_db', __( 'Could not create the form.', 'fillaro' ), array( 'status' => 500 ) ); } $response = rest_ensure_response( $this->full( FormRepository::find( $id ) ) ); $response->set_status( 201 ); return $response; } /** * GET /forms/{id}. * * @param WP_REST_Request $request Request. * @return \WP_REST_Response|\WP_Error */ public function show( WP_REST_Request $request ) { $form = FormRepository::find( (int) $request['id'] ); if ( ! $form ) { return $this->not_found(); } return rest_ensure_response( $this->full( $form ) ); } /** * PUT /forms/{id}. * * @param WP_REST_Request $request Request. * @return \WP_REST_Response|\WP_Error */ public function update( WP_REST_Request $request ) { $id = (int) $request['id']; if ( ! FormRepository::find( $id ) ) { return $this->not_found(); } if ( ! FormRepository::update( $id, (array) $request->get_json_params() ) ) { return new \WP_Error( 'fillaro_db', __( 'Could not save the form.', 'fillaro' ), array( 'status' => 500 ) ); } return rest_ensure_response( $this->full( FormRepository::find( $id ) ) ); } /** * DELETE /forms/{id}. * * @param WP_REST_Request $request Request. * @return \WP_REST_Response|\WP_Error */ public function delete( WP_REST_Request $request ) { $id = (int) $request['id']; if ( ! FormRepository::find( $id ) ) { return $this->not_found(); } FormRepository::delete( $id ); return rest_ensure_response( array( 'deleted' => true ) ); } /** * POST /forms/{id}/duplicate. * * @param WP_REST_Request $request Request. * @return \WP_REST_Response|\WP_Error */ public function duplicate( WP_REST_Request $request ) { $id = FormRepository::duplicate( (int) $request['id'] ); if ( ! $id ) { return $this->not_found(); } $response = rest_ensure_response( $this->full( FormRepository::find( $id ) ) ); $response->set_status( 201 ); return $response; } /** * GET /forms/export?ids[]=…: forms as a portable JSON document, without * entries or site-specific IDs. * * @param WP_REST_Request $request Request. * @return \WP_REST_Response|\WP_Error */ public function export( WP_REST_Request $request ) { $forms = array(); foreach ( array_unique( array_map( 'absint', (array) $request['ids'] ) ) as $id ) { $form = FormRepository::find( $id ); if ( ! $form ) { continue; } $item = array( 'title' => $form['title'], 'fields' => $form['fields'], 'settings' => $form['settings'], 'theme' => $form['theme'], ); // A page ID means nothing on another site. $item['settings']['confirmation']['pageId'] = 0; /** * Filters one exported form. Add-ons remove secrets and * site-specific connections here. * * @param array $item Exported form: title, fields, settings, theme. * @param array $form Form. */ $forms[] = (array) apply_filters( 'fillaro/export_form', $item, $form ); } if ( ! $forms ) { return $this->not_found(); } return rest_ensure_response( array( 'format' => 'fillaro', 'version' => 1, 'plugin' => FILLARO_VERSION, 'exported' => gmdate( 'c' ), 'forms' => $forms, ) ); } /** * POST /forms/import: create forms from an export, as drafts. * * @param WP_REST_Request $request Request. * @return \WP_REST_Response|\WP_Error */ public function import( WP_REST_Request $request ) { $created = array(); foreach ( (array) $request['forms'] as $item ) { if ( ! is_array( $item ) || empty( $item['fields'] ) || ! is_array( $item['fields'] ) ) { continue; } // Everything goes through the normal sanitizers in create(). $id = FormRepository::create( array( 'title' => isset( $item['title'] ) && is_string( $item['title'] ) ? $item['title'] : __( 'Imported form', 'fillaro' ), 'status' => 'draft', 'fields' => $item['fields'], 'settings' => isset( $item['settings'] ) && is_array( $item['settings'] ) ? $item['settings'] : array(), 'theme' => isset( $item['theme'] ) && is_array( $item['theme'] ) ? $item['theme'] : array(), ) ); if ( $id ) { $created[] = $id; } } if ( ! $created ) { return new \WP_Error( 'fillaro_import', __( 'No forms found in this file. Choose a file exported from Fillaro.', 'fillaro' ), array( 'status' => 400 ) ); } $response = rest_ensure_response( array( 'ids' => $created ) ); $response->set_status( 201 ); return $response; } /** * GET /forms/{id}/stats. * * @param WP_REST_Request $request Request. * @return \WP_REST_Response|\WP_Error */ public function stats( WP_REST_Request $request ) { if ( ! FormRepository::find( (int) $request['id'] ) ) { return $this->not_found(); } return rest_ensure_response( Stats::series( (int) $request['id'], (int) $request['days'] ) ); } /** * GET /templates. * * @return \WP_REST_Response */ public function templates() { $out = array(); foreach ( Templates::all() as $key => $t ) { $out[] = array( 'id' => $key, 'title' => $t['title'], 'description' => $t['description'], 'icon' => $t['icon'], 'fieldCount' => count( $t['fields'] ), 'theme' => Theme::sanitize( array_merge( Theme::defaults(), $t['theme'] ) ), ); } return rest_ensure_response( $out ); } /** * List view of a form. * * @param array $form Form. * @return array */ public function summary( array $form ) { return array( 'id' => $form['id'], 'title' => $form['title'], 'status' => $form['status'], 'fieldCount' => count( $form['fields'] ), 'primary' => $form['theme']['primary'], 'stats' => isset( $form['stats'] ) ? $form['stats'] : null, 'shortcode' => sprintf( '[fillaro id="%d"]', $form['id'] ), 'previewUrl' => Preview::url( $form['id'] ), 'updatedAt' => $form['updated_at'], 'createdAt' => $form['created_at'], ); } /** * Full form for the builder. * * @param array $form Form. * @return array */ private function full( array $form ) { return array_merge( $this->summary( $form ), array( 'fields' => $form['fields'], 'settings' => $form['settings'], 'theme' => $form['theme'], ) ); } /** * 404 error. * * @return \WP_Error */ private function not_found() { return new \WP_Error( 'fillaro_not_found', __( 'Form not found.', 'fillaro' ), array( 'status' => 404 ) ); } }