Система подписки на пользователя

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

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

  1. Когда вы впервые заходите на страницу нового пользователя, появляется кнопка, которая должна сказать “Подписаться”. Когда вы нажимаете на эту кнопку, запускается ajax и, если успешно, кнопка переключается на скрытую кнопку, которая говорит “Отписаться”. Проблема в том, что при первом посещении страницы нового пользователя сначала появляется кнопка “Отписаться”, что не должно происходить.

  2. Когда вы подписываетесь на нового пользователя, а затем отписываетесь, если вы попробуете снова нажать на кнопку отписки, ajax уведомит вас об ошибке, так как нельзя отписаться дважды, что нормально. Однако проблема в том, что при повторной попытке подписаться на пользователя почему-то ошибка не возвращается, и это возможно.

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

function tb_get_following( $user_id ) {

if ( empty( $user_id ) ) {
    $user_id = get_current_user_id();
}

$following = get_user_meta( $user_id, '_tb_following', true );

return (array) apply_filters( 'tb_get_following', $following, $user_id );
}

function tb_get_followers( $user_id ) {

if ( empty( $user_id ) ) {
    $user_id = get_current_user_id();
}

$followers = get_user_meta( $user_id, '_tb_followers', true );

return (array) apply_filters( 'tb_get_followers', $followers, $user_id );

}

function tb_follow_user( $user_id, $user_to_follow ) {

$following = tb_get_following( $user_id );

if ( $following && is_array( $following ) ) {
    $following[] = $user_to_follow;
} else {
    $following = array();
    $following[] = $user_to_follow;
}

// retrieve the IDs of all users who are following $user_to_follow
$followers = tb_get_followers( $user_to_follow );

if ( $followers && is_array( $followers ) ) {
    $followers[] = $user_id;
} else {
    $followers = array();
    $followers[] = $user_id;
}

do_action( 'tb_pre_follow_user', $user_id, $user_to_follow );

// update the IDs that this user is following
$followed = update_user_meta( $user_id, '_tb_following', $following );

// update the IDs that follow $user_id
$followers = update_user_meta( $user_to_follow, '_tb_followers', $followers );

// increase the followers count
$followed_count = tb_increase_followed_by_count( $user_to_follow ) ;

if ( $followed ) {

    do_action( 'tb_post_follow_user', $user_id, $user_to_follow );

    return true;
}
return false;
}

function tb_unfollow_user( $user_id, $unfollow_user ) {

do_action( 'tb_pre_unfollow_user', $user_id, $unfollow_user );

// get all IDs that $user_id follows
$following = tb_get_following( $user_id );

if ( is_array( $following ) && in_array( $unfollow_user, $following ) ) {

    $modified = false;

    foreach ( $following as $key => $follow ) {
        if ( $follow == $unfollow_user ) {
            unset( $following[$key] );
            $modified = true;
        }
    }

    if ( $modified ) {
        if ( update_user_meta( $user_id, '_tb_following', $following ) ) {
            tb_decrease_followed_by_count( $unfollow_user );
        }
    }

}

// get all IDs that follow the user we have just unfollowed so that we can remove $user_id
$followers = tb_get_followers( $unfollow_user );

if ( is_array( $followers ) && in_array( $user_id, $followers ) ) {

    $modified = false;

    foreach ( $followers as $key => $follower ) {
        if ( $follower == $user_id ) {
            unset( $followers[$key] );
            $modified = true;
        }
    }

    if ( $modified ) {
        update_user_meta( $unfollow_user, '_tb_followers', $followers );
    }

}

if ( $modified ) {
    do_action( 'tb_post_unfollow_user', $user_id, $unfollow_user );
    return true;
}

return false;
}

function tb_get_following_count( $user_id ) {

if ( empty( $user_id ) ) {
    $user_id = get_current_user_id();
}

$following = tb_get_following( $user_id );

$count = 0;

if ( $following ) {
    $count = count( $following );
}

return (int) apply_filters( 'tb_get_following_count', $count, $user_id );
}

