'Voting is disabled for visitors.' ] ) ); } // View only for closed topics $topic_id = bbp_get_reply_topic_id( $post_id ); $topic_status = get_post_status( $topic_id ); if ( $topic_status == 'closed' && forumax_get_opt( 'is_disabled_voting_closed_topics', false ) ) { die( json_encode( [ 'error' => 'Voting is disabled on closed topics.' ] ) ); } // View only for author of post if ( is_user_logged_in() && forumax_get_opt( 'is_disabled_voting_own_topic_reply', false ) && get_post_field( 'post_author', $post_id ) == get_current_user_ID() ) { die( json_encode( [ 'error' => 'Voting is disabled on for the author.' ] ) ); } // Direction $direction = (int) $_POST['direction']; $direction = in_array( $direction, [ 1, -1 ] ) ? $direction : 0; // Enforce 1 or -1 // Check if down votes are disabled if ( $direction === -1 && forumax_get_opt( 'is_down_votes_disabled', 0 ) != 1 ) { die( json_encode( [ 'error' => 'Down voting is disabled.' ] ) ); } // $voting_cookie = unserialize($_COOKIE['bbp_voting']); $voting_log = get_post_meta( $post_id, 'bbp_voting_log', true ); $voting_log = is_array( $voting_log ) ? $voting_log : []; // Set up new array // Use hashed IP for anonymous users (GDPR compliant - real IP is never stored) $identifier = is_user_logged_in() ? get_current_user_id() : forumax_get_hashed_ip(); $legacy_identifier = null; // Backward compatibility: Check for legacy raw IP entries (pre-2.3.1) // This allows migration from raw IP to hashed IP without losing vote history if ( ! is_user_logged_in() ) { $raw_ip = forumax_get_raw_ip(); if ( $raw_ip && array_key_exists( $raw_ip, $voting_log ) ) { $legacy_identifier = $raw_ip; } } $admin_bypass = current_user_can( 'administrator' ) && forumax_get_opt( 'is_admin_can_vote_unlimited', false ); $remove_vote = false; $reverse_vote = false; // Admin bypass skips the restriction checks if ( ! $admin_bypass ) { // Check for existing vote - first by new hashed identifier, then by legacy raw IP $check_identifier = array_key_exists( $identifier, $voting_log ) ? $identifier : $legacy_identifier; if ( $check_identifier && array_key_exists( $check_identifier, $voting_log ) ) { // Identifier found (either hashed or legacy) if ( $voting_log[ $check_identifier ] == $direction ) { // Voting again in the same direction $remove_vote = true; } elseif ( $voting_log[ $check_identifier ] == $direction * -1 ) { // Changing the vote in different direction $reverse_vote = true; } else { // Changing vote from 0 } // Migrate legacy raw IP to hashed IP (one-time migration per vote) if ( $legacy_identifier && $check_identifier === $legacy_identifier ) { $voting_log[ $identifier ] = $voting_log[ $legacy_identifier ]; unset( $voting_log[ $legacy_identifier ] ); update_post_meta( $post_id, 'bbp_voting_log', $voting_log ); } } } // All good, add the user's vote // But first get all the data $score = (int) get_post_meta( $post_id, 'bbp_voting_score', true ); $ups = $ups_og = (int) get_post_meta( $post_id, 'bbp_voting_ups', true ); $downs = $downs_og = (int) get_post_meta( $post_id, 'bbp_voting_downs', true ); if ( $direction > 0 ) { // Up vote if ( $remove_vote ) { $ups = $ups - 1; $score = $score - 1; } else { $ups = $ups + 1; $score = $score + 1; } if ( $reverse_vote ) { $downs = $downs + 1; $score = $score + 1; } } elseif ( $direction < 0 ) { // Down vote if ( $remove_vote ) { $downs = $downs + 1; $score = $score + 1; } else { $downs = $downs - 1; $score = $score - 1; } if ( $reverse_vote ) { $ups = $ups - 1; $score = $score - 1; } } // Update the score update_post_meta( $post_id, 'bbp_voting_score', $score ); // Update the ups and downs if needed if ( $ups !== $ups_og ) { update_post_meta( $post_id, 'bbp_voting_ups', $ups ); } if ( $downs !== $downs_og ) { update_post_meta( $post_id, 'bbp_voting_downs', $downs ); } // Hook for additional features like weighted score calculation do_action( 'bbp_voting_process_score_on_vote', $post_id, $ups, $downs ); // Log the user's ID or IP $real_direction = $remove_vote ? 0 : $direction; $voting_log[ $identifier ] = $real_direction; update_post_meta( $post_id, 'bbp_voting_log', $voting_log ); // Set the cookie // $voting_cookie[$post_id] = true; // setcookie('bbp_voting', serialize($voting_cookie), time() + (86400 * 30 * 365), '/'); do_action( 'bbp_voting_voted', $post_id, $real_direction, $score, $identifier ); echo json_encode( [ 'score' => $score, 'direction' => $real_direction, 'ups' => $ups, 'downs' => $downs, ] ); exit; }