WordPress как на ладони

Не передаётся корректно action при AJAX.

Не получается сделать ajax-запрос.
Стоит задача сделать калькулятор калорий и индекса массы тела. Расчёты производятся в бэкенде в плагине, фронт js передаёт данные из формы.
HTML:

<form action="bmi" class="calculator__form" id="calcForm" method="POST">
	<input type="text" name="height" class="calculator__input input__height"
						placeholder="Введите ваш рост (см)">
	<input type="text" name="weight" class="calculator__input input__weight"
						placeholder="Введите ваш вес (кг)">
	<input type="text" name="age" class="calculator__input input__age"
						placeholder="Введите ваш возраст">
	<select name="gender" id="" class="calculator__input input__gender">
		<option value="choose">Выберите ваш пол</option>
		<option value="male">Мужчина</option>
		<option value="female">Женщина</option>
	</select>
	<select name="activity" id="" class="calculator__input input__activity">
		<option value="choose">Выберите ваш уровень активности</option>
		<option value="1-to-3">Тренировки 1-3 раза в неделю</option>
		<option value="3-to-5">Тренировки 3-5 дней в неделю</option>
		<option value="sportsman">Спортсмены, тренировки чаще 1 раза в день</option>
	</select>
</form>

JS-код:

'use strict';

let calcForm = document.querySelector('#calcForm');

calcForm.addEventListener('submit', function (e) {
	e.preventDefault();

	let data = {
		'action': 'bmi',
		'height': +document.querySelector('input[name="height"]').value,
		'weight': +document.querySelector('input[name="weight"]').value,
		'age': +document.querySelector('input[name="age"]').value,
		'gender': document.querySelector('select[name="gender"]').value,
		'activity': document.querySelector('select[name="activity"]').value
	}

	let xhr  = new XMLHttpRequest();
	xhr.open('POST', myAjax.ajaxurl, true);
	xhr.responseType = 'json';
	xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8');
	xhr.send(JSON.stringify(data));
	xhr.addEventListener('load', () => {
		console.log(xhr.response);
	});

});

PHP-код в плагине:

<?php
/*
	Plugin Name: bmi
*/
add_action( 'wp_ajax_bmi', 'count_bmi' );
add_action( 'wp_ajax_nopriv_bmi', 'count_bmi' );
add_action( 'wp_enqueue_scripts', 'include_bmi_scripts' );

function count_bmi() {
	$height = $_POST['height'];
	$weight = $_POST['weight'];
	$age = $_POST['age'];
	$gender = $_POST['gender'];
	$activity = $_POST['activity'];
	$bmi = 0;
	$bmr = 0;
	$bmra = 0;
	$message = "";
	$image = "";

	$bmi = $weight / (($height / 100) * ($height / 100));
	if ($gender == 'male') {
		$bmr = 88.36 + (13.4 * $weight) + (4.8 * $height) - (5.7 * $age);
	} else {
		$bmr = 447.6 + (9.2 * $weight) + (3.1 * $height) - (4.3 * $age);
	}

	if ($activity == 'desk') {
		$bmra = $bmr * 1.2;
	} else if ($activity == '1-to-3') {
		$bmra = $bmr * 1.375;
	} else if ($activity == '3-to-5') {
		$bmra = $bmr * 1.55;
	} else if ($activity == '6-to-7') {
		$bmra = $bmr * 1.725;
	} else if ($activity == 'sprotsman') {
		$bmra = $bmr * 1.9;
	} else {
		$bmra = 0;
	}

	$out = array (
		'message' => $message,
		'bmi' => $bmi,
		'bmr' => $bmr,
		'bmra' => $bmra
	);

	header('Content Type: text/json; charset=utf-8');
	echo json_encode($out);
}

function include_bmi_scripts() {
	wp_enqueue_script('bmi-js', plugins_url( 'bmi.js', __FILE__ ), array(), false, true);
	wp_localize_script('bmi-js', 'myAjax', array('ajaxurl'=>admin_url('admin-ajax.php')));
}

JS-скрипт отрабатывает корректно ровно до того момента, как вызывается метод send() у объекта класса XMLHttpRequest.

Если поменять myAjax.ajaxurl на сторонний фейковый api url, то приходят корректные ответы от сервера и возвращаются нужные данные. Но как только дело доходит до отправки запроса в admin-ajax.php, то вылазит 400-я ошибка, а сервер возвращает 0.

Я посмотрел код и знаю, что 0 возвращается в случае некорректного action либо его отсутствия. Но как мне ещё его передать, я ума не приложу. Я пробовал добавлять его в url (myAjax.ajaxurl + '?action=bmi') - не работает; я пробовал передавать не json, а FormData (но у меня почему-то данные туда даже аппендиться не хотели, после всех append оставался пустой объект). И что я только не делал, но результат всё равно один и тот же.