function tb_get_follower_count( $user_id ) {

if ( empty( $user_id ) ) {
    $user_id = get_current_user_id();
}

$followed_count = get_user_meta( $user_id, '_tb_followed_by_count', true );

$count = 0;

if ( $followed_count ) {
    $count = $followed_count;
}

return (int) apply_filters( 'tb_get_follower_count', $count, $user_id );
}

function tb_increase_followed_by_count( $user_id ) {

do_action( 'tb_pre_increase_followed_count', $user_id );

$followed_count = tb_get_follower_count( $user_id );

if ( $followed_count !== false ) {

    $new_followed_count = update_user_meta( $user_id, '_tb_followed_by_count', $followed_count + 1 );

} else {

    $new_followed_count = update_user_meta( $user_id, '_tb_followed_by_count', 1 );

}

do_action( 'tb_post_increase_followed_count', $user_id );

return $new_followed_count;
}

function tb_decrease_followed_by_count( $user_id ) {

do_action( 'tb_pre_decrease_followed_count', $user_id );

$followed_count = tb_get_follower_count( $user_id );

if ( $followed_count ) {

    $count = update_user_meta( $user_id, '_tb_followed_by_count', ( $followed_count - 1 ) );

    do_action( 'tb_post_increase_followed_count', $user_id );

}
return $count;
}

function tb_is_following( $user_id, $followed_user ) {

$following = tb_get_following( $user_id );

$ret = false; // is not following by default

if ( is_array( $following ) && in_array( $followed_user, $following ) ) {
    $ret = true; // is following
}

return (int) apply_filters( 'tb_is_following', $user_id, $followed_user );

}

Вот функции для html-кнопок:

function tb_get_follow_unfollow_links( $follow_id = null ) {

global $user_ID;

if( empty( $follow_id ) )
    return;

if ( $follow_id == $user_ID )
    return;

ob_start(); ?>
    <?php if(is_user_logged_in()): ?>

        <?php if ( pwuf_is_following( $user_ID, $follow_id ) ) { ?>
        <a href="#" data-user-id="<?php echo $user_ID; ?>" data-follow-id="<?php echo $follow_id; ?>" class="button unfollow followed"><i></i> Отписаться</a>
        <a href="#" class="button follow" style="display:none;" data-user-id="<?php echo $user_ID; ?>" data-follow-id="<?php echo $follow_id; ?>"><i></i> Подписаться</a>
        <?php } else { ?>
        <a href="#" class="button follow" data-user-id="<?php echo $user_ID; ?>" data-follow-id="<?php echo $follow_id; ?>"><i></i> Подписаться</a>
        <a href="#" class="button followed unfollow" style="display:none;" data-user-id="<?php echo $user_ID; ?>" data-follow-id="<?php echo $follow_id; ?>"><i></i> Отписаться</a>
        <?php } ?>
        <?php else: ?>
        <a class="not-logged-inbutton"><i></i> Подписаться</a>
        <?php endif; ?>
<?php
return ob_get_clean();
}

Вот ajax-действия и ajax-функция:

function tb_process_new_follow() {
if ( isset( $_POST['user_id'] ) && isset( $_POST['follow_id'] ) ) {
    if( tb_follow_user( absint( $_POST['user_id'] ), absint( $_POST['follow_id'] ) ) ) {
        echo 'success';
    } else {
        echo 'failed';
    }
}
die();
}
add_action('wp_ajax_follow', 'tb_process_new_follow');

function tb_process_unfollow() {
if ( isset( $_POST['user_id'] ) && isset( $_POST['follow_id'] ) ) {
    if( tb_unfollow_user( absint( $_POST['user_id'] ), absint( $_POST['follow_id'] ) ) ) {
        echo 'success';
    } else {
        echo 'failed';
    }
}
die();
}
add_action('wp_ajax_unfollow', 'tb_process_unfollow');

jQuery:

jQuery(document).ready(function($) {
/*******************************
follow / unfollow a user
*******************************/
$( '.follow-links a' ).on('click', function(e) {
    e.preventDefault();

    var $this = $(this);

    var data      = {
        action:    $this.hasClass('follow') ? 'follow' : 'unfollow',
        user_id:   $this.data('user-id'),
        follow_id: $this.data('follow-id'),
        nonce:     pwuf_vars.nonce
    };

    $.post( pwuf_vars.ajaxurl, data, function(response) {
        console.log(data);
        if( response == 'success' ) {
            $('.follow-links a').toggle();
        } else {
            console.log( pwuf_vars.processing_error );
        }
    } );
});
});

