Skip Navigation

A note on using the cred_form_ajax_upload_validate hook

Resolved

Reported for: Toolset Forms 2.4

Resolved in: Toolset Forms 2.4

Symptoms

In Forms 2.4 we switched the AJAX upload mechanism for media fields, from a jQuery upload plugin, to the native media library provided by WordPress.

One side effect of that change is that, when the file is being uploaded, the $_FILES global holds data in a slightly different structure:

  • The jQuery uploads plugin included one entry for each file field being uploaded, with the key being the field slug.
  • The native media library holds the same data, but the key is no longer the field slug. It uses the keyword async-upload instead.

This should not be a problem, since the cred_form_ajax_upload_validate provides all the information you would need to validate a file being uploaded. However, we detected some support tickets that included some custom code that was accessing directly the $_FILES global instead.

Please never trust any external data when working with a hook (an action or a filter). The only data that will keep its structure on a hook callback is the one passed to the hook itself.

Workaround

The correct way of accessing the data for the file being uploaded when using AJAX on a media field in Forms is as follows (and this is working before, on, and after Forms 2.4):

add_filter( 'cred_form_ajax_upload_validate', 'prefix_get_data_for_uploading_files', 10, 2 );
function prefix_get_data_for_uploading_files( $error_fields, $form_data ) {
// You can apply this to a given relevant form checking against $form_data['id']

// Get the list of uploading fields and errors
list( $fields, $errors ) = $error_fields;

// Put here the key of the field that you want to validate
$field_key = 'my-field-key';
// You can get data from the uploading field as follows:
if ( array_key_exists( $field_key, $fields ) ) {
$file_uploading_data = $fields[ $field_key ];
// Get the filename for the file being uploaded
$file_uploading_name = $file_uploading_data['field_data']['name'];
// Get the mime type of the file being uploaded
$file_uploading_type = $file_uploading_data['field_data']['type'];
// Get the size of the file being uploaded
$file_uploading_size = $file_uploading_data['field_data']['size'];
// Get the temporary name of the file being uploaded
$file_uploading_tmp_name = $file_uploading_data['field_data']['tmp_name'];
}

return array( $fields, $errors );
}


In case you have some old custom code that is hard to review, and that is getting data from the global $_FILES inside a callback for this cred_form_ajax_upload_validate filter, here it is a workaround that should set the global data to what it was before Forms 2.4, and then reset it back to what the media library requires.

Use at your own risk, since the preferred, supported mechanism to get and check data from the file being uploaded is described above.

add_filter( 'cred_form_ajax_upload_validate', 'prefix_cred_form_ajax_upload_validate_set_legacy_global_files', 1 );
add_filter( 'cred_form_ajax_upload_validate', 'prefix_cred_form_ajax_upload_validate_reset_global_files', 9999 );
function prefix_cred_form_ajax_upload_validate_set_legacy_global_files( $error_fields ) {
if ( array_key_exists( 'async-upload', $_FILES ) ) {
$files_global = array();
list( $fields, $errors ) = $error_fields;
foreach ( $fields as $field_key => $field_data ) {
$files_global[ $field_key ] = $field_data['field_data'];
}
$_FILES = $files_global;
}
return $error_fields;
}
function prefix_cred_form_ajax_upload_validate_reset_global_files( $error_fields ) {
$files_global = $_FILES;
$files_global_restored = array();
foreach ( $files_global as $key => $value ) {
$files_global_restored['async-upload'] = $value;
}
$_FILES = $files_global_restored;
return $error_fields;
}

Comments are closed