Contact Form 7 5.4新版本如何处理上传图片? [解决方案]

How to process uploaded images in new 5.4 version of Contact Form 7? [SOLUTION]

我在我的 WordPress 网站上的提交表单中使用 Contact Form 7 (5.4) 和 CF7 Smart Grid Design Extension (4.10.0) 来构建自定义 Post 类型草案。最初的灵感是这个 awesome SO post.

一年多来,提交表单一直运行良好且可靠,但在新的 CF7 5.4 版本中,内部发生了一些变化,图像上传也出现了问题。所有其他字段都保持不变。

我上传的 CF7 字段显示为

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

图片已邮寄,因此表单正在正确上传文件。但是有些事情发生了变化,这打破了我在通过电子邮件发送后删除图像之前获取图像的尝试。

这是 functions.php 中的相关 PHP,它在构建 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 );
            }
        }
    }
}

调用者:

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

在 CF7 电子邮件中成功发送的图像不会上传到正在创建的新 CPT。

虽然问题可能出在处理提交的 post 提交代码中,但其中的 none 在一年内发生了变化。只有CF7变了。

有什么提示吗?

附录 A:完整函数

这是完整的 save_my_form_data_to_my_cpt 函数:

~已删除~

附录 B:调试输出

在函数的早期,我们调用获取从 CF7 表单传递的数据:

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

当我们将这些变量转储到控制台时,我们大吃一惊。对于 $posted_data,我们得到:

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',
)

对于 $uploadedFiles,我们得到:

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

因此,虽然文件数组似乎在 posted 数据中可用,但无法从旨在获取它的函数中获得。

这是什么意思?

解决方案

所以实际上有两个问题:

  1. 因为@howard_e 建议 CF7 的开发人员将上传字段更改为数组(可能允许上传多个文件)。这破坏了现有代码。
  2. WPCF7_Submission::get_instance()->uploaded_files() 方法停止返回上传的文件。虽然它们不会在 WPCF7_Submission::get_instance()
  3. 的上传字段对象中返回

所以这里是修改后的函数相关部分:

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

这个问题很可能与我遇到的问题相同。 CF7 的开发者似乎决定将 $uploaded_files['something'] 放入数组中会更好。这可能会破坏任何利用此功能的插件。他不是第一次从字符串变成数组了。

无论如何,这可能会为您解决。

改变这个:

file_get_contents($uploadedFiles['field_image'])

对此:

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

在查看完整功能后,我想到了这个:

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

以上内容已经过测试,确实有效。我从没有放在测试环境中的字段中删除了额外的检查。但是 - 一个注释 - $post_id 未定义。如果你正在使用表单页面的父post,你想使用

$post_id = $submission->get_meta('container_post_id');

您能否通过适当的暂停(或导致 php 致命错误)进行测试,以查看图像是否在任何时候 grabbed/saved 正确?

如果是这样,您可以通过使用 additional/alternate 方法将其移动到正确的文件夹来解决您的问题(恰好在正确 saved/grabbed/handled 之后)。 考虑到图像已通过电子邮件正确发送,因此我确定您可以在此期间的某个时候将其保存在媒体文件夹中 php script/page