Вот несколько советов:

Почему вы используете буферизацию вывода в tb_get_follow_unfollow_links()? Я не вижу необходимости в этом.

В tb_get_follow_unfollow_links() отображайте только одну кнопку. При загрузке страницы используйте PHP, чтобы определить, какие классы и текст кнопки нужно установить.

С помощью jQuery измените кнопку, когда получите успешный возврат ajax. Измените класс кнопки, чтобы вы могли вызвать другой ajax-запрос при нажатии.

Используйте .on, чтобы получить события от динамических (загружаемых через ajax) элементов: $( "#container" ).on( "click", ".element", function() {});.

Ваш второй вопрос легко обнаружить с помощью некоторой отладки. Чтобы проверить, уже ли подписан пользователь, можно сделать что-то вроде этого:

$following = get_user_meta( $user_id, '_tb_following', true );
if( ! in_array( $id_to_check, $following )) { // пользователь не подписан, делаем это сейчас }

С уважением, Бьорн

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

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

Проблема 1: Неправильное отображение кнопки на странице пользователя

Ваш код JavaScript и PHP не синхронизируются должным образом для правильного отображения зачарованных кнопок. Когда вы впервые заходите на страницу нового пользователя, отображается кнопка "Unsubscribe", а не "Subscribe". Это связано с тем, как вы генерируете кнопки в функции tb_get_follow_unfollow_links().

Решение:

  1. Перепишите функцию tb_get_follow_unfollow_links() так, чтобы она генерировала только одну кнопку, основываясь на статусе подписки пользователя. Это избавит от необходимости переключения видимости с помощью jQuery:
function tb_get_follow_unfollow_links($follow_id = null) {
    global $user_ID;

    if (empty($follow_id) || $follow_id == $user_ID) {
        return;
    }

    $is_following = tb_is_following($user_ID, $follow_id);
    $button_text = $is_following ? "Unsubscribe" : "Subscribe";
    $button_class = $is_following ? "unfollow" : "follow";

    echo "<a href=\"#\" class=\"button {$button_class}\" data-user-id=\"{$user_ID}\" data-follow-id=\"{$follow_id}\">{$button_text}</a>";
}
  1. Обновите JavaScript, чтобы логика изменения кнопки была основана на классе:
$('.follow-links').on('click', 'a', function(e) {
    e.preventDefault();
    var $this = $(this);

    var data = {
        action: $this.hasClass('follow') ? 'follow' : 'unfollow',
        user_id: $this.data('user-id'),
        follow_id: $this.data('follow-id')
    };

    $.post(pwuf_vars.ajaxurl, data, function(response) {
        if (response === 'success') {
            if ($this.hasClass('follow')) {
                $this.text('Unsubscribe').removeClass('follow').addClass('unfollow');
            } else {
                $this.text('Subscribe').removeClass('unfollow').addClass('follow');
            }
        } else {
            console.log(pwuf_vars.processing_error);
        }
    });
});

Проблема 2: Повторное подписывание без уведомления об ошибке

В функции tb_follow_user() не производится проверка на повторное добавление пользователя в массив подписанных. Это приводит к возможности многократного подписывания без ошибок.

Решение:
Добавьте проверку перед добавлением пользователя в массив:

function tb_follow_user($user_id, $user_to_follow) {
    $following = tb_get_following($user_id);

    if (!in_array($user_to_follow, $following)) {
        $following[] = $user_to_follow;
    }

    $followers = tb_get_followers($user_to_follow);

    if (!in_array($user_id, $followers)) {
        $followers[] = $user_id;
    }

    do_action('tb_pre_follow_user', $user_id, $user_to_follow);

    $followed = update_user_meta($user_id, '_tb_following', $following);
    update_user_meta($user_to_follow, '_tb_followers', $followers);
    tb_increase_followed_by_count($user_to_follow);

    if ($followed) {
        do_action('tb_post_follow_user', $user_id, $user_to_follow);
        return true;
    }
    return false;
}

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

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

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