Как обновить мою функцию jquery/PHP, чтобы добавить/удалить пользователя в качестве избранного в списке пользователей (WordPress)

У меня есть веб-сайт WordPress, на котором я перечисляю всех пользователей (на основе подписки MemberPress), и пользователи могут сохранять других пользователей в качестве избранных. Функция хорошо работает при сохранении пользователя в качестве избранного, она сохраняет и обновляет, как следует, и она восстанавливается, когда я проверяю другое место/браузер.

Но удаление пользователя из избранного не работает. Вот что происходит:

  • Загрузка одной страницы, когда я нажимаю «удалить из избранного», она действует так, как будто я нажал «сохранить в избранное», текст «удалить из избранного» не меняется. При повторном нажатии на то же "удалить из избранного" текст меняется, а кнопка обновляется, по логу вроде все нормально, но при перезагрузке страницы ничего не сохраняется, и снова "удалить из избранного" '.

  • Другая ситуация, при загрузке страницы я нажимаю «сохранить в избранное» одного пользователя, а потом «сохранить в избранное» другого, вроде все нормально. Но при перезагрузке страницы фактически сохраняется только второй, первый возвращается к «сохранению в избранном». То же самое происходит, когда я нажимаю 3 или более «сохранить в избранное» и перезагружаю страницу, сохраняется только последняя.

Это мой список пользователей в PHP

function display_users($args = array(), $show_all_users = true)
{
    $default_args = array(
        'orderby' => 'name',
        'order' => 'ASC',
        'role' => 'subscriber',
        'search' => '',
    );
    $args = wp_parse_args($args, $default_args);

    $wp_user_query = new WP_User_Query($args);

    if (!empty($wp_user_query->results)) {
        $output = '<div class = "user-grid">';
        foreach ($wp_user_query->results as $user) {
            $mepr_user = new MeprUser($user->ID);
            if (empty($mepr_user->active_product_subscriptions('ids'))) {
                continue;
            }
            // Check if only favorites should be displayed
            if (!$show_all_users) {
                $user_id = get_current_user_id();
                $favorites = get_user_meta($user_id, 'favorites', true);
                if (!in_array($user->ID, $favorites)) {
                    // If user is not in favorites list, skip to the next user
                    continue;
                }
            }
            $output .= '<div class = "user">';
            $output .= '<a href = "' . get_author_posts_url($user->ID) . '">';
            if (get_field('mepr_avatar_profile', 'user_' . $user->ID)) {
                $avatar = get_field('mepr_avatar_profile', 'user_' . $user->ID);
                $class = 'user-image-bw';
            } else {
                $avatar = '/wp-content/uploads/2023/04/new-color-community-1.png';
                $class = 'default-image-avatar';
            }

            $output .= '<div class = "user-image">';
            $output .= '<img class = "' . $class . '" src = "' . esc_url($avatar) . '" alt = "Author Avatar" />';
            $output .= '</div>';

            if (get_field('mepr_open_to_connect', 'user_' . $user->ID) == 'always-feel-free-to-reach-out') {
                $output .= '<p class = "user-connect">Let\'s connect</p>';
            }

            $output .= '<div class = "user-name">' . get_field('first_name', 'user_' . $user->ID) . '</div>';
            $output .= '<div class = "user-info">';
            $current_work = get_field('mepr_current_work', 'user_' . $user->ID)[0];
            $current_work = str_replace('-', ' ', $current_work);
            $output .= '<p class = "user-current-work">' . $current_work . '</p>';
            $output .= '</div>';
            $output .= '</a>';
            // Add favorite button
            if (is_user_logged_in()) {
                $user_id = get_current_user_id();
                $favorites = get_user_meta($user_id, 'favorites', true);
                if (!is_array($favorites)) {
                  $favorites = array(); // set $favorites to an empty array if it is not already an array
                }
                $nonce = wp_create_nonce('save_user_favorites');
                $output .= '<button class = "favorite-button" data-user-id = "' . $user->ID . '" data-favorites = "' . esc_attr(json_encode($favorites)) . '" data-is-favorite = "' . (in_array($user->ID, $favorites) ? 'true' : 'false') . '" data-nonce = "' . $nonce . '">' . (in_array($user->ID, $favorites) ? 'Remove from favorites' : 'Add to favorites') . '</button>';
              }      

            $output .= '</div>';
        }
        $output .= '</div>';
    } else {
        $output = '<p>No users found.</p>';
    }

    return $output;
}

Это моя PHP-функция добавления в избранное

// save favorites function
function save_user_favorites() {
    if (!isset($_POST['favorites'])) {
      wp_send_json_error('Favorites not provided');
    }
  
    // Verify nonce
    if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'save_user_favorites')) {
      wp_send_json_error('Invalid nonce');
    }
  
    // Check if user is logged in
    if (!is_user_logged_in()) {
      wp_send_json_error('User not logged in');
    }
  
    // Get user ID
    $user_id = get_current_user_id();
  
    // Get favorites
    $favorites = isset($_POST['favorites']) ? $_POST['favorites'] : array();
  
    // Update user meta
    update_user_meta($user_id, 'favorites', $favorites);
  
    wp_send_json_success();
  }
  
  add_action( 'wp_ajax_nopriv_save_user_favorites', 'save_user_favorites' );
  add_action( 'wp_ajax_save_user_favorites', 'save_user_favorites');

