Хуки template_redirect перенаправляют на неверный URL

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

Я создал пользовательский плагин для входа, регистрации и восстановления пароля.

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

Но у меня есть ошибки, я думаю, что хуки template_redirect не знают, какое перенаправление для проверки, а какое для восстановления пароля.

Пожалуйста, посмотрите на мой код:

это custom-plugin.php

    <?php

    if( ! defined('PLUGIN_PATH') ){
        define('PLUGIN_PATH' , plugin_dir_path(__FILE__));
    }

    require_once ABSPATH . 'wp-admin/includes/plugin.php';
    require_once ABSPATH . 'wp-admin/includes/upgrade.php';
    require_once PLUGIN_PATH . 'includes/register.php';
    require_once PLUGIN_PATH . 'includes/login.php';
    require_once PLUGIN_PATH . 'includes/forgot-password.php';
    require_once PLUGIN_PATH . 'includes/change-password.php';
    require_once PLUGIN_PATH . 'includes/functions.php';

    if( ! class_exists('main')){
        class main {

            function register(){

                // Начать сессии при инициализации.
                add_action( 'init', array('myFunctions','wpse16119876_init_session') );

                add_action ('template_redirect', array( 'forgotPasswordForm', 'forgotPassword'));

                add_action ('template_redirect', array( 'loginForm', 'verify'));

                add_action ('template_redirect', array( 'loginForm', 'set_submit_login_func'));

            }

        }

        $main = new main();
        $main->register();

   }

  ?>

Предположим, что я вставил настройки SMTP и у меня есть форма. Я даю только функции, которые имеют wp_redirect.

А это login.php,

<?php
        class loginForm extends registerForm{

        public function set_submit_login_func(){
            global $wpdb;

            $account = filter_input(INPUT_POST, 'account');
            $password = filter_input(INPUT_POST, 'password');

            $users = $wpdb->get_row( $wpdb->prepare("SELECT * FROM {$wpdb->prefix}users WHERE user_email="$account" OR user_login = '$account'", ARRAY_A));

            ob_start();

            if(isset($_POST["login"])){
                if($users){
                    if($users->user_status == 0){
                        if(wp_check_password($password, $users->user_pass)){
                            $credentials = array(
                                'user_login' => $account,
                                'user_password' => $password
                            );

                            wp_signon($credentials, true);
                            wp_redirect(site_url());
                            exit;
                        } else{
                            $_SESSION["message"] = '<div style="background-color: indianred; color: #FFFFFF; line-height: 30px; height: 10%; text-align: center; top: 0px; width: 100%; z-index: 100; margin-bottom: 10px;">Неправильный пароль</div>';
                        }
                    } else{
                        $_SESSION["message"] = '<div style="background-color: indianred; color: #FFFFFF; line-height: 30px; height: 10%; text-align: center; top: 0px; width: 100%; z-index: 100; margin-bottom: 10px;">Учетная запись еще не активирована!</div>';
                    }

                }else{
                    if($account != ($users->user_email && $user_login)){
                        $_SESSION["message"] = '<div style="background-color: indianred; color: #FFFFFF; line-height: 30px; height: 10%; text-align: center; top: 0px; width: 100%; z-index: 100; margin-bottom: 10px;">Учетная запись не зарегистрирована!</div>';
                    }

                }

            }

            session_destroy();

            return ob_get_clean(); 

        }

        public function verify(){

                global $wpdb;

                $email = $_GET["em"];
                $token = $_GET["tk"];
                $url = site_url() .'/login';

                $registered_date = date( 'Y-m-d H:i:s', current_time( 'timestamp', 0 ) );  

                $users = $wpdb->get_row( $wpdb->prepare("SELECT * FROM {$wpdb->prefix}users WHERE user_email="$email"", ARRAY_A));

                if($users){

                    $user_token = $wpdb->get_row( $wpdb->prepare("SELECT * FROM {$wpdb->prefix}user_token WHERE token = '$token'", ARRAY_A));

                    if($user_token){
                        if(time() - $user_token->date_created < (60*60*24)){

                            $wpdb->update($wpdb->prefix . 'users', ["user_status" => 0, "user_registered" => $registered_date], ["user_email" => $email]);

                            $wpdb->delete($wpdb->prefix . 'user_token', ['email' => $email]);

                            $_SESSION["message"] = '<div style="background-color: darkcyan; color: #FFFFFF; line-height: 30px; height: 10%; text-align: center; top: 0px; width: 100%; z-index: 100; margin-bottom: 10px;">'.$email.'&nbsp'.'активирован, пожалуйста, войдите'.'</div>';

                            wp_redirect($url);
                            exit;

                        }else{
                            $wpdb->delete($wpdb->prefix . 'users', ['user_email' => $email]);
                            $wpdb->delete($wpdb->prefix . 'user_token', ['email' => $email]);

                            $_SESSION["message"] = '<div style="background-color: indianred; color: #FFFFFF; line-height: 30px; height: 10%; text-align: center; top: 0px; width: 100%; z-index: 100; margin-bottom: 10px;">'.'Ошибка активации учетной записи! Токен истек'.'</div>';

                            wp_redirect($url);
                            exit;
                        }

                    }else{
                        if(($token != $user_token) === true){
                            $_SESSION["message"] = '<div style="background-color: indianred; color: #FFFFFF; line-height: 30px; height: 10%; text-align: center; top: 0px; width: 100%; z-index: 100; margin-bottom: 10px;">'.'Ошибка активации учетной записи! Неверный токен'.'</div>';

                            wp_redirect($url);    
                            exit;

                        }
                    }

                }else{

                    if(($email != $users->user_email) === true){   

                        $_SESSION["message"] = '<div style="background-color: indianred; color: #FFFFFF; line-height: 30px; height: 10%; text-align: center; top: 0px; width: 100%; z-index: 100; margin-bottom: 10px;">'.'Ошибка активации учетной записи! Неверный адрес электронной почты'.'</div>';

                        wp_redirect($url);    
                        exit;

                    }

                }

                session_destroy();

            } 

        }
