Я продолжаю получать 400 (неверный запрос) при отправке формы WordPress с использованием Fetch API

#javascript #jquery #ajax #wordpress #fetch

#javascript #jquery #ajax #wordpress #выборка

Вопрос:

Я работаю над сайтом WordPress и пытаюсь преобразовать свой код jQuery в ванильный JavaScript (в основном для обучения, но также и для того, чтобы мне не приходилось полагаться на jQuery). Цель состоит в том, чтобы после отправки формы вместо перехода на страницу благодарности или что-то еще просто отобразить наложение поверх формы с надписью «Спасибо за ваше сообщение». Опять же, все отлично работает с jQuery / AJAX, но я хочу попробовать заставить его работать и с обычным JavaScript.

Вот рабочий код jQuery:

   jQuery('#myContactForm').on('submit', function () {
    var formData = jQuery(this).serializeArray();

    formData.push({ 
      name: 'security', 
      value: ajaxNonce 
    });

    jQuery.ajax({
      type: 'POST',
      url: ajaxUrl,
      data: formData
    });

    jQuery('.form-overlay').addClass('visible');

    return false;
  });
 

И вот рабочий код из functions.php:

 <?php 

function javascript_variables() { ?>
  <script type="text/javascript">
    var ajaxUrl = '<?php echo admin_url('admin-ajax.php'); ?>';
    var ajaxNonce = '<?php echo wp_create_nonce('secure_nonce_name'); ?>';
  </script>
  <?php
}
add_action('wp_head', 'javascript_variables');


add_action('wp_ajax_send_form', 'send_form');
add_action('wp_ajax_nopriv_send_form', 'send_form');
 
function send_form() {
  check_ajax_referer('secure_nonce_name', 'security');
 
  $to = 'myemailaddressgoeshere@gmail.com';

  $subject = $_POST['subject'];
  
  $body  = 'From: ' . $_POST['full_name'] . '<br />';
  $body .= 'Email: ' . $_POST['email'] . '<br />';
  $body .= 'Phone: ' . $_POST['phone'] . '<br />';
  $body .= 'Message: ' . $_POST['message'] . '<br />';

  $headers = array('Content-Type: text/html; charset=UTF-8');
    
  wp_mail($to, $subject, $body, $headers);

  wp_die();
}
 

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

 <input class="form-inputs" type="hidden" name="action" value="send_form" />
 

Вот что я придумал, пытаясь использовать Fetch API вместо jQuery:

 // handle form submission
const formSubmissionHandler = () => {
  const form = document.getElementById('myContactForm');
  const formOverlay = document.querySelector('.form-overlay');
  const formInputs = Array.from(document.querySelectorAll('.form-inputs'));
  const formData = [];

  form.addEventListener('submit', (e) => {
    e.preventDefault();

    formInputs.forEach((input) => {
      if (!input.name || !input.value) {
        return;
      }

      formData.push({
        name: input.name,
        value: input.value,
      });
    });

    formData.push({
      name: 'security',
      value: ajaxNonce,
    });

    const fetchOptions = {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(formData),
    };

    // send post request
    fetch(ajaxUrl, fetchOptions)
      .then((res) => res.json())
      .then((res) => console.log(res))
      .catch((err) => console.error(err));

    formOverlay.classList.add('visible');
  });
};
document.addEventListener('DOMContentLoaded', formSubmissionHandler);
 

Я наткнулся на FormData() конструктор из поиска, не уверен, где / буду ли я использовать его здесь?

И вот что я написал в своем functions.php файл:

 function send_form() {
  check_ajax_referer('secure_nonce_name', 'security');
 
  $to = 'myemailaddressgoeshere@gmail.com';

  $subject = $_POST['subject'];

  $json_input = json_decode(file_get_contents('php://input'), true);

  $body = '';
  
  foreach ($json_input as $key => $value) {
    $body  = 'From: ' . $value['full_name'] . '<br />';
    $body .= 'Email: ' . $value['email'] . '<br />';
    $body .= 'Phone: ' . $value['phone'] . '<br />';
    $body .= 'Message: ' . $value['message'] . '<br />';
  }

  $headers = array('Content-Type: text/html; charset=UTF-8');
    
  wp_mail($to, $subject, $body, $headers);

  wp_die();
}
 

Я новичок во всем этом, поэтому, если бы кто-нибудь мог мне помочь, я был бы очень признателен. Я думаю, что моя проблема в том, как я анализирую данные JSON в functions.php . Или я мог просто не форматировать данные так же в vanilla JS, как это делается в jQuery? Спасибо!

Комментарии:

1. Подлинный вопрос из любопытства: почему вы используете CSS, чтобы «скрыть» ваше уже скрытое action поле ввода?

2. Также обратите внимание, что formInputs (в вашем ванильном JS-коде) запрашивается только для элементов с class form-inputs . Это не учитывает ваше скрытое action поле, верно? Ваша версия jQuery заполняет все поля.

3. @cabrerahector Я забыл включить имя класса form-inputs в скрытый ввод, когда вставлял код. С тех пор я обновил его. А для CSS на скрытом вводе, tbh, я не уверен, ха-ха. Я получил большую часть кода из других статей / руководств, поэтому я этого не заметил. С тех пор я удалил его.

4. не могли бы вы console.log(ajaxUrl) раньше fetch(ajaxUrl, fetchOptions) и сообщить мне, получили ли вы правильный URL? Один из 400 триггеров ошибок при неправильном запросе — неверный URL.

5. @parse console.log(ajaxUrl) , когда я получаю http://www.domainnamehere.ca/wp-admin/admin-ajax.php

Ответ №1:

Я знаю, что мне, вероятно, немного поздно публиковать это, но если кто-то в будущем столкнется с этим, вот в чем дело:

 const fetchOptions = {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify(formData),
};
 

здесь вы создаете строку json для передачи целевому URL-адресу, но вы должны помнить, что синтаксический анализатор ajax WordPress не может понимать данные, отправляемые ему в виде необработанного json.

 $json_input = json_decode(file_get_contents('php://input'), true);
 

здесь вы превращаете необработанные входные данные, которые вы получили, в массив, но до этого все, что получил WordPress, было частью данных, которая представляет собой простую строку. Таким образом, он не знает, как с этим бороться и какие пользовательские хук и действия должны быть запущены для проверки этого.

 add_action('wp_ajax_send_form', 'send_form');
add_action('wp_ajax_nopriv_send_form', 'send_form');
 

здесь вы сообщаете wordpress ожидать некоторый запрос с именем действия ‘send_form’, и если вы его получили, передайте его в функцию с именем ‘send_form’. Однако WordPress не получает этот запрос с именем «действие». Отсюда и ошибка.

Однако исправление довольно простое, просто добавьте это имя запроса в качестве GET к URL, на который вы отправляете необработанные данные, и очистите его для wordpress:

 var ajaxUrl = '<?php echo admin_url('admin-ajax.php'); ?>?action=send_for';
 

или версия, которую я предпочитаю:

 // send post request
fetch(ajaxUrl   '?action=send_form', fetchOptions)
  .then((res) => res.json())
  .then((res) => console.log(res))
  .catch((err) => console.error(err));
 

и готово!
Я думаю, что как только вы начнете работать с fetch () и WP, по крайней мере, на данный момент (пока WordPress не найдет способ), это может пригодиться.