Как обрабатывать загруженные изображения в новой версии 5.4 контактной формы 7? [РЕШЕНИЕ]

Я использую контактную форму 7 (5.4) и расширение CF7 Smart Grid Design Extension (4.10.0) в форме отправки на моем сайте WordPress для создания черновиков пользовательских типов сообщений. Первоначальным источником вдохновения для этого послужил этот потрясающий пост SO.

Форма отправки работала хорошо и надежно уже более года, но с новой версией CF7 5.4 что-то изменилось внутри, и загрузка изображений прервалась. Все остальные поля остались без изменений.

Поле CF7, с которым я загружаю, выглядит как

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

Изображения отправляются по почте, поэтому форма загружает файл правильно. Но что-то изменилось, что мешает моим попыткам получить изображения до того, как они будут удалены после отправки по электронной почте.

Вот соответствующий PHP в functions.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.

Хотя проблема может заключаться в коде отправки сообщения, который обрабатывает отправку, ничего из этого не изменилось за год. Изменился только 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 (
  ),
)

Таким образом, хотя массив файлов кажется доступным в опубликованных данных, он недоступен из самой функции, предназначенной для его получения.

Что это значит?

РЕШЕНИЕ

Итак, на самом деле было две проблемы:

  1. Как предполагает @howard_e, разработчик CF7 изменил поле загрузки на массив (вероятно, чтобы разрешить загрузку нескольких файлов). Это сломало существующий код.
  2. Метод WPCF7_Submission::get_instance()->uploaded_files() перестал возвращать загруженные файлы. Хотя они не возвращаются в объекте поля загрузки WPCF7_Submission::get_instance()

Итак, вот пересмотренные соответствующие части функции:

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

person Wes Modes    schedule 03.04.2021    source источник
comment
Можете ли вы опубликовать всю функцию save_my_form_data_to_my_cpt?   -  person Howard E    schedule 03.04.2021
comment
Хорошо, готово. Размещено в приложении.   -  person Wes Modes    schedule 03.04.2021
comment
Извините, что заставил вас опубликовать этот дополнительный материал. Я думаю, что решение - это то, что я опубликовал. Я только что нашел ту же проблему на сайте, на котором я использовал эту же функцию, и, по-видимому, около 50 неудачных загрузок.   -  person Howard E    schedule 03.04.2021
comment
Итак, должен ли $post_id быть родительским постом формы? Кажется, что это не определено.   -  person Howard E    schedule 04.04.2021


Ответы (2)


Скорее всего, это та же проблема, с которой я столкнулся. Похоже, что разработчик 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_id = $submission->get_meta('container_post_id');
person Howard E    schedule 03.04.2021
comment
Пытаюсь прямо сейчас. Возможно, вы захотите добавить соответствующий парен в конце. - person Wes Modes; 04.04.2021
comment
Но, к сожалению, пока нет. Изображение по-прежнему не отображается в моей медиатеке. Хм... - person Wes Modes; 04.04.2021
comment
Так много проблем с WP можно было бы избежать, если бы был простой способ записи в консоль. - person Wes Modes; 04.04.2021
comment
gist.github.com/DuckDivers/ . Это поможет вам вывести переменные в журнал ошибок. - person Howard E; 04.04.2021
comment
Я обновил ответ. - person Howard E; 04.04.2021
comment
Что касается вашего последнего комментария, у меня где-то посередине есть код, который устанавливает $post_id = wp_insert_post($new_post), поскольку он создает новый пост и добавляет все его данные и метаданные. - person Wes Modes; 04.04.2021
comment
Он все еще не работал у меня после тщательной проверки моего кода на ваш, поэтому я наконец установил плагин (BugFu), позволяющий мне выводить сложные данные на консоль. Я обнаружил странный сюрприз. Проверьте Приложение B моего исходного поста. - person Wes Modes; 04.04.2021
comment
Итак, вы были совершенно правы насчет массива И $submission->uploaded_files() возвращал пустой массив. Поэтому я установил $uploadedFiles = $posted_data['field_image']; и удалил ссылку на ключ из вложенной части функции, и это сработало. См. Решение в OP. - person Wes Modes; 04.04.2021
comment
@WesModes Итак... еще один способ сбросить данные (если вам интересно) — использовать Kint Debugger (который я обновил для PHP 7.4) — github.com/DuckDivers/kint-debugger — тогда вы можете использовать d($var_name) — и использовать add_filter('wpcf7_load_js', '__return_false'); в файле functions.php, чтобы перезагрузить страницу при отправке вместо обработчика ajax. Тогда все ваши сброшенные переменные/объекты и т. д. находятся в отладочной информации от Kint после отправки. - person Howard E; 04.04.2021
comment
Блестящий. Я попробую это в следующий раз, когда у меня возникнет неразрешимая проблема. - person Wes Modes; 04.04.2021
comment
Спасибо за помощь. Не уверен, что я бы легко обнаружил, что строка была преобразована в массив. - person Wes Modes; 04.04.2021

Можете ли вы протестировать с хорошо поставленной паузой (или вызвать фатальную ошибку php), чтобы увидеть, правильно ли в какой-то момент изображение захвачено/сохранено?

Если это так, вы можете обойти свою проблему, переместив ее в нужную папку, используя дополнительный/альтернативный метод (именно после того, как она будет правильно сохранена/захвачена/обработана). Примите во внимание, что изображение правильно отправлено по электронной почте, поэтому я уверен, что вы можете сохранить его в папке мультимедиа в какой-то момент во время этого php-скрипта/страницы.

person Community    schedule 03.04.2021
comment
Я полностью согласен. Он определенно получает изображение, потому что электронная почта получает его, но не сохраняет. Я подозреваю, что он не захватывает его из временной папки должным образом. - person Wes Modes; 04.04.2021