\d+)/submissions', array( 'methods' => \WP_REST_Server::CREATABLE, 'callback' => array( self::class, 'create_submission' ), // Public by design: anyone may submit a published contact form, exactly // like the HTML form. Abuse is handled by Spam_Guard (honeypot, time // trap, rate limit, and a nonce for logged-in users). 'permission_callback' => '__return_true', 'args' => array( 'id' => array( 'type' => 'integer', 'required' => true, 'minimum' => 1, 'sanitize_callback' => 'absint', ), ), ) ); } /** * Handles a submission. * * @param \WP_REST_Request $request Request. */ public static function create_submission( \WP_REST_Request $request ): \WP_REST_Response|\WP_Error { $form = Form::find( (int) $request->get_param( 'id' ) ); if ( null === $form ) { return new \WP_Error( 'tflexforms_not_found', __( 'Form not found.', 'flexsolutions-form-builder' ), array( 'status' => 404 ) ); } // Body params only (form-encoded or JSON); never mix in query-string values. // The REST server has already unslashed these. $input = $request->get_json_params(); if ( ! is_array( $input ) || array() === $input ) { $input = $request->get_body_params(); } // Sanitized as plain text here; Validator then checks each field for its type. $input = is_array( $input ) ? map_deep( $input, 'sanitize_textarea_field' ) : array(); $result = Submission_Handler::process( $form, $input, (array) $request->get_file_params() ); $invalid = array(); foreach ( $result->errors as $field => $message ) { $invalid[] = array( 'field' => $field, 'message' => $message, ); } $response = new \WP_REST_Response( array( 'status' => $result->status, 'message' => $result->message, 'invalid_fields' => $invalid, 'redirect' => $result->is_success() ? Submission_Handler::redirect_url( $form ) : '', ), $result->http_status() ); // Submission responses must never be cached by proxies or CDNs. $response->header( 'Cache-Control', 'no-store, private' ); return $response; } }