skip to Main Content

I am using Contact Form 7 (5.4) and CF7 Smart Grid Design Extension (4.10.0) in a submit form on my WordPress site to construct draft Custom Post Types. The original inspiration for this was this awesome SO post.

The submission form has worked well and reliably for over a year, but with the new CF7 5.4 version, something has changed internally and broken image uploads. All of the other fields have remained unchanged.

The CF7 field with which I am uploading appears as

[file* field_image limit:10000000 filetypes:jpg|gif|png|jpeg class:field-image]

The images get mailed, so the form is uploading the file properly. But something has changed that breaks my attempts to nab the images before they are deleted after emailing.

Here’s the relevant PHP in functions.php that handles uploaded images within the function that constructs a WP CPT.

// Handle CF7 form submission and populate new CPT 'Thing'
// Ref: https://wordpress.stackexchange.com/questions/328429/how-to-save-contact-form-7-data-in-custom-post-types-cpt
//
add_action('wpcf7_before_send_mail', 'save_my_form_data_to_my_cpt', 10, 3);
function save_my_form_data_to_my_cpt($contact_form){
    //Get the form ID
    $contact_form = WPCF7_ContactForm::get_current();
    $contact_form_id = $contact_form -> id;
    
    $submission = WPCF7_Submission::get_instance();
    if (!$submission){
        return $contact_form;
    }
    $posted_data = $submission->get_posted_data();
    //The Sent Fields are now in an array
    //you can now access them with $posted_data['my-email']
    //
    // create new post array
    $new_post = array();
    //
    // META META FIELDS
    // post_type (i.e., your CPT)
    $new_post['post_type'] = 'thing';
    // post_status (draft, publish, pending)
    $new_post['post_status'] = 'draft';
    //
    // POST FIELDS
    // post_title
    if(isset($posted_data['field_title']) &&
            !empty($posted_data['field_title'])){
        $new_post['post_title'] = $posted_data['field_title'];
    } else {
        $new_post['post_title'] = '[Insert Title Here]';
    }
    // POST CPT
    //When everything is prepared, insert post into WP Database
    if($post_id = wp_insert_post($new_post)){
        // it worked so let's continue...
        //
        // IMAGE
        // Retrieving and inserting uploaded image as featured image
        // CF7 uploads the image and puts it in a temporary directory,
        //      deleting it after the mail is sent
        // Before it deletes it, we will move into our media library,
        //      and attach it to our post
        //
        // get file upload info from form
        $uploadedFiles = $submission->uploaded_files();
        // if we have an uploaded image...
        if( isset($posted_data['field_image']) ){
            // move image from temp folder to upload folder
            $imageUpload = wp_upload_bits($posted_data['field_image'], null,
                file_get_contents($uploadedFiles['field_image']));
            //
            require_once(ABSPATH . 'wp-admin/includes/admin.php');
            // construct array to register this image
            $filename = $imageUpload['file'];
            $attachment = array(
                'post_mime_type' => $imageUpload['type'],
                'post_parent' => $post_id,
                'post_title' => $posted_data['field_title'] . ' - ' .
                            $posted_data['field_contributor'],
                'post_content' => $posted_data['field_info'],
                'post_status' => 'inherit'
            );
            // attach image to this post
            $attachment_id = wp_insert_attachment( $attachment, $filename, $post_id );
            // if we succeeded...
            if (!is_wp_error($attachment_id)) {
                require_once(ABSPATH . 'wp-admin/includes/image.php');
                $attachment_data = wp_generate_attachment_metadata( $attachment_id, $filename );
                wp_update_attachment_metadata( $attachment_id,  $attachment_data );
                set_post_thumbnail( $post_id, $attachment_id );
                // add image id (attchment id) to ad_image field
                update_field( 'ad_image', $attachment_id, $post_id );
            }
        }
    }
}

This is called by:

add_action('wpcf7_before_send_mail', 'save_my_form_data_to_my_cpt', 10, 3);

Images which are successfully being sent in CF7 emails don’t get uploaded to the new CPT being created.

While the problem could lie in the post submit code that handles the submission, none of that has changed in a year. Only CF7 has changed.

Any hints?

APPENDIX A: Complete Function

Here’s the entire save_my_form_data_to_my_cpt function:

~Deleted~

APPENDIX B: Debugging Output

Early in the function we call get the data that is passed from the CF7 form:

$submission = WPCF7_Submission::get_instance();
$posted_data = $submission->get_posted_data();
$uploadedFiles = $submission->uploaded_files();

When we dump these variables to the console we get a surprise. For $posted_data we get:

array (
  'field_title' => 'TEST',
  'field_expires' => '1',
  'field_tags' => 
  array (
    0 => 'Children',
  ),
  'field_addl_tags' => '',
  'field_info' => '',
  'field_call_to_action' => '',
  'field_phone_contact' => '',
  'field_email_contact' => '',
  'field_website' => '',
  'field_location' => '',
  'field_contributor' => 'Wes Modes',
  'field_notes' => '',
  'field_image' => 
  array (
    0 => '/srv/data/web/vhosts/unavoidabledisaster.com/htdocs/wp-content/uploads/wpcf7_uploads/0318808318/left-boob.jpg',
  ),
  'mc4wp_checkbox' => 'No',
)

For $uploadedFiles we get:

array (
  'field_image' => 
  array (
  ),
)

So while the file array seems to be available within the posted data, it isn’t available from the very function designed to get it.

What does this mean?

SOLUTION

So there were two problems actually:

  1. As @howard_e suggests the developer of CF7 changed the upload field to an array (probably to allow for multiple files to be uploaded). This broke existing code.
  2. The WPCF7_Submission::get_instance()->uploaded_files() method stopped returning the uploaded files. Though they are not returned within the upload field object of WPCF7_Submission::get_instance()