?>

это forgot-password.php

<?php
    class forgotPasswordForm extends loginForm{

        public function forgotPassword(){

            global $wpdb;

            $email = $_GET["em"];
            $token = $_GET["tk"];
            $url = site_url() .'/login/forgotpassword';

            $other_url = add_query_arg(
                array(
                    'req:em' =>$email,
                    'tk' => $token
                ), site_url().'/changepassword'
            );

            $users = $wpdb->get_row( $wpdb->prepare("SELECT * FROM {$wpdb->prefix}users WHERE user_email="$email"", ARRAY_A));

            if($users){
                $user_token = $wpdb->get_row( $wpdb->prepare("SELECT * FROM {$wpdb->prefix}user_token WHERE token = '$token'", ARRAY_A));

                if($user_token){
                    if(time() - $user_token->date_created < (60*60*24)){

                        $_SESSION["message"] = '<div style="background-color: darkcyan ; color: #FFFFFF; line-height: 30px; height: 10%; text-align: center; top: 0px; width: 100%; z-index: 100; margin-bottom: 10px;">'.'Сбросить пароль: '.$email.'</div>';

                        wp_redirect($other_url);

                        exit;

                    }
                    else{
                        $wpdb->delete($wpdb->prefix . 'user_token', ['email' => $email]);

                        $_SESSION["message"] = '<div style="background-color: indianred; color: #FFFFFF; line-height: 30px; height: 10%; text-align: center; top: 0px; width: 100%; z-index: 100; margin-bottom: 10px;">'.'Ошибка сброса пароля! Токен истек'.'</div>';

                        wp_redirect($url);
                        exit;
                    }

                }

                else{
                    if($token != $user_token){

                        $_SESSION["message"] = '<div style="background-color: indianred; color: #FFFFFF; line-height: 30px; height: 10%; text-align: center; top: 0px; width: 100%; z-index: 100; margin-bottom: 10px;">'.'Ошибка сброса пароля! Неверный токен'.'</div>';

                        wp_redirect($url);    
                        exit;

                    }
                }

            }else{

                if($email != $users->user_email){   

                    $_SESSION["message"] = '<div style="background-color: indianred; color: #FFFFFF; line-height: 30px; height: 10%; text-align: center; top: 0px; width: 100%; z-index: 100; margin-bottom: 10px;">'.'Ошибка сброса пароля! Неверный адрес электронной почты'.'</div>';

                    wp_redirect($url); 
                    exit;

                }

            }

        }

    }

?>

и я разместил функции sendEmail в functions.php

<?php
class myFunctions {

  protected static function _sendEmail($token, $type){

            $sendto = filter_input(INPUT_POST, 'email');
            $sendfrom = '[email protected]';
            $headers = array("Content-type:text/html; charset=UTF-8","From: Me Myself <". $sendfrom . ">");
            if($type == 'verify'){
                $sendsub = 'Подтверждение учетной записи';
                $sendmess="Пожалуйста, нажмите, чтобы активировать вашу учетную запись:<a href="".site_url(). '/login/verify?em='.filter_input(INPUT_POST, 'email'). '&tk='.urlencode_deep($token).'">Активировать</a>";
            }
            if($type == 'forgot'){
                $sendsub = 'Сброс пароля';
                $sendmess="Пожалуйста, нажмите, чтобы сбросить ваш пароль:<a href="".site_url(). '/login/forgotpassword?em='.filter_input(INPUT_POST, 'email'). '&tk='.urlencode_deep($token).'">Сбросить пароль</a>";

            }

            wp_mail($sendto, $sendsub, $sendmess, $headers);

        }

}

