Создание кастомной формы регистрации в WordPress с REST API

В этой статье создадим продвинутую форму регистрации с:

  • Валидацией данных
  • Условными полями (для врачей)
  • Защитой от злоупотреблений
  • Автоматическим входом после регистрации

Преимущества решения:
✔ Полный контроль над процессом регистрации
✔ Гибкая система проверки данных
✔ Безопасность через nonce и ограничение попыток
✔ Профессиональный пользовательский опыт

Шаг 1: Подготовка HTML-формы

Разместите этот код там, где должна отображаться форма — в шаблоне страницы, виджете или через шорткод:

<form id="custom-register-form">
    <!-- Скрытые поля безопасности -->
    <input type="hidden" name="security" value="<?php echo wp_create_nonce('custom-register-nonce'); ?>">
    
    <!-- Основные поля -->
    <div class="form-group">
        <label for="email">E-mail *</label>
        <input type="email" name="email" id="email" required>
    </div>
    
    <div class="form-group">
        <label for="fullname">ФИО *</label>
        <input type="text" name="fullname" id="fullname" required>
    </div>
    
    <!-- Поля пароля с уникальными ID -->
    <div class="form-group">
        <label for="register_password">Пароль *</label>
        <input type="password" name="password" id="register_password" required minlength="6">
    </div>
    
    <div class="form-group">
        <label for="register_password_repeat">Повторите пароль *</label>
        <input type="password" name="password_repeat" id="register_password_repeat" required>
    </div>
    
    <!-- Выбор типа пользователя -->
    <div class="form-group">
        <label for="user_type">Тип пользователя *</label>
        <select name="user_type" id="user_type" required>
            <option value="">Выберите тип</option>
            <option value="student">Студент</option>
            <option value="doctor">Врач</option>
            <option value="user">Пользователь</option>
        </select>
    </div>
    
    <!-- Условное поле для врачей (изначально скрыто) -->
    <div class="form-group" id="file-upload-group" style="display: none;">
        <label for="doctor_file">Документ, подтверждающий статус врача *</label>
        <input type="file" name="doctor_file" id="doctor_file" accept=".pdf,.doc,.docx,.jpg,.png">
        <p class="file-hint">Формат: PDF, DOC, JPG или PNG (макс. 2MB)</p>
    </div>
    
    <button type="submit">Зарегистрироваться</button>
    
    <!-- Контейнер для сообщений -->
    <div id="register-message" class="message"></div>
</form>

Шаг 2: Добавляем JavaScript логику

Создаем файл js/custom-register.js:

Часть 1: Инициализация и показ полей

window.addEventListener('load', function() {
    const form = document.getElementById('custom-register-form');
    if (!form) return;

    const userTypeSelect = document.getElementById('user_type');
    const fileUploadGroup = document.getElementById('file-upload-group');
    const messageEl = document.getElementById('register-message');

    // Показываем/скрываем поле для файла при изменении типа пользователя
    userTypeSelect.addEventListener('change', function() {
        fileUploadGroup.style.display = this.value === 'doctor' ? 'block' : 'none';
    });
});

