Не удается заставить wp_redirect() работать после добавления пользовательского типа записи через фронтенд.

Вопрос или проблема

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

У меня возникли серьезные проблемы с ‘headers already sent’ при попытке заставить работать wp_redirect() после создания нового клиента пользователем.

Вот пример того, что я хочу сделать:

  • /new-customer.php : Создать новый Пользовательский Тип Записи через фронтенд и затем перенаправить на страницу одного поста этого клиента. Вот код:

        <?php
            $address_line_1      = $_POST['address_line_1'];
            $address_line_2      = $_POST['address_line_2'];
            $suburb              = $_POST['suburb'];
            $state               = $_POST['state'];
            $post_code           = $_POST['post_code'];
            $country             = $_POST['country'];
            $email               = $_POST['email'];
            $first_name          = $_POST['first_name'];
            $last_name           = $_POST['last_name'];
            $phone_number        = $_POST['phone_number'];
            $progress_identifier="1";
    
                // ОБРАБОТКA ФОРМЫ
                if ('POST' == $_SERVER['REQUEST_METHOD'] && !empty($_POST['action']) && $_POST['action'] == "new_customer")
                {
    
                    $new_customer = array(
                        'post_title'  => wp_rand(100,999).'-'.wp_rand(),
                        'post_author' => $user_ID,
                        'post_status' => 'publish',
                        'post_type'   => 'customer'
                    );
    
                    $pid = wp_insert_post($new_customer);
    
                    add_post_meta($pid, 'address_line_1',      $address_line_1,      true);
                    add_post_meta($pid, 'address_line_2',      $address_line_2,      true);
                    add_post_meta($pid, 'suburb',              $suburb,              true);
                    add_post_meta($pid, 'state',               $state,               true);
                    add_post_meta($pid, 'post_code',           $post_code,           true);
                    add_post_meta($pid, 'country',             $country,             true);
                    add_post_meta($pid, 'email',               $email,               true);
                    add_post_meta($pid, 'first_name',          $first_name,          true);
                    add_post_meta($pid, 'last_name',           $last_name,           true);
                    add_post_meta($pid, 'phone_number',        $phone_number,        true);
                    add_post_meta($pid, 'address',             $address,             true);
                    add_post_meta($pid, 'progress_identifier', $progress_identifier, true);
    
                    $survey_post = array(
                        'post_title' => $pid . '-' . wp_rand(),
                        'post_author' => $user_ID,
                        'post_status' => 'publish',
                        'post_type' => 'survey'
                    );
    
                    $survey_id = wp_insert_post($survey_post);
    
                    global $wpdb;
                    $wpdb->insert(
                        $wpdb->p2p,
                        array(
                            'p2p_from' => $survey_id,
                            'p2p_to' => $pid,
                            'p2p_type' => 'survey_to_customer'
                        )
                    );
                    wp_redirect(home_url());
                    exit();
                }
        ?>
    

Этот код размещен после HTML-формы.

Я знаю, что wp_redirect() должно вызываться до того, как на страницу будет выведено что-либо, но я не уверен, как это сделать, потому что я пытался разместить его выше на странице, но это ни к чему не привело.

Не стесняйтесь критиковать меня за плохой код и неопределённый вопрос, но если вы можете направить меня в правильном направлении, чтобы достичь того, что я пытаюсь сделать, это было бы замечательно! Я пытался разбить все на функции, чтобы вызывать их через хук ‘save_post’, но и с этим не повезло.

Спасибо за внимание!

Вам следует оставить форму на new-customer.php и установить действие формы на POST к другому скрипту (что-то вроде new-customer-process.php), затем вставьте свой PHP-код в этот скрипт. По сути, пользователь не заметит разницы, так как его перенаправят обратно на главную страницу.

Чтобы дать вам больше информации, форма отправляет заголовки, и поэтому вам нужно разделить форму и скрипт обработки. Перенаправление должно происходить ДО того, как будет отправлен какой-либо HTML.

Вы должны вызвать

exit;

после wp_redirect и вам следует сохранить данные поста в хуке pre_get_posts.

Я бы посоветовал вам посмотреть на AJAX-вызовы WordPress.

Вы можете добавить ваш AJAX так:

add_action( 'wp_ajax_{nopriv_}new_customer', 'my_function_to_hendle_ajax' );

где {nopriv_} предназначен для пользователей, не вошедших в систему

и ваша функция будет выглядеть так:

function my_function_to_hendle_ajax() {
$address_line_1      = $_POST['address_line_1'];
$address_line_2      = $_POST['address_line_2'];
$suburb              = $_POST['suburb'];
$state               = $_POST['state'];
//....
// нет необходимости в if( 'post' .... )
$new_customer = array(
  'post_title'  => wp_rand(100,999).'-'.wp_rand(),
  'post_author' => $user_ID,
  'post_status' => 'publish',
  'post_type'   => 'customer'
);

$pid = wp_insert_post($new_customer);

add_post_meta($pid, 'address_line_1',      $address_line_1,      true);
add_post_meta($pid, 'address_line_2',      $address_line_2,      true);
// ....
wp_redirect(home_url());
exit();
}

А ваша HTML-форма должна быть:

<form action="<?php echo admin_url( 'admin-ajax.php' ); ?>" method="POST">
<input type="hidden" name="action" value="new_customer" />
...
</form>

