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

Est. Reading: 4 minutes
By: rvencu
Created: 01/21/2017
Category:
Difficulty: Intermediate

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

×Warning: This tutorial was created 2670 days ago. Some of the information may be out of date with more recent versions of Formidable. Please proceed with caution and always perform a backup before adding custom code.

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 ) );
 }

}

Leave a Reply

Making the Best WordPress Plugin even better - Together

Take on bigger projects with confidence knowing you have access to an entire community of Formidable Experts and Professionals who have your back when the going gets tough. You got this!
Join the community
crosschevron-leftchevron-rightarrow-right