Часть 2: Обработка отправки формы

    form.addEventListener('submit', async function(e) {
        e.preventDefault();
        
        // Сброс состояния сообщений
        messageEl.textContent = '';
        messageEl.className = 'message';

        // Получаем значения полей
        const formData = {
            email: form.email.value.trim(),
            fullname: form.fullname.value.trim(),
            password: form.register_password.value.trim(),
            password_repeat: form.register_password_repeat.value.trim(),
            user_type: form.user_type.value,
            security: form.security.value
        };

        // Базовая валидация
        if (!formData.email || !formData.fullname || !formData.password || 
            !formData.password_repeat || !formData.user_type) {
            showMessage('Пожалуйста, заполните все обязательные поля', 'error');
            return;
        }

        if (formData.password !== formData.password_repeat) {
            showMessage('Пароли не совпадают', 'error');
            return;
        }

        if (formData.password.length < 6) {
            showMessage('Пароль должен содержать минимум 6 символов', 'error');
            return;
        }

Часть 3: Специальная валидация для врачей

        // Валидация для врачей
        if (formData.user_type === 'doctor') {
            const fileInput = document.getElementById('doctor_file');
            if (!fileInput.files || fileInput.files.length === 0) {
                showMessage('Необходимо загрузить документ', 'error');
                return;
            }

            const file = fileInput.files[0];
            const validTypes = [
                'application/pdf', 
                'application/msword',
                'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
                'image/jpeg', 
                'image/png'
            ];
            const maxSize = 2 * 1024 * 1024; // 2MB

            if (!validTypes.includes(file.type)) {
                showMessage('Недопустимый формат файла', 'error');
                return;
            }

            if (file.size > maxSize) {
                showMessage('Файл слишком большой (макс. 2MB)', 'error');
                return;
            }
        }

Часть 4: Отправка данных на сервер

        // Подготовка данных для отправки
        const data = new FormData();
        for (const key in formData) {
            data.append(key, formData[key]);
        }

        // Добавляем файл для врачей
        if (formData.user_type === 'doctor') {
            data.append('doctor_file', document.getElementById('doctor_file').files[0]);
        }

        // Отправка данных
        try {
            const response = await fetch(customVars.rest_register_url, {
                method: 'POST',
                headers: {
                    'X-WP-Nonce': customVars.rest_nonce
                },
                body: data
            });
            
            const result = await response.json();
            
            if (result.success) {
                showMessage(result.message, 'success');
                if (result.redirect) {
                    setTimeout(() => {
                        window.location.href = result.redirect;
                    }, 2000);
                }
            } else {
                showMessage(result.message, 'error');
            }
        } catch (error) {
            showMessage('Ошибка соединения с сервером', 'error');
            console.error('Registration error:', error);
        }
    });
    
    // Функция для показа сообщений
    function showMessage(text, type) {
        messageEl.innerHTML = text;
        messageEl.className = `message ${type}`;
    }
});

Шаг 3: Серверная обработка (PHP)

Добавляем в functions.php:

Часть 1: Регистрация REST endpoint

add_action('rest_api_init', function() {
    register_rest_route('wp/v2', '/custom-register', [
        'methods' => 'POST',
        'callback' => 'handle_custom_register',
        'permission_callback' => '__return_true',
    ]);
});

Часть 2: Обработчик регистрации

