0

I have one endpoint to create players, which is a PUT request to a certain route. While I was sending parameters via JSON, it was working fine, but now I need to upload a picture with data, so I switched to formdata format.

This is the function running in the endpoint:

    public function put(WP_REST_Request $request)
    {

        ['foto' => $file] = $request->get_file_params();

        if (!empty($file)) {
            if (!function_exists('media_handle_upload')) {
                require_once(ABSPATH . 'wp-admin/includes/image.php');
                require_once(ABSPATH . 'wp-admin/includes/file.php');
                require_once(ABSPATH . 'wp-admin/includes/media.php');
            }

            $attachmentId = media_handle_upload('foto', 0);
        }

        //Recebe os dados
        $genero = $request['genero'];
        $nome = $request['nome'];
        $apelido = $request['apelido'];
        $data_nascimento = $request['data-nascimento'];
        $turma = $request['class_id'];
        $avatar = $request['avatar'];
        $id_parent = $request['user_id'];

        //Criar player
        $playerId = wp_insert_post([
            'post_type' => 'player'
            'post_status' => 'publish',
            'post_title' => '',
            'post_author' => $id_parent,
            'meta_input' => [
                'genero' => $genero,
                'nome' => $nome,
                'apelido' => $apelido,
                'data-nascimento' => $data_nascimento,
                'avatar' => $avatar,
            ]
        ]);

        if (is_wp_error($playerId)) {
            return $this->error([
                'status' => 'error',
                'message' => 'Não foi possível criar o jogador'
            ]);
        }

        // ...
        return $this->response([
            'status' => 'success',
            'message' => 'player cadastrado',
            'id' => $playerId,
            // next row is added for testing purpose
            'body_params' => $request->get_body_params(),

        ], 201);
    }

This runs in rest_api_init hook:

// ...
        register_rest_route("zw/v1", "players", [
                    'methods' => "PUT",
                    'callback' => [$playersApi, "put"],
                    'permission_callback' => [$playersApi, 'permissionCallback']
                ]);

When I use PUT method, body_params returns as empty array. Switching to POST method it works as expected. But I would like to keep semantics of the API, so what do I have to do to make PUT request read the body as formdata?

9
  • Can you include the endpoint/route registration that you're using with this callback? Internally the REST API considers POST PUT and PATCH to all be alias' of each other to be handled the same way ( github.com/WordPress/WordPress/blob/… )
    – Tom J Nowell
    May 26, 2022 at 23:24
  • Looks like put method is not supported in forms, see eg stackoverflow.com/questions/8054165/… if thats how you use it.
    – birgire
    May 26, 2022 at 23:26
  • I would note that after searching the WP codebase i can see no evidence of special handling of PUT, however PUT doesn't mean what you think it means, your endpoint doesn't fit the semantics of a PUT request anyway because PUT requests are an instruction to the server to take a given filepath that the server has access to and put it on the server, it's not the same as uploading the file, and you wouldn't be providing other parameters anyway. See php.net/manual/en/features.file-upload.put-method.php
    – Tom J Nowell
    May 26, 2022 at 23:27
  • @TomJNowell I updated my post with the route registration
    – Bruno Polo
    May 26, 2022 at 23:31
  • @TomJNowell about semantics, all I want is to keep standards that are already applied in the project, and having this one single case that is not compliant to everything else is annoying to me. I actually did change it to POST but I want to know why this happens.
    – Bruno Polo
    May 26, 2022 at 23:35

1 Answer 1

1

This is because PUT requests don't have body parameters, that's not how PUT works. PUT doesn't quite do what you thought it did, and can only be used to upload a file from a client.

Your endpoint is incompatible with PUT as a request type because you're providing parameters as key value pairs, and that is not possible with PUT:

According to the HTML standard, you can not. The only valid values for the method attribute are get and post, corresponding to the GET and POST HTTP methods. is invalid HTML and will be treated like , i.e. send a GET request.

Likewise:

XHTML 1.x forms only support GET and POST. GET and POST are the only allowed values for the "method" attribute.


As for WordPress, it doesn't handle PUT and treats it as an alias of POST along with PATCH, so while its handling is technically correct, it's only by accident.

Now this doesn't prevent PHP from using it as a file upload mechanism, but that is the only thing it can be used for:

https://www.php.net/manual/en/features.file-upload.put-method.php

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.