Wordpress 无需插件即可将包含多个文件的表单发送到电子邮件

Wordpress send form with multiple files to email without plugin

目的是让用户将自己的material新文章(文本和文件)发送到管理员的邮箱。

有一个表格:

<form class="form form-send" enctype="multipart/form-data">
    <div class="send__inputs-block">
        <div class="sliding-label__block send__textarea-block">
            <textarea name="comment" id="comment" class="input textarea send__textarea" placeholder=" "></textarea>
            <label for="comment" class="text text--fz-18 sliding-label">
                <?php echo get_post_meta( get_the_ID(), 'joint_send_comment_text', true ); ?>
            </label>
        </div>
        <div class="sliding-label__block">
            <input id="name" type="text" name="name" class="input input-text" placeholder=" ">
            <label for="name" class="text text--fz-18 sliding-label">
                <?php echo get_post_meta( get_the_ID(), 'joint_send_name_text', true ); ?>
            </label>
        </div>
    </div>
    <div class="send__file-block">
        <input id="file" type="file" name="file" class="input-file" multiple>
        <label for="file" class="label label-file">
            <i class="joint-upload icon"></i>
            <span class="text text--fz-14 upload__text">
                <?php echo get_post_meta( get_the_ID(), 'joint_send_file_text', true ); ?>
            </span>
        </label>
    </div>
    <button type="submit" class="button form-button">
        <span class="button-text">
            <?php echo get_post_meta( get_the_ID(), 'joint_send_submit_text', true ); ?>
        </span>
    </button>
</form>

这是JS代码:

function formSend(e, form) {
    e.preventDefault()

    if (formValidate(form)) return

    let backFile = jointAjax.ajaxurl
    let curPage = ''

    let formData = new FormData(form)

    if (form.classList.contains('form-contacts')) {
       curPage = 'contacts'
    }
    else if (form.classList.contains('form-send')){
        curPage = 'send'
        let uploadFiles = []
        for (let single of form.file.files) {
            uploadFiles.push(single)
        }
        console.log(uploadFiles[0])
        formData.append('file', uploadFiles)
    }
    else {
        return
    }

    formData.append('action', curPage)

    fetch(backFile, {
       method: 'POST',
       body: formData,
    })
        .then(form.reset())
        .catch(error => {
            error.json().then(response => {
               alert(response.message)
            })
        })
}

这是 PHP 代码:

add_action('wp_ajax_send', 'joint_send_send_form');
add_action('wp_ajax_nopriv_send', 'joint_send_send_form');
function joint_send_send_form() {
    global $joint_settings;

    $data = json_encode($_POST);
    $data = json_decode($data, true);

    $attachment = array();
    if (isset($_FILES['file'])) {
        foreach($_FILES['file'] as $key => $file) {
            $attachment[] = $file['tmp_name'] . $file['name'];
        }
    }

    $mailBody = '';

    foreach ($data as $key => $value) {
        if ($key === 'action' || $key === 'file') continue;
        if (!empty($data[$key]))
            $mailBody .= '<p><strong>' . ucfirst($key) . ':</strong> ' . esc_html($value) . '</p>';
    }

    $headers = array(
        'From: Joint Admin <' . SMTP_FROM . '>',
        'content-type: text/html'
    );

    wp_mail(
        $joint_settings['send_mail_to'],
        $joint_settings['send_mail_theme'],
        $mailBody,
        $headers,
        WP_CONTENT_DIR . '\' . $_FILES['file']['name']
    );

    // wp_send_json_success($_FILES['file']['tmp_name'] . '\' . $_FILES['file']['name']);

}

我已经查看了各种论坛、文章和视频,但我似乎无法完成任务。

在wp_mail中我们必须传递文件的完整路径,但是我们从哪里得到那个路径呢? 而且无论我如何尝试处理多个文件,函数 returns 仅回复最后一个文件的名称。

SMTP 设置正确。收到电子邮件,但没有文件。

请帮忙 - 我不知道该怎么办了。

我明白了 - 我查看了 Contact form 7 插件中的实现并理解了其中的原理。

基本思路是先将上传的文件移动到网站的内部目录,然后从那里发送到邮箱。

JS中我只改变了一件事(你可以发送文件到请求而不处理):

else if (form.classList.contains('form-send')){
    formData.append('file', form.file.files)
    curPage = 'send'
}

我的处理函数看起来像这样:

add_action('wp_ajax_send', 'joint_send_send_form');
add_action('wp_ajax_nopriv_send', 'joint_send_send_form');
function joint_send_send_form() {
    global $joint_settings;

    $data = json_encode($_POST);
    $data = json_decode($data, true);

    $mailBody = '';

    foreach ($data as $key => $value) {
        if ($key === 'action' || $key === 'file') continue;
        if (!empty($data[$key]))
            $mailBody .= '<p><strong>' . ucfirst($key) . ':</strong> ' . esc_html($value) . '</p>';
    }

    $headers = array(
        'From: Joint Admin <' . SMTP_FROM . '>',
        'content-type: text/html'
    );

    $file = $_FILES['file'];
    // joint_array_flatten() - converts multi-dimensional array to a flat array
    $names = joint_array_flatten( $file['name'] );
    $tmp_names = joint_array_flatten( $file['tmp_name'] );

    $uploads = wp_get_upload_dir()['basedir'];
    $uploads_dir = path_join( $uploads, 'joint_uploads' );

    $uploaded_files = array();

    foreach ( $names as $key => $filename ) {
        $tmp_name = $tmp_names[$key];

        if ( empty( $tmp_name ) or ! is_uploaded_file( $tmp_name ) ) {
            continue;
        }

        // joint_antiscript_file_name() - converts a file name to one that is not executable as a script
        $filename = joint_antiscript_file_name( $filename );

        $filename = wp_unique_filename( $uploads_dir, $filename );
        $new_file = path_join( $uploads_dir, $filename );

        if ( false === @move_uploaded_file( $tmp_name, $new_file ) ) {
            wp_send_json_error( json_encode( array('message' => 'Upload error') ) );
            return;
        }

        // Make sure the uploaded file is only readable for the owner process
        chmod( $new_file, 0400 );

        $uploaded_files[] = $new_file;
    }

    wp_mail(
        $joint_settings['send_mail_to'],
        $joint_settings['send_mail_theme'],
        $mailBody,
        $headers,
        $uploaded_files
    );

    // Deletes sent files as they are on the email
    foreach ( $uploaded_files as $filepath ) {
        wp_delete_file( $filepath );
    }
}

我从 Contact form 7 中窃取了几个功能。反脚本绝对有用,但是否需要 joint_array_flatten - 我不知道,但我已经累得想不起来了更多

最后我从目录中删除了下载的文件,这样它就不会被阻塞。

此外,正如用户@TangentiallyPerpendicular 正确指出的那样,您需要将 [] 添加到 file-input 名称才能发送多个文件:

<input id="file" type="file" name="file[]" class="input-file" multiple>

否则,就是这样。我希望有一天这会帮助其他人,他们不必像我一样为类似的任务而苦恼)