php - AJAX button toggle works only once until page refresh

I have a button that allows users to "favorite" or "unfavorite" a post. Clicking it should toggle between the two states (by adding or removing the post ID from a user's repeater field). The function works, but only once until the page is refreshed, then it will work once again. I cannot figure out how to make it work repeatedly without a page refresh.
It seems as though, if a post is not favorited, clicking the button will favorite the page, then clicking it again will keep trying to favorite it. Only when the page is reloaded does the button recognize that it is already favorited and then will run the unfavorite function.
I'm sure there is something simple I am overlooking, but I can't figure out what it is. Any help is much appreciated!
Here is the code for the button in my PHP template:
<div id="favorites">
<?php
// Favorited indicator
// Check if the user has any saved Favorites. If so, loop through them and if there are any matches, change the favorite heart icon to pink.
if (have_rows('my_favorites', $currentUserID)) :
while (have_rows('my_favorites', $currentUserID)) : the_row();
$favorite_post_id = get_sub_field('post_id');
$favorite_name = get_field('name', $favorite_post_id);
// If the post ID exists
if ($favorite_post_id == $post_ID) {
array_push($check_favorites_array, 'yes');
} else {
array_push($check_favorites_array, 'no');
}
endwhile;
endif;
$post = get_post();
$favorite_class = '';
$nonce = wp_create_nonce('add_remove_dog_from_favorites_nonce');
$link = '';
if (in_array('yes', $check_favorites_array)) {
$link = admin_url('admin-ajax.php?action=remove_dog_from_favorites&post_id=' . $post->ID . '&nonce=' . $nonce);
$favorite_class = 'is-favorite';
} else {
$link = admin_url('admin-ajax.php?action=add_dog_to_favorites&post_id=' . $post->ID . '&nonce=' . $nonce);
$favorite_class = 'not-favorite';
}
?>
<a href="<?php echo $link; ?>" data-post_id="<?php echo $post->ID ?>" data-nonce="<?php echo $nonce; ?>" data-user_id="<?php echo $currentUserID ?>" class="favorite-toggle <?php echo $favorite_class ?>" id="favorite-toggle">
<i class="fas fa-heart"></i>
</a>
</div>
And the functions' code:
/ define the actions for the two hooks created, first for logged in users and the next for logged out users
add_action('wp_ajax_add_dog_to_favorites', 'add_dog_to_favorites');
add_action('wp_ajax_nopriv_add_dog_to_favorites', 'login_to_add_to_favorites');
// define the function to be fired for logged in users
function add_dog_to_favorites()
{
// nonce check for an extra layer of security, the function will exit if it fails
if (!wp_verify_nonce($_REQUEST['nonce'], 'add_remove_dog_from_favorites_nonce')) {
exit('Woof Woof Woof');
}
$post_id = $_REQUEST['post_id'];
$user_id = $_REQUEST['user_id'];
$row = array(
'post_id' => $post_id
);
$contains_row = false;
if (have_rows('my_favorites', $user_id)) :
while (have_rows('my_favorites', $user_id)) : the_row();
$sub_value = get_sub_field('post_id');
if ($sub_value == $post_id) {
$contains_row = true;
}
endwhile;
if ($contains_row == false) {
add_row('my_favorites', $row, $user_id);
}
endif;
$contains_row = false;
// If the above action fails, result type is set to 'error' and like_count set to old value, if success, update to new_like_count
if ($post_id === false) {
$result['type'] = 'error';
// $result['like_count'] = $like_count;
} else {
$result['type'] = 'success';
// $result['like_count'] = $new_like_count;
}
// Check if action was fired via Ajax call. If yes, JS code will be triggered, else the user is redirected to the post page
if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
$result = json_encode($result);
echo $result;
} else {
header("Location: " . $_SERVER['HTTP_REFERER']);
}
// don't forget to end your scripts with a wp_die() function - very important
wp_die();
}
// define the functtion to be fired for logged out users
function login_to_add_to_favorites()
{
echo 'You must log in to like';
wp_die();
}
// used here only for enabling syntax highlighting. Leave this out if it's already included in your plugin file.
// Fires after WordPress has finished loading, but before any headers are sent.
add_action('init', 'enqueue_add_dog_to_favorites_script');
function enqueue_add_dog_to_favorites_script()
{
// Register the JS file with a unique handle, file location, and an array of dependencies
wp_register_script('add_favorites_script', plugin_dir_url(__FILE__) . 'add_favorites_script.js', array('jquery'));
// localize the script to your domain name, so that you can reference the url to admin-ajax.php file easily
wp_localize_script('add_favorites_script', 'myAjax', array('ajaxurl' => admin_url('admin-ajax.php')));
// enqueue jQuery library and the script you registered above
wp_enqueue_script('jquery');
wp_enqueue_script('add_favorites_script');
}
/**
* Remove Dog from Favorites
*/
// define the actions for the two hooks created, first for logged in users and the next for logged out users
add_action('wp_ajax_remove_dog_from_favorites', 'remove_dog_from_favorites');
add_action('wp_ajax_nopriv_remove_dog_from_favorites', 'login_to_remove_dog_from_favorites');
// define the function to be fired for logged in users
function remove_dog_from_favorites()
{
// nonce check for an extra layer of security, the function will exit if it fails
if (!wp_verify_nonce($_REQUEST['nonce'], 'add_remove_dog_from_favorites_nonce')) {
exit('Woof Woof Woof');
}
$post_id = $_REQUEST['post_id'];
$user_id = $_REQUEST['user_id'];
if (have_rows('my_favorites', $user_id)) :
while (have_rows('my_favorites', $user_id)) : the_row();
$sub_value = get_sub_field('post_id');
if ($sub_value == $post_id) {
delete_row('my_favorites', get_row_index(), $user_id);
}
endwhile;
endif;
// If the above action fails, result type is set to 'error' and like_count set to old value, if success, update to new_like_count
if ($post_id === false) {
$result['type'] = 'error';
// $result['like_count'] = $like_count;
} else {
$result['type'] = 'success';
// $result['like_count'] = $new_like_count;
}
// Check if action was fired via Ajax call. If yes, JS code will be triggered, else the user is redirected to the post page
if (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
$result = json_encode($result);
echo $result;
} else {
header("Location: " . $_SERVER['HTTP_REFERER']);
}
// don't forget to end your scripts with a wp_die() function - very important
wp_die();
}
// define the functtion to be fired for logged out users
function login_to_remove_dog_from_favorites()
{
echo 'You must log in to like';
wp_die();
}
And my Jquery:
jQuery(document).ready(function () {
jQuery(".not-favorite").on("click", function (e) {
e.preventDefault();
buttonLike = jQuery(".is-favorite");
post_id = jQuery(this).attr("data-post_id");
nonce = jQuery(this).attr("data-nonce");
user_id = jQuery(this).attr("data-user_id");
jQuery.ajax({
type: "post",
dataType: "json",
url: myAjax.ajaxurl,
data: {
action: "add_dog_to_favorites",
post_id: post_id,
nonce: nonce,
user_id: user_id,
},
success: function (response) {
if (response.type == "success") {
console.log("success!");
// const button = document.querySelector('.not-favorite');
// button.classList.remove('not-favorite');
// button.classList.add('is-favorite');
// jQuery("#favorites").load(' #favorites');
jQuery("#favorite-toggle").removeClass("not-favorite");
jQuery("#favorite-toggle").addClass("is-favorite");
linkText = jQuery("#favorite-toggle").prop("href");
newLinkText = linkText.replace(
"add_dog_to_favorites",
"remove_dog_from_favorites"
);
jQuery("#favorite-toggle").attr("href", newLinkText);
} else {
alert("Your like could not be added");
}
},
});
});
jQuery(".is-favorite").on("click", function (e) {
e.preventDefault();
buttonLike = jQuery(".not-favorite");
post_id = jQuery(this).attr("data-post_id");
nonce = jQuery(this).attr("data-nonce");
user_id = jQuery(this).attr("data-user_id");
jQuery.ajax({
type: "post",
dataType: "json",
url: myAjax.ajaxurl,
data: {
action: "remove_dog_from_favorites",
post_id: post_id,
nonce: nonce,
user_id: user_id,
},
success: function (response) {
if (response.type == "success") {
console.log("success!");
// var button = document.querySelector('.is-favorite');
// button.classList.remove('is-favorite');
// button.classList.add('not-favorite');
// jQuery("#favorites").load(' #favorites');
jQuery("#favorite-toggle").removeClass("is-favorite");
jQuery("#favorite-toggle").addClass("not-favorite");
linkText = jQuery("#favorite-toggle").prop("href");
newLinkText = linkText.replace(
"remove_dog_from_favorites",
"add_dog_to_favorites"
);
jQuery("#favorite-toggle").attr("href", newLinkText);
} else {
alert("Your like could not be added");
}
},
});
});
});
Answer
Solution:
According to your js code, on page load you "favorite" the page, and onclick
you "unfavorite" it. Your page load AJAX call should check whether that page has been favorited, and update the state. Then, onclick
your AJAX should check whether the user favorited or unfavorited and make the appropriate call (remove_dog_from_favorites / add_dog_to_favorites):
type: "post",
dataType: "json",
url: myAjax.ajaxurl,
data: {
action: favoritesAction,
post_id: post_id,
nonce: nonce,
user_id: user_id,
}
Share solution ↓
Additional Information:
Link To Answer People are also looking for solutions of the problem: foreach() argument must be of type array|object, null given
Didn't find the answer?
Our community is visited by hundreds of web development professionals every day. Ask your question and get a quick answer for free.
Similar questions
Find the answer in similar questions on our website.
Write quick answer
Do you know the answer to this question? Write a quick response to it. With your help, we will make our community stronger.