So here is the revised relevant parts of the function:

add_action('wpcf7_before_send_mail', 'save_my_form_data_to_my_cpt');
function save_my_form_data_to_my_cpt($contact_form){
    //Get the form ID
    $contact_form_id = $contact_form->id;

    $submission = WPCF7_Submission::get_instance();
    if (!$submission){
        return; // exit the hook
    }
    // get posted data
    $posted_data = $submission->get_posted_data();
    // get file upload info from form
    $uploadedFiles = $posted_data['field_image'];

    // create new post array
    $new_post = array();
    //
    // META META FIELDS
    // post_type (i.e., your CPT)
    $new_post['post_type'] = 'thing';
    // post_status (draft, publish, pending)
    $new_post['post_status'] = 'draft';
    //
    // POST FIELDS
    // post_title
    if(isset($posted_data['field_title']) &&
            !empty($posted_data['field_title'])){
        $new_post['post_title'] = $posted_data['field_title'];
    } else {
        $new_post['post_title'] = '[Insert Title Here]';
    }
    // POST CPT
    //When everything is prepared, insert the post into WP Database
    if($post_id = wp_insert_post($new_post)){
        // it worked so let's continue...
        // 
        // if we have an uploaded image...
        if (!empty($uploadedFiles)) {
            // move image from temp folder to upload folder
            $file = file_get_contents($uploadedFiles[0]);
            $image_name = basename($uploadedFiles[0]);
            $imageUpload = wp_upload_bits(basename($uploadedFiles[0]), null, $file);
            require_once(ABSPATH . 'wp-admin/includes/admin.php');
            // construct array to register this image
            $filename = $imageUpload['file'];
            $attachment = array(
                'post_mime_type' => $imageUpload['type'],
                'post_parent' => $post_id,
                'post_title' => $posted_data['field_title'] . ' - ' .
                                $posted_data['field_contributor'],
                'post_content' => $posted_data['field_info'],
                'post_status' => 'inherit'
            );
            // attach image to this post
            $attachment_id = wp_insert_attachment( $attachment, $filename, $post_id );
            // if we succeeded...
            if (!is_wp_error($attachment_id)) {
                require_once(ABSPATH . 'wp-admin/includes/image.php');
                $attachment_data = wp_generate_attachment_metadata( $attachment_id, $filename );
                wp_update_attachment_metadata( $attachment_id,  $attachment_data );
                set_post_thumbnail( $post_id, $attachment_id );
                // add image id (attchment id) to ad_image field
                update_field( 'ad_image', $attachment_id, $post_id );
            }
        }
    }
}

2

Answers


  1. Most likely, this issue is the same one I’ve faced. It appears that the Developer of CF7 decided it was better to make $uploaded_files['something'] into an array. Which probably breaks anyone’s plugin that taps into this feature. Not the first time he’s changed from a string to an array.

    Anyway, this may solve it for you.

    Changing this:

    file_get_contents($uploadedFiles['field_image'])
    

    to this:

    file_get_contents($uploadedFiles['field_image'][0]);
    

    After reviewing the complete function I came up with this:

    add_action('wpcf7_before_send_mail', 'save_my_form_data_to_my_cpt');
    function save_my_form_data_to_my_cpt($contact_form) {
        //Get the form ID
        // $contact_form object is the first parameter
        $contact_form_id = $contact_form->id;
    
        $submission = WPCF7_Submission::get_instance();
        if (!$submission) {
            // you don't have to return the form, this is a hook not a filter
            //return $contact_form;
            return; // exit the hook
        }
        $posted_data = $submission->get_posted_data();
        $uploadedFiles = $submission->uploaded_files();
        // if we have an uploaded image...
        if (!empty($uploadedFiles)) {
            // move image from temp folder to upload folder
            $file = file_get_contents($uploadedFiles['field_image'][0]);
            $image_name = basename($uploadedFiles['field_image'][0]);
            $imageUpload = wp_upload_bits(basename($uploadedFiles['field_image'][0]), null, $file);
            //
            require_once(ABSPATH . 'wp-admin/includes/admin.php');
            // construct array to register this image
            $filename = $imageUpload['file'];
            $attachment = array(
                'post_mime_type' => $imageUpload['type'],
                'post_parent' => $post_id,
                'post_title' => $posted_data['field_title'] . ' - ' .
                    $posted_data['field_contributor'],
                'post_content' => $posted_data['field_info'],
                'post_status' => 'inherit'
            );
            // attach image to this post
            $attachment_id = wp_insert_attachment($attachment, $filename, $post_id);
            if (!is_wp_error($attachment_id)) {
                require_once(ABSPATH . 'wp-admin/includes/image.php');
                $attachment_data = wp_generate_attachment_metadata($attachment_id, $filename);
                // PC::debug("attachment_data:", print_r($attachment_data, True));
                wp_update_attachment_metadata($attachment_id, $attachment_data);
                set_post_thumbnail($post_id, $attachment_id);
                // add image id (attchment id) to ad_image field
                update_field('ad_image', $attachment_id, $post_id);
            }
        }
    }
    

    This above is tested, and does work. I removed the extra checks from fields I didn’t put in my test environment. However – one note – $post_id is undefined. If you are using the parent post of the form page, you want to use

    $post_id = $submission->get_meta('container_post_id');
    
    Login or Signup to reply.
  2. Can you test with a well placed pause (or cause a php fatal error) to see if at any point the image is grabbed/saved properly?

    If so you could circumvent your issue by moving it to the right folder using an additional/alternate method (precisely after it’s properly saved/grabbed/handled).
    Take in consideration the image is sent out properly within an email, so I’m certain you can have it saved in the media folder at some point during this php script/page

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search