I'm building a form widget with upload field, where the form data is sent via POST request through Wordpress REST API. Works well, but I can't make the upload file be sent with the proper file name and file extension. It is currently being sent with temporary name and .tmp extension.
The JS Ajax request to exemplify:
submitData(form) {
let formData = new FormData(form[0]);
jQuery.ajax({
url: '/wp-json/my-plugin/v1/send_email/',
type: 'POST',
data: formData,
processData: false,
contentType: false,
beforeSend: function () {
// validate fields
},
success: function (response) {
// success actions
},
error: function () {
// build error messages
}
});
return false;
}
Example of the file data received through REST API:
{
"form_fields": {
"name": {
"file": "beatifull-picture.jpeg"
},
"full_path": {
"file": "beatifull-picture.jpeg"
},
"type": {
"file": "image/jpeg"
},
"tmp_name": {
"file": "C:\\Windows\\Temp\\phpD363.tmp"
},
"error": {
"file": 0
},
"size": {
"file": 364006
}
}
}
The code responsible for adding the attachment to wp_mail()
:
protected function send_mail($mail_data, $file){
// ..
$attachment = $this->prepare_attachments($file);
$email = wp_mail(
$mail_data['mail_to'],
$mail_data['mail_subject'],
$mail_data['mail_message'],
$mail_data['headers'],
$attachment,
);
}
// KEY FUNCTION
protected function prepare_attachments($files) {
$attachments = [];
// Iterate through the files array to extract attachments
if (isset($files['form_fields']['tmp_name']['file'])) {
$tmp_name = $files['form_fields']['tmp_name']['file'];
$error = $files['form_fields']['error']['file'];
if ($error === UPLOAD_ERR_OK) {
// Log the path of each file
error_log('Attachment: ' . $tmp_name);
$attachments[] = $tmp_name;
}
}
return $attachments;
}
I've tried getting the original name of the file instead of the temp name, but then the files aren't attached; tried uploading to wordpress before attaching; tried to store the original name and extension and replace after, but nothing worked so far.
Using wp_handle_upload() did the job. The problem was that only getting /using the attachment data without moving the file to somewhere before sending don't work. Would always be sent as temporary format/extension.
<?php
protected function prepare_attachments($files) {
$attachments = [];
// Check if wp_handle_upload is available
if ( ! function_exists( 'wp_handle_upload' ) ) {
require_once( ABSPATH . 'wp-admin/includes/file.php' );
}
if (isset($files['form_fields']['tmp_name']['file'])) {
// Populate the file array with the file details
$file = array(
'name' => $files['form_fields']['name']['file'],
'type' => $files['form_fields']['type']['file'],
'tmp_name' => $files['form_fields']['tmp_name']['file'],
'error' => $files['form_fields']['error']['file'],
'size' => $files['form_fields']['size']['file'],
);
// Upload the file to the uploads directory
$upload_result = wp_handle_upload($file, ['test_form' => false]);
if (!isset($upload_result['error'])) {
$attachments[] = $upload_result['file'];
// delete the uploaded file after sending the email
register_shutdown_function('unlink', $upload_result['file']);
} else {
// Log an error if the file could not be moved
error_log('Failed to upload file: ' . $upload_result['error']);
}
}
return $attachments;
}