Это мой jquery

$('.favorite-button').click(function(e) {
  e.preventDefault();

  var button = $(this);
  var userId = button.data('userId');
  var nonce = button.data('nonce');
  // get existing favorites from the data attribute of the button
  var favorites = button.data('favorites') || [];

  // Add or remove user from favorites
  if (userId !== "") { 
    const indexToRemove = favorites.indexOf(userId);

    if (!favorites.includes(userId)) { 
      favorites.push(userId);
      console.info(`User ${userId} added to favorites.`);
    } else {
      favorites.splice(indexToRemove, 1);
      console.info(`User ${userId} removed from favorites.`);
    }

    // Save favorites to the user metadata via AJAX 
    $.post(ajaxurl, {
      'action': 'save_user_favorites',
      'favorites': favorites,
      'nonce': nonce,
      'user_id': userId // add user ID to request parameters,
    })  
    .done(function(response) {
      console.info('Favorites saved:', response);
      // update the favorites attribute of the button
      button.data('favorites', favorites);
    })
    .fail(function(xhr, status, error) {
      console.info('Failed to save favorites:', error);
      console.info('Server response:', xhr.responseText);
    });
  } else {
    console.info(`Cannot add/remove user with empty ID`);
  }

  // Toggle button text and data attribute
  button.text(favorites.includes(userId) ? 'Remove from favorites' : 'Add to favorites');
});

Пытаюсь по-другому

Я также попробовал другой способ для запроса ajax, сначала сохранив его как локальное хранилище и обновив список избранного при перезагрузке страницы. Это сработало очень хорошо, как и должно (добавление/удаление пользователей), но я получаю сообщение об ошибке при перезагрузке страницы, когда она пытается сохранить ее в избранном (не в локальном хранилище).

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

from the update user Array []
from the update user Array []
from the update user Array []
from the update user Array(4) [ 420, 442, 449, 447 ]
from the update user Array []

И так продолжается, только с массивом значений тех, что я сохранил. Рядом написано, тоже много раз в firefox:

Failed to save favorites: 
Server response: undefined
Failed to save favorites: 
Server response: undefined

В хроме:

Favorites saved: {success: false, data: 'Favorites not provided'} 
data: "Favorites not provided"
success: false
[[Prototype]]: Object

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

// get existing favorites from localStorage, or initialize to empty array
var favorites = JSON.parse(localStorage.getItem('favorites') || '[]');

$('.favorite-button').click(function(e) {
  e.preventDefault();

  var button = $(this);
  var userId = button.data('userId');

  // Add or remove user from favorites if userId is not empty
  if (userId !== "") {
    var isFavorite = button.data('isFavorite');
    var nonce = button.data('nonce');

    const userIdToRemove = userId; // Replace with the actual user ID you want to remove
    const indexToRemove = favorites.indexOf(userIdToRemove);

  // Add or remove user from favorites
  if (!favorites.includes(userId)) {
    favorites.push(userId);
    console.info('user added to favorites')
  } else {
    favorites.splice(indexToRemove, 1);
    console.info('user deleted from favorites')
  }

  // Save favorites to localStorage
  localStorage.setItem('favorites', JSON.stringify(favorites));

  // Save favorites to user metadata
  $.post(ajaxurl, {
    'action': 'save_user_favorites',
    'favorites': favorites,
    'nonce': nonce,
    'user_id': userId // add user ID to request parameters
  })  
  .done(function(response) {
    console.info('Favorites saved:', response);
  })
  .fail(function(xhr, status, error) {
    console.info('Failed to save favorites:', error);
    console.info('Server response:', xhr.responseText);
  });

  update_local_storage(userId, favorites)

  console.info('favorites saved to local storage', favorites)

  // Toggle button text and data attribute
  button.text(favorites.includes(userId) ? 'Remove from favorites' : 'Add to favorites');
  }
});

// on page load, update button text based on stored favorites
$('.favorite-button').each(function() {
  var button = $(this);
  var userId = button.data('userId');
  var isFavorite = button.data('isFavorite');

  // check if user is in favorites
  var favorites = JSON.parse(localStorage.getItem('favorites') || '[]');
  var isUserFavorite = favorites.includes(userId);

  // set button text and data attribute based on result
  button.text(isUserFavorite ? 'Remove from favorites' : 'Add to favorites');
  button.data('isFavorite', isUserFavorite);
  button.data('favorites', favorites);
});

// function to store favorites in localStorage
function update_local_storage(user_id, favorites) {
  localStorage.setItem('favorites_' + user_id, JSON.stringify(favorites));
  // console.info('localstorage', favorites)
}

