The Community forums are being phased out in favor of a new Slack group.
Add your email address below to get an invitation to join the community slack group

Slack Signup
Newsletter Optin
Help Desk

How to create entries for a form that contains the file upload field using Formidable API

Labels

This Discussion is public

Notifications

Formidable API and even WordPress REST API v2 are having difficulties to upload media to the target server. Here is a method to overcome the limitations and be able to create entries that include uploaded files.In my case I wrote a simple C# Windows Forms application that controls the network scanner, grabs the images then upload them inside a Formidable Forms entry along with other structured data.

We have to split the workload in two main parts, first to make sure the file gets uploaded into .../uploads folder or somewhere further down, and second to deal with registration of the files inside the WordPress/Formidable Forms database.For me WordPress REST API v2 for media looked a bit worrysome because I had to write the API client in C# and things are a bit complicated in the WP API specifications. Therefore I preffered to write my own API endpoint to deal with the issue.The following are the steps needed to complete the task. I am sure there are variations or perhaps even better approaches but this is what worked for me:

  1. upload the files via any method such as FTP or network share to the /uploads folder of WordPress (of course if many files are to be uploaded use a more granulated structure like /uploads/year/month/day/)
  2.  extend WP REST API v2 with a new custom endpoint (see below)
  3. POST to the above endpoint the relative file uploaded name from step 2 like: /2017/01/some-uploaded-file.jpg
  4. The custom endpoint will answer with a simple json like {'id':'786'} where 786 is the attachment ID created in windows media.
  5. POST via Formidable API to create the entry, use string of comma separated ids of the previously uploaded files as the file upload field value and we are done

This is the custom API endpoint as a plugin that manage to create a media attachment from the uploaded file and returns the id of the attachment:

/*
Plugin Name: REST API RICHARD CUSTOM
Description: Extended media uploaded via FTP endpoint for WP REST API 2.0
Version: 1.0
Author: Richard Vencu
Plugin URI: 
 */
 
add_action( 'rest_api_init', function () {
 require_once(ABSPATH . 'wp-admin/includes/user.php');
 register_rest_route( 'ivory/v1', '/mupload', array(
 'methods' => 'POST',
 'args' => array(
 'file' => array(
 'validate_callback' => function($param, $request, $key) {
 return true;
 }
 ),
 ),
 'callback' => 'IVORY_media_upload',
 'permission_callback' => function () {
 return true; //current_user_can( 'upload_files' );
 }
 ) );
} );

function IVORY_media_upload( WP_REST_Request $data ) {

 $media = new RICH;
 
 $id = $media->create( $data["file"] );
 if (is_numeric($id)) {
 return new WP_REST_Response( array('id' => $id), array( 'status' => 200 ) );
 }
 else {
 return $id; //$id is already well formatted WP_Error
 }
}



class RICH { //stripped down AMU class https://gist.github.com/Giuseppe-Mazzapica/10951232

 /**
 * Get a relative path to a file and create an attachment post
 *
 * @param string $file Relative path to 'uploads folder' for the file
 * @return int The attachment ID, 0 on failure
 * @access private
 * @uses shouldCreate
 */
 function create( $file = '' ) {
 $wp_upload_dir = wp_upload_dir();
 $fullpath = $this->shouldCreate( $file, $wp_upload_dir );
 if ( is_wp_error( $fullpath ) ) {
 return $fullpath;
 }
 $filetype = wp_check_filetype( basename( $fullpath ), NULL );
 $attachment = array (
 'guid' => $wp_upload_dir['url'] . '/' . basename( $fullpath ),
 'post_mime_type' => $filetype['type'],
 'post_title' => preg_replace( '/.[^.]+$/', '', basename( $fullpath ) ),
 'post_content' => '',
 'post_status' => 'inherit'
 );
 $attach_id = wp_insert_attachment( $attachment, $fullpath, 0 );
 require_once( ABSPATH . 'wp-admin/includes/image.php' );
 $attach_data = wp_generate_attachment_metadata( $attach_id, $fullpath );
 wp_update_attachment_metadata( $attach_id, $attach_data );
 return $attach_id;
 }


 /**
 * Check existence of the file and using AMU::isAttached() check if it is already attached to
 * an existend attachemnt post. Return fullpath of the file if both check are passed.
 *
 * @param string $file Relative path to 'uploads folder' for the file
 * @param array $wp_upload_dir Whatever returned by wp_upload_dir()
 * @return string|WP_Error Full path of the fail or WP_Error on failure
 */
 private function shouldCreate( $file, $wp_upload_dir ) {
 if ( ! is_string( $file ) || empty( $file ) ) {
 $msg = sprintf( "Please use valid file relative path with %s", __FUNCTION__ );
 return new WP_Error( 'bad_file_arg', $msg, array( 'status' => 409 ) );
 }
 $base = $wp_upload_dir['basedir'];
 $fullpath = trailingslashit( $base ) . $file;
 if ( ! file_exists( $fullpath ) ) {
 $msg = sprintf( "The file %s does not exists", $fullpath );
 return new WP_Error( 'file_not_exists', $msg, array( 'status' => 409 ) );
 }
 $already = $this->isAttached( $file );
 if ( $already > 0 ) {
 $url = get_edit_post_link( $already, '' );
 $link = sprintf( '<a href="%s">(ID: %d)</a>', $url, $already );
 $msg = sprintf( "The file %s is already connected to an attachment %s", $file, $link );
 return new WP_Error( 'file_attached', $msg, array( 'status' => 409 ) );
 }
 return $fullpath;
 }

 /**
 * Query database to see if a file is already attached to an attachement post
 *
 * @global wpdb $wpdb
 * @param string $file Relative path to 'uploads folder' for the file
 * @return int Attachement post id if found, 0 otherwise
 */
 private function isAttached( $file ) {
 global $wpdb;
 $query = "SELECT p.ID FROM {$wpdb->posts} p "
 . "INNER JOIN {$wpdb->postmeta} m ON p.ID = m.post_id "
 . "WHERE p.post_type = 'attachment' "
 . "AND m.meta_key = '_wp_attached_file' "
 . "AND m.meta_value = %s GROUP BY p.ID LIMIT 1";
 return (int) $wpdb->get_var( $wpdb->prepare( $query, $file ) );
 }

}

Discussion closed.