?>

И для наследования, мой код выглядит так:

class myFunctions
class registerForm extends myFunctions 
class loginForm extends registerForm
class forgotPasswordForm extends loginForm
class changePasswordForm extends forgotPasswordForm

Вот где вызывается статическая функция _sendEmail:

это внутри forgot-password.php

public function set_submit_forgot_password_func(){
        global $wpdb;

        $email = filter_input(INPUT_POST, 'email', FILTER_SANITIZE_STRING);

        $token = $this->token = base64_encode(random_bytes(32));

        ob_start();

        if(isset($_POST["forgot-password"])){

            if(!filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL) === true){
                $this->error["email"] = "* электронный адрес недействителен";
            }
            else if(!email_exists($email)){
                $this->error["email"] = "* электронный адрес не зарегистрирован";
            }
            else{
                if($this->error["email"]){
                    unset($_POST);
                    return false;
                }
                else{
                    $_SESSION["message"] = '<div style="background-color: darkcyan; color: #FFFFFF; line-height: 30px; height: 10%; text-align: center; top: 0px; width: 100%; z-index: 100; margin-bottom: 10px;">Мы отправили письмо на '.$_POST["email"].', пожалуйста, сбросьте пароль в течение 24 часов!'.'</div>';

                    $user_token = [
                        'id' => '',
                        'email' => $email,
                        'token' => $token,
                        'date_created' => time()
                    ];

                    $wpdb->insert($wpdb->prefix . 'user_token', $user_token);

                    forgotPasswordForm::_sendEmail($token, 'forgot');

                }
            }
        }

        session_destroy();

        return ob_get_clean();

    }

Вот как register.php отправляет проверку по электронной почте:

public function set_submit_func(){
        global $wpdb;

        $fname = filter_input(INPUT_POST, 'fname', FILTER_SANITIZE_STRING);
        $lname = filter_input(INPUT_POST, 'lname', FILTER_SANITIZE_STRING);
        $username  = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_STRING);
        $email = filter_input(INPUT_POST, 'email', FILTER_SANITIZE_STRING);
        $password = wp_hash_password(filter_input(INPUT_POST, 'password', FILTER_DEFAULT));
        $repeat_password = wp_hash_password(filter_input(INPUT_POST, 'repeat_password', FILTER_DEFAULT));

        $regexp_username = array("options"=>array("regexp"=>"/^[a-zA-Z\d\D]+$/"));
        $regexp_name = array("options"=>array("regexp"=>"/^[a-zA-Z\s]+$/"));
        $regexp_password = array("options"=>array("regexp"=>"/^[a-zA-Z\d\D]+$/"));

        $token = $this->token = base64_encode(random_bytes(32));

        ob_start();

        if(isset($_POST["submit2"])){

            if(!filter_input(INPUT_POST, 'fname', FILTER_VALIDATE_REGEXP, $regexp_name ) === true){
                $this->error["fname"] = "* имя не валидно";
            }
            if(!filter_input(INPUT_POST, 'lname', FILTER_VALIDATE_REGEXP, $regexp_name) === true){
                $this->error["lname"] = "* фамилия не валидна";
            }

            if(!filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL) === true){
                $this->error["email"] = "* электронный адрес недействителен";
            }
            else if (email_exists($email)) {
                $this->error["email"] = "* электронный адрес уже зарегистрирован";
            }

            if(!filter_input(INPUT_POST, 'username', FILTER_VALIDATE_REGEXP, $regexp_username ) === true){
                $this->error["username"] = "* имя пользователя недействительно";
            }
            else if (username_exists($username)){
                $this->error["username"] = "* имя пользователя уже зарегистрировано";
            }

            if(!filter_input(INPUT_POST, 'password', FILTER_VALIDATE_REGEXP, $regexp_password) === true){
                $this->error["password"] = "* пароль недействителен";
            }
            else if(strlen($_POST["password"]) < 5){
                $this->error["password"] = "* пароль не может быть меньше 5 символов";
            }
            else if($_POST["repeat_password"] != $_POST["password"]){
                $this->error["repeat_password"] = "* пароли не совпадают";
            }

            else{

                if($this->error["lname"] || $this->error["fname"] || $this->error["username"] || $this->error["email"] || $this->error["password"] || $this->error["repeat_password"] ){
                    unset($_POST);
                    return false;
                }
                else{
                    $_SESSION["message"] = '<div style="background-color: darkcyan; color: #FFFFFF; line-height: 30px; height: 10%; text-align: center; top: 0px; width: 100%; z-index: 100; margin-bottom: 10px;">Мы отправили письмо на '.$_POST["email"].', пожалуйста, подтвердите его в течение 24 часов!</div>';

                    $data = [
                        'ID' => '',
                        'user_login' => $username,
                        'user_pass' => $repeat_password,
                        'user_nicename' => $username,
                        'user_email' => $email,
                        'user_status' => '1',
                        'display_name' => $username
                    ];

                    $user_token = [
                        'id' => '',
                        'email' => $email,
                        'token' => $token,
                        'date_created' => time()
                    ];

                    $wpdb->insert($wpdb->prefix . 'users', $data);
                    $wpdb->insert($wpdb->prefix . 'user_token', $user_token);

                    registerForm::_sendEmail($token, 'verify');

                }
            }
        }

        return ob_get_clean();
    }