Вопрос: где я косячу? Как мне передать action при помощи чистого js?

P.S. fetch тоже пробовал, не хочет работать. Сделать хочу именно на чистом js, чтобы понимать по шагам, что происходит вообще и не быть завязанным на фреймворки.

Заметки к вопросу:
Uko1ove 19 дней назад

Оставлю на всякий случай ссылку на форум. Задавал там свой вопрос, можно прочитать уже данные мне советы, что я там пробовал и какие были результаты, чтобы не тратить время впустую. А перепробовал реально много чего.
P.S. делаю на виртуальном сервере xampp.
https://www.cyberforum.ru/wordpress/thread2999829.html

0
Andrey
20 дней назад
  • 0
    stepan2143 www.weblancer.net/users/stepanko/?affili...

    Там пример есть

    Для начала отправьте простой запрос:

    let xhr = new XMLHttpRequest();
    let url = myAjax.ajaxurl+ '?action=bmi';
    
    alert( url ); // проверка, а куда отправляем данные?
    
    xhr.open( 'POST', url, true );
    xhr.addEventListener('load', () => {
    	console.log(xhr.response);
    });
    function count_bmi() {
    
    		print_r( $_POST );
    
    	exit;
    	//  ...
    }
    Uko1ove 19 дней назад

    Это не работает. Я пробовал экшн передавать по ссылке - 500 ошибка выскакивает. Урл правильный, отправляет в /wp-admin/admin-ajax.php.

    stepan 18 дней назад

    https://stackoverflow.com/questions/9713058/send-post-data-using-xmlhttprequest
    вот там РАБОЧИЙ пример.

    let xhr = new XMLHttpRequest();
    let url = ajaxurl + '?action=bmi';
    let params = 'orem=ipsum&name=binny';
    
    xhr.open("POST", url, true);
    xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    
    xhr.send(params);
    
    xhr.addEventListener('load', () => {
    	console.log(xhr.response);
    });

    Код проверил локально - и он работает.
    Как получить в таком виде переменную params - уже сами разберетесь.

    ЗАМЕЧУ: если у вас при базовом запросе НЕТ вообще ответа от сервера - значит вы НЕ отправляете туда запрос.
    У меня при неправ передаче данных - в $_POST был пустой массив.
    У вас же - как вы пишите, вообще сервер НЕ отвечает, что есть бредом.
    Значит вы не отправл туда, а именно на admin-ajax.php данные ИЛИ они блокируются кем-то чем-то.
    Базово все работает "с коробки".

    Комментировать
  • 0
    el-lable485 el-lable.ru

    Во-первых вместо

    xhr.send(JSON.stringify(data));

    должно быть

    xhr.send(data);

    Во-вторых вместо

        header('Content Type: text/json; charset=utf-8');
    	echo json_encode($out);

    есть нативный вордпресовский вывод

    wp_send_json($out);
    Uko1ove 19 дней назад

    Пробовал и JSON.stringify, и просто data, и FormData отправлять. Не работает. Пробовал через fetch и jquery отправлять. На сторонних апишках всё ок, отрабатывает корректно, но как только дело касается вордпресса, то он почему-то не видит экшн. Попытка передать его через урл тоже ни к чему не привела.

    Насчёт вордпрессовского родного вывода - не знал. Спасибо. Делал многое по ютубу и гуглу, видел там реализацию, которая у меня сейчас.

    el-lable 19 дней назад

    Вы так и не отписали, вы заменили ли код в обоих местах и что теперь получается?
    Проблема в том что ваш код

        header('Content Type: text/json; charset=utf-8');
    	echo json_encode($out);

    должен иметь третью строчку

    die();
    //wp_die(); // или так

    именно из-за этого у вас 400 с выводом 0

    Uko1ove 18 дней назад

    Всё равно 400-я ошибка. Фишка там даже не в php-коде, почему-то admin-ajax.php просто не видит action. А если ему его передавать насильно ссылкой, то 500-я ошибка вообще вылазит

    el-lable 18 дней назад

    Как вам уже написал уважаемый Stepan, допишите в вашей функции хука в самом начале

    function count_bmi() {
    	echo json_encode( $_POST );
    

    и посмотрите что возвращает в ответе в консоле.

    А в JS допишите здесь после 'use strict'

    'use strict';
    
    alert(myAjax.ajaxurl + ' - ' + window.myAjax.ajaxurl);
    

    Нужно посмотреть все ли там правильно.

    Комментировать
На вопросы могут отвечать только зарегистрированные пользователи. Вход . Регистрация