1

I'm building a React app (with create-react-app) and I need to upload images in a Wordpress website, using Wordpress Media Rest API. I'm running the react app locally (http://localhost:3000/test) In the Wordpress website I am using 'JWT Authentication for WP-API' plugin for easier authentication.

When I try to upload the image, it gives me a '400 - Bad Request' response with the following details:

{"code":"rest_upload_no_data","message":"No data supplied.","data":{"status":400}}

I've been searching and trying all solutions I found the last 3 days. None of them works.

My implementation details:

In wp-config, I did all the changes described in the plugin's page.

WP Server .htaccess

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [E=REMOTE_USER:%{HTTP:Authorization}]
SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1 
#RewriteRule ^(.*) - [E=HTTP_AUTHORIZATION:%1]
Header set Access-Control-Allow-Headers "Origin, X-Requested-With, Content-Type, Content-Length, Cache-Control, Content-Disposition, Accept"
</IfModule>

# END WordPress

# BEGIN cPanel-generated php ini directives, do not edit
# Manual editing of this file may result in unexpected behavior.
# To make changes to this file, use the cPanel MultiPHP INI Editor (Home >> Software >> MultiPHP INI Editor)
# For more information, read our documentation (https://go.cpanel.net/EA4ModifyINI)
<IfModule php7_module>
   php_flag display_errors Off
   php_value max_execution_time 30
   php_value max_input_time 60
   php_value max_input_vars 1000
   php_value memory_limit 256M
   php_value post_max_size 260M
   php_value session.gc_maxlifetime 1440
   php_value session.save_path "/var/cpanel/php/sessions/ea-php72"
   php_value upload_max_filesize 256M
   php_flag zlib.output_compression Off

</IfModule>
<IfModule lsapi_module>
   php_flag display_errors Off
   php_value max_execution_time 30
   php_value max_input_time 60
   php_value max_input_vars 1000
   php_value memory_limit 256M
   php_value post_max_size 260M
   php_value session.gc_maxlifetime 1440
   php_value session.save_path "/var/cpanel/php/sessions/ea-php72"
   php_value upload_max_filesize 256M
   php_flag zlib.output_compression Off
</IfModule>
# END cPanel-generated php ini directives, do not edit

React

const Test = () => {

    const [isUploading, setIsUploading] = useState(false)
    const [selectedFile, setSelectedFile] = useState(null)
    const blockScreenContext = useContext(BlockScreenUIContext)

    const fileUploadHandler = e => {

        e.preventDefault();

        //setting the data that will parsed with the file
        let oDate = new Date();
        let wpMediaData = {
            title: 'Posted from App',
            caption: 'The post caption text'
        }


        //creating the form data object and appending the extra info for the file
        let formData = new FormData();
        for (var key in wpMediaData) {
            formData.append(key, wpMediaData[key])
        }

        formData.append('file', selectedFile)
        //formData.append('file', document.querySelector('input[type="file"]').files[0])

        //defining the base url
        let baseUrl = 'https://mywebsite.com/'


        //getting the token
        let token = 'my token'

            let headers = {
                Authorization: 'Bearer ' + token,
                'Content-Type': 'multipart/form-data; charset=utf-8; boundary=' + Math.random().toString().substr(2),
                'Content-Disposition': `form-data; filename="${selectedFile.name}"`,
                'Cache-Control': 'no-cache',
            }


            const options = {
                method: 'POST',
                body: formData,
                headers: headers
            }

            let url = baseUrl + 'wp-json/wp/v2/media'

            fetch( url, options).then(res => {
                console.log('response', res)

            }).catch(err => {
                console.log('error', err)
            })


    }

    const fileSelectedHandler = e => {
        //the first element of the target is the file
        console.log('o valor obtido com e.target', e.target.files[0])
        setSelectedFile(e.target.files[0])
    }

    return <div>
        <form method="POST" encType="multipart/form-data">
            <div className="form-group">
                <input id="file" name="file" type="file" className="form-control" onChange={fileSelectedHandler} />
            </div>
            <div className="form-group">
                <BSButton
                    type='submit'
                    className='btn-primary'
                    text="Upload"
                    loadingText="Uploading..."
                    onClick={fileUploadHandler}
                    disable={isUploading}
                />
            </div>

        </form>
    </div>
}

For Content Disposition, I also tried:

Content-Disposition': `attachment; filename=${selectedFile.name}

I tried to use Axios instead, and had the same problem. All other requests with Wordpress are working fine. Thank you in advance!

2
  • First try the api with a rest client like postman and find whether the issue is with the client side or server side. This must be the first step to do. Commented Aug 25, 2019 at 12:19
  • @KrishnadasPC I also tried that, and got the same response. In my case, i used Insomnia. Commented Aug 25, 2019 at 15:08

2 Answers 2

1

I've made a separated re-usable method for media uploading using @wordpress/api-fetch which is now a good standard for fetching/storing data in WordPress.

// Import api-fetch Library
import apiFetch from '@wordpress/api-fetch';

/**
 * Upload a media file.
 *
 * @param {Object} file
 * @param {Object} additionalData
 *
 * @return {Promise} A promise representing the request processed via the registered middlewares.
 */
export function uploadMedia(file, additionalData = {}) {
    const data = new window.FormData();
    data.append('file', file, file.name || file.type.replace('/', '.'));

    if (additionalData) {
        Object.entries(additionalData).forEach(([key, value]) =>
            data.append(key, value)
        );
    }

    return apiFetch({
        path: '/wp/v2/media',
        method: 'POST',
        body: data,
    });
}

And then call this method easily as your needs.

<input type="file" onChange={(e) => uploadMedia(e.target.files[0])} />

Hope, this will help many ones in future.

Sign up to request clarification or add additional context in comments.

Comments

0

It was a full day of my experiments, but it works!

  1. button MEDIA in this repository https://github.com/fotomain/react-wordpress-auth-starter/blob/master/src/App.js
  2. define('ALLOW_UNFILTERED_UPLOADS', true);

Comments

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.