Это то, как вызывается функция _sendEmail для сброса пароля:

введите описание изображения здесь

Но когда я нажимаю на ссылку, перенаправляет на страницу входа, а не на страницу смены пароля:

введите описание изображения здесь

Надеюсь, я смогу получить помощь в решении этих ошибок. Спасибо!

Код добавляет функции таким образом:

add_action ('template_redirect', array( 'loginForm', 'set_submit_login_func'));

Что сообщает PHP сделать это, когда происходит template_redirect:

loginForm::set_submit_login_func();

Но мы видим set_submit_login_func в коде вопросов, и очевидно, что это не статическая функция:

public function set_submit_login_func(){

Что вам нужно, это динамическая вызываемая функция, например:

class MyClass {
    public function test() { }
}

$obj = new MyClass();
add_action( '...', array( $obj, 'test' ) );

Где array( $obj, 'test' ) такое же, как $obj->test(). Обратите внимание, что первый параметр – это объект, на котором нужно вызвать функцию, а не имя класса.

Я настоятельно рекомендую ознакомиться с тем, как использовать вызываемые функции PHP, чтобы лучше понять это: https://www.php.net/manual/en/language.types.callable.php

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

Решение проблемы с неправильной переадресацией на основе template_redirect

Вам нужно обратить внимание на то, как вы используете хуки template_redirect. В текущем коде вы пытаетесь установить действие для вызова функций на основе класса, что может привести к проблемам с контекстом вызова. Давайте рассмотрим основные ошибки и пути их решения.

1. Статические против нестатических методов

Ваша проблема заключена в том, что вы пытаетесь использовать нестатические методы (например, set_submit_login_func) как статические. Это неправильно, так как вызываемый метод не является статическим и не может быть вызван через имя класса. В результате, вызов array('loginForm', 'set_submit_login_func') не будет работать должным образом, поскольку вы не создаете экземпляр класса.

Правильный способ:

Создайте экземпляр класса и передайте его в метод add_action. Это выглядит следующим образом:

$loginForm = new loginForm();
add_action('template_redirect', array($loginForm, 'set_submit_login_func'));

$forgotPasswordForm = new forgotPasswordForm();
add_action('template_redirect', array($forgotPasswordForm, 'forgotPassword'));

add_action('template_redirect', array($loginForm, 'verify'));

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

2. Использование глобальных переменных и сессий

Убедитесь, что вы инициализируете сессии и корректно работаете с глобальными переменными, такими как $_SESSION и $_GET. Это важно, поскольку неправильное использование или незадействованная сессия может привести к не корректной работе вашей логики:

  • Проверьте, что сессии инициализируются в нужный момент (обычно в init или plugins_loaded).
  • Убедитесь, что вы корректно обрабатываете переменные, поступающие через $_GET и $_POST.

3. Сообщения и редиректы

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

if(isset($_SESSION["message"])) {
    add_action('wp_footer', function() {
        echo $_SESSION["message"];
        unset($_SESSION["message"]); // Очищаем сообщение после вывода
    });
}

Это позволяет показать сообщение после перенаправления.

4. Код редиректа и проверок

В ваших методах verify и forgotPassword, перед редиректом добавьте проверки, чтобы убедиться, что вы переходите на правильный URL. Например:

if (condition) {
    wp_redirect($url);
    exit;
} else {
    // Обработка ошибок
}

Заключение

Эти изменения должны исправить ваши ошибки с переадресацией и помочь обеспечить правильное функционирование вашего плагина. Убедитесь, что класс и методы организованы корректно, чтобы они работали в нужном контексте. Если проблема сохраняется, рассмотрите возможность добавления логирования для отслеживания, на какие URL происходит переадресация, и какие проверки не проходят.

Если вам нужна дополнительная помощь или разъяснения по какому-либо из пунктов, не стесняйтесь задавать вопросы. Удачи в разработке!

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

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