Кроме того, вы можете вернуть с помощью функции wp_send_json_error ошибку, чтобы обработать ее в jQuery (но в этом случае вам нужно использовать $.ajax или $.post) при отправке формы.

Проверьте документацию о WordPress Ajax. Надеюсь, это поможет вам.

Ответ или решение

Конечно! Понимание работы функции wp_redirect() в WordPress очень важно, особенно когда вы работаете с пользовательскими постами (CPT) и формами на фронтенде. Основная проблема, с которой вы столкнулись, заключается в ошибке "headers already sent", которая возникает, когда вы пытаетесь отправить заголовки HTTP после того, как уже был выполнен вывод HTML-контента.

Решение проблемы с wp_redirect()

Чтобы обойти эту проблему, мы можем использовать AJAX для обработки вашей формы без необходимости перезагружать страницу и избегания ситуации с заголовками. Давайте поймём, как это сделать шаг за шагом.

  1. Создайте AJAX действие в WordPress

Вам нужно зарегистрировать новый AJAX обработчик в functions.php вашей темы. Это можно сделать следующим образом:

add_action('wp_ajax_new_customer', 'my_function_to_handle_ajax');
add_action('wp_ajax_nopriv_new_customer', 'my_function_to_handle_ajax');

function my_function_to_handle_ajax() {

    // Ваша логика обработки формы
    if (isset($_POST['address_line_1']) && !empty($_POST['action']) && $_POST['action'] == "new_customer") {
        $user_ID = get_current_user_id(); // Получаем ID текущего пользователя
        $address_line_1 = sanitize_text_field($_POST['address_line_1']);
        $address_line_2 = sanitize_text_field($_POST['address_line_2']);
        $suburb = sanitize_text_field($_POST['suburb']);
        $state = sanitize_text_field($_POST['state']);
        $post_code = sanitize_text_field($_POST['post_code']);
        $country = sanitize_text_field($_POST['country']);
        $email = sanitize_email($_POST['email']);
        $first_name = sanitize_text_field($_POST['first_name']);
        $last_name = sanitize_text_field($_POST['last_name']);
        $phone_number = sanitize_text_field($_POST['phone_number']);

        // Создание нового заказчика
        $new_customer = array(
            'post_title' => wp_rand(100, 999) . '-' . wp_rand(),
            'post_author' => $user_ID,
            'post_status' => 'publish',
            'post_type' => 'customer'
        );

        $pid = wp_insert_post($new_customer);

        // Добавление метаданных
        add_post_meta($pid, 'address_line_1', $address_line_1, true);
        add_post_meta($pid, 'address_line_2', $address_line_2, true);
        add_post_meta($pid, 'suburb', $suburb, true);
        add_post_meta($pid, 'state', $state, true);
        add_post_meta($pid, 'post_code', $post_code, true);
        add_post_meta($pid, 'country', $country, true);
        add_post_meta($pid, 'email', $email, true);
        add_post_meta($pid, 'first_name', $first_name, true);
        add_post_meta($pid, 'last_name', $last_name, true);
        add_post_meta($pid, 'phone_number', $phone_number, true);

        // Ссылка для перенаправления
        $redirect_url = get_permalink($pid); // Получение URL для перенаправления

        // Отправка ответа с перенаправлением
        wp_send_json_success(array('redirect' => $redirect_url));
    } else {
        wp_send_json_error('Invalid request');
    }
}
  1. Измените вашу HTML-форму для использования AJAX

Вместо отправки данных формы через стандартный метод POST, давайте используем AJAX. Ваш код формы может выглядеть следующим образом:

<form id="new-customer-form" method="post">
    <input type="text" name="address_line_1" required />
    <input type="text" name="address_line_2" required />
    <input type="text" name="suburb" required />
    <input type="text" name="state" required />
    <input type="text" name="post_code" required />
    <input type="text" name="country" required />
    <input type="email" name="email" required />
    <input type="text" name="first_name" required />
    <input type="text" name="last_name" required />
    <input type="text" name="phone_number" required />
    <input type="hidden" name="action" value="new_customer" />
    <button type="submit">Создать клиента</button>
</form>
  1. Добавьте JavaScript для обработки отправки формы

Теперь добавим JavaScript, который будет перехватывать отправку формы и отправлять данные с помощью AJAX:

jQuery(document).ready(function($) {
    $('#new-customer-form').on('submit', function(e) {
        e.preventDefault(); // предотвращаем стандартную отправку формы

        $.ajax({
            url: '<?php echo admin_url('admin-ajax.php'); ?>',
            type: 'POST',
            data: $(this).serialize(),  // сериализуем данные формы
            success: function(response) {
                if (response.success) {
                    window.location.href = response.data.redirect; // перенаправление
                } else {
                    alert('Произошла ошибка: ' + response.data); // обработка ошибки
                }
            },
            error: function(xhr, status, error) {
                alert('Ошибка: ' + error); // обработка ошибок AJAX
            }
        });
    });
});

Заключение

Таким образом, мы избегаем проблемы с заголовками, обрабатывая отправку формы с помощью AJAX. Это позволяет вам перенаправлять пользователей на нужную страницу после успешного создания нового клиента, не сталкиваясь с ошибками, связанными с выводом данных на экран до вызова wp_redirect(). Убедитесь, что ваш JavaScript подключен корректно, и ваша форма работает как нужно. Надеюсь, это поможет вам в разработке вашего приложения на базе WordPress!

Оцените материал
Добавить комментарий

Капча загружается...