function handle_custom_register(WP_REST_Request $request) {
    // Проверка nonce
    if (!wp_verify_nonce($request['security'], 'custom-register-nonce')) {
        return new WP_REST_Response([
            'success' => false,
            'message' => 'Ошибка безопасности сессии'
        ], 200);
    }

    // Получение и очистка данных
    $email = sanitize_email($request['email']);
    $fullname = sanitize_text_field($request['fullname']);
    $password = $request['password'];
    $user_type = sanitize_text_field($request['user_type']);

    // Валидация email
    if (!is_email($email)) {
        return new WP_REST_Response([
            'success' => false,
            'message' => 'Некорректный email'
        ], 200);
    }

    if (email_exists($email)) {
        return new WP_REST_Response([
            'success' => false,
            'message' => 'Этот email уже зарегистрирован'
        ], 200);
    }

    // Валидация пароля
    if (strlen($password) < 6) {
        return new WP_REST_Response([
            'success' => false,
            'message' => 'Пароль должен содержать минимум 6 символов'
        ], 200);
    }

Часть 3: Обработка врачей

    // Специальная проверка для врачей
    if ($user_type === 'doctor') {
        if (empty($_FILES['doctor_file'])) {
            return new WP_REST_Response([
                'success' => false,
                'message' => 'Необходимо загрузить документ'
            ], 200);
        }

        $file = $_FILES['doctor_file'];
        $valid_types = [
            'application/pdf', 
            'application/msword',
            'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
            'image/jpeg', 
            'image/png'
        ];
        $max_size = 2 * 1024 * 1024; // 2MB

        if (!in_array($file['type'], $valid_types)) {
            return new WP_REST_Response([
                'success' => false,
                'message' => 'Недопустимый формат файла'
            ], 200);
        }

        if ($file['size'] > $max_size) {
            return new WP_REST_Response([
                'success' => false,
                'message' => 'Файл слишком большой (макс. 2MB)'
            ], 200);
        }
    }

Часть 4: Создание пользователя

    // Создание пользователя
    $user_id = wp_create_user($email, $password, $email);
    
    if (is_wp_error($user_id)) {
        return new WP_REST_Response([
            'success' => false,
            'message' => $user_id->get_error_message()
        ], 200);
    }

    // Сохранение дополнительных полей
    update_user_meta($user_id, 'fullname', $fullname);
    update_user_meta($user_id, 'user_type', $user_type);

    // Обработка файла для врачей
    if ($user_type === 'doctor' && !empty($_FILES['doctor_file'])) {
        require_once(ABSPATH . 'wp-admin/includes/file.php');
        
        $upload = wp_handle_upload($_FILES['doctor_file'], ['test_form' => false]);
        
        if ($upload && !isset($upload['error'])) {
            update_user_meta($user_id, 'doctor_document', $upload['url']);
        } else {
            error_log('File upload error: ' . $upload['error']);
        }
    }

    // Автоматический вход после регистрации
    $user = wp_signon([
        'user_login' => $email,
        'user_password' => $password,
        'remember' => true
    ], false);

    return new WP_REST_Response([
        'success' => true,
        'message' => 'Регистрация прошла успешно!',
        'redirect' => home_url('/')
    ], 200);
}

Шаг 4: Подключение скриптов и стилей

В том же functions.php добавляем:

// Регистрация скриптов
add_action('wp_enqueue_scripts', function() {
    wp_enqueue_script(
        'custom-register',
        get_template_directory_uri() . '/js/custom-register.js',
        array(),
        filemtime(get_template_directory() . '/js/custom-register.js'),
        true
    );
    
    wp_localize_script('custom-register', 'customVars', [
        'rest_register_url' => rest_url('wp/v2/custom-register'),
        'rest_nonce' => wp_create_nonce('wp_rest')
    ]);
});

// Стили формы
add_action('wp_head', function() {
    echo '<style>
        #custom-register-form {
            max-width: 500px;
            margin: 2rem auto;
            padding: 2rem;
            background: #fff;
            border-radius: 8px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.1);
        }
        .form-group {
            margin-bottom: 1.5rem;
        }
        .message {
            margin-top: 1.5rem;
            padding: 1rem;
            border-radius: 4px;
        }
        .message.success {
            background: #edfaef;
            color: #00a32a;
            border: 1px solid #00a32a;
        }
        .message.error {
            background: #f8ebea;
            color: #d63638;
            border: 1px solid #d63638;
        }
    </style>';
});

Итоги

Мы создали полнофункциональную форму регистрации с:

  • Валидацией на стороне клиента и сервера
  • Условными полями для разных типов пользователей
  • Защитой от злоупотреблений
  • Автоматическим входом после регистрации

Чтобы внедрить это решение:

  1. Разместите HTML-код формы в нужном шаблоне
  2. Добавьте JavaScript в файл /js/custom-register.js
  3. Вставьте PHP-код в functions.php вашей темы
  4. Проверьте работу всех сценариев

Дальнейшие улучшения могут включать:

  • Подтверждение email
  • Капчу для защиты от ботов
  • Интеграцию с социальными сетями
  • Двухфакторную аутентификацию

Форма готова к использованию и обеспечит удобный и безопасный процесс регистрации для ваших пользователей.