function update_user_favorites(user_id, favorites, nonce) {
  console.info('from the update user', favorites)

  $.post(ajaxurl, {
    'action': 'save_user_favorites',
    'favorites': favorites,
    'nonce': nonce,
    'user_id': user_id // Use the user_id parameter instead of userId
  })
  .done(function(response) {
    console.info('Favorites saved:', response);
  })
  .fail(function(xhr, status, error) {
    console.info('Failed to save favorites:', error);
    console.info('Server response:', xhr.responseText);
  });
}


// update user metadata when page is unloaded
$(window).on('beforeunload', function() {
  $('.favorite-button').each(function() {
    var user_id = $(this).data('userId');
    var nonce = $(this).data('nonce');
    var favorites = JSON.parse(localStorage.getItem('favorites_' + user_id) || '[]');
    // var favorites = [ 449, 487, 442, 474, 488, 457, 553, 559, 841]
    // console.info({favorites})
    update_user_favorites(user_id, favorites, nonce);
  });
});

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

Вы правильно ссылаетесь на действие PHP в своем AJAX? Что такое ajaxurl? Я нигде не вижу объявления этой переменной. Вероятно, это запрос, который выполняется неправильно, и поэтому вы не можете сохранить своих пользователей на стороне сервера.

Oris Sin 25.04.2023 12:33

Более того, лучше всего будет установить data.favorites= favorites, data.nonce= nonce и, наконец, data.user_id = user_id. Затем вы должны передать все эти данные в действие POST, например: $.post(ajaxurl, function( data ) { $( ".result" ).html( data );});

Oris Sin 25.04.2023 13:02

Привет @OrisSin, спасибо за твое сообщение. Я использую ajaxurl WordPress из admin-ajax.php, который работает нормально. К сожалению, изменение того, как я передаю данные, не меняется.

Bart 27.04.2023 11:21
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
2
3
124
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Может быть, что-то вроде этого

PHP на переднем плане

$output .= '<button class = "favorite-button ' . (in_array($user->ID, $favorites) ? 'is_favorite' : '') . '" data-user-id = "' . $user->ID . '" data-favorites = "' . esc_attr(json_encode($favorites)) . '" data-is-favorite = "' . (in_array($user->ID, $favorites) ? 'true' : 'false') . '" data-nonce = "' . $nonce . '">' . (in_array($user->ID, $favorites) ? 'Remove from favorites' : 'Add to favorites') . '</button>';

JS

$('.favorite-button').click(function(e) {
    e.preventDefault();
  
    var button = $(this);
    var action = 'add';
    var ajax = 0;
    var userId = button.data('userId');
    var nonce = button.data('nonce');
    if (button.hasClass('is_favorite')) { 
        var action = 'remove';
    }
    if (userId !== "" && !ajax) { 
        ajax =1;
        // Save favorites to the user metadata via AJAX 
        $.post(ajaxurl, {
            'action': 'save_user_favorites',
            'nonce': nonce,
            'user_id': userId // add user ID to request parameters,
        })  
        .done(function(response) {
            ajax =0;
            console.info('Favorites saved:', response);
            if (action == 'add') { 
              button.addClass('is_favorite');
              console.info(`User ${userId} added to favorites.`);
              button.text( 'Remove from favorites' );
            } else {
              console.info(`User ${userId} removed from favorites.`);
              button.text( 'Add to favorites');
            }
        })
        .fail(function(xhr, status, error) {
            console.info('Failed to save favorites:', error);
            console.info('Server response:', xhr.responseText);
        });
    } else {
        console.info(`Cannot add/remove user with empty ID`);
    }
      
});

PHP

// save favorites function
function save_user_favorites() {
    if (!isset($_POST['favorites'])) {
      wp_send_json_error('Favorites not provided');
    }
  
    // Verify nonce
    if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'save_user_favorites')) {
      wp_send_json_error('Invalid nonce');
    }
  
    // Check if user is logged in
    if (!is_user_logged_in()) {
      wp_send_json_error('User not logged in');
    }
  
    // Get user ID
    $user_id = get_current_user_id();
  
    // Get favorites 
    $favorites = get_user_meta($user_id, 'favorites', true) ;

    if ( !$favorites ){
        $favorites = [];
    }

    if ( in_array($_POST['user_id'], $favorites) ){
        unset( $favorites[array_search($_POST['user_id'], $favorites)] );
    } else {
        $favorites[] = $_POST['user_id'];
    }
  
    // Update user meta
    update_user_meta($user_id, 'favorites', $favorites);
  
    wp_send_json_success();
  }
  
  add_action( 'wp_ajax_nopriv_save_user_favorites', 'save_user_favorites' );
  add_action( 'wp_ajax_save_user_favorites', 'save_user_favorites');

Вы определенно сделали мой день (дни) @Galina! Мне просто нужно было добавить данные в сообщение в качестве параметра, например 'favorites': button.data('favorites'). Мне просто нужно посмотреть, почему при третьем клике или после удаления из избранного и повторного добавления текст не меняется (функционал работает идеально). Спасибо!

Bart 27.04.2023 14:53

Чтобы кнопка не менялась, как объяснялось выше, я добавил button.removeClass('is_favorite'); к оператору ajax else в .done.

Bart 28.04.2023 12:18

Другие вопросы по теме