0

Working on a "Like" vs "Dislike" for blog post in WordPress. While all is working fine, the intention here is to make it work for guests and logged in users, but more importantly; to only allow one click (Like or Dislike) per post from the same user (trying to understand if I can use WordPress sessions here?).

Idea:

Guest / registered and logged in user clicks on Like or Dislike = both button for that specific post are deactivated (cannot be clicked again). If the same user visits a different post on the same website where the user has not yet clicked any of the two buttons; they can click either Like or Dislike.

I hope I am being clear and that you all understand me. I'm looking for advice and code examples and what not as to how to achieve this.

As of now; a user (logged in or not) can click on Like or Dislike as many times as they want and the count just keeps on ticking -- which is NOT ideal.

This is the code I'm working on:

add_filter( 'the_content', 'post_likes' );
function post_likes( $content ) {

    // only on posts
    if ( is_singular( 'post' ) ) {
        
        ob_start();

        ?>
            <ul class="likes">

                <li class="likes__item likes__item--like">
                    <a href="<?php echo add_query_arg( 'post_action', 'like'); ?>">
                        Useful (<?php echo get_post_like_count('likes') ?>)
                    </a>
                </li>

                <li class="likes__item likes__item--dislike">
                    <a href="<?php echo add_query_arg('post_action', 'dislike'); ?>">
                        Dislike (<?php echo get_post_like_count('dislikes') ?>)
                    </a>
                </li>

            </ul>
        
        <?php

        $output = ob_get_clean();

        return $output . $content;
    
    } else {
    
        return $content;
    }
}

function get_post_like_count( $type = 'likes' ) {

    // like or dislike count
    $current_count = get_post_meta( get_the_id(), $type, true );

    return ( $current_count ? $current_count : 0 );
}


add_action( 'template_redirect', 'process_post_like_click' );
function process_post_like_click() {

    $processed_like = false;
    $redirect = false;

    // Check if like or dislike
    if ( is_singular( 'post' ) ) {
        
        if ( isset( $_GET['post_action'] ) ) {
            
            if ( $_GET['post_action'] == 'like' ) {
            
                // Like
                $like_count = get_post_meta( get_the_id(), 'likes', true );

                if ( $like_count ) {
                    $like_count = $like_count + 1;
            
                } else {
                    $like_count = 1;
                }

                $processed_like = update_post_meta( get_the_id(), 'likes', $like_count );
            
            } elseif ( $_GET['post_action'] == 'dislike' ) {

                // Dislike
                $dislike_count = get_post_meta( get_the_id(), 'dislikes', true );

                if ( $dislike_count ) {
                    $dislike_count = $dislike_count + 1;
            
                } else {
                    $dislike_count = 1;
                }

                $processed_like = update_post_meta( get_the_id(), 'dislikes', $dislike_count );
            }

            if ( $processed_like ) {
                $redirect = get_the_permalink();
                
                // how do I deactivate both buttons on this post while keping them intact on other posts?

            }
        }
    }

    // redirect (refresh)
    if ( $redirect ) {
        wp_redirect( $redirect );
        die;
    }
}

Thanks all!

7
  • WordPress sessions do not exists, but as you know there are users and they can be logged in or not - but as you want something that is available to all users, you should probably ignore login status and work on something else, such as IP address, to give a unique reference to each user - you could save an array of data in a post_meta field with IP and vote_type and use this to hide / show UI and show totals.
    – Q Studio
    Commented Dec 27, 2020 at 14:04
  • What I mean is this: developer.wordpress.org/reference/functions/… Or a PHP session. Commented Dec 27, 2020 at 14:08
  • Both are unreliable and might change - same for IP - same for a cookie.. you just have to decide which is best for your use-case and available ( some hosts do not support PHP sessions )
    – Q Studio
    Commented Dec 27, 2020 at 14:09
  • 1
    I know, but we're stuck with what we got, right? I guess I'll go for logged in or not. Meaning; if not logged in; the user cannot click. Commented Dec 27, 2020 at 14:11
  • Right, or go with IP and make it available to everyone - as it's not really crucial data and this will increase usage.
    – Q Studio
    Commented Dec 27, 2020 at 14:12

1 Answer 1

0

Untested Pseudo-code examples, which you can expand to resolve the issues:

function get_the_user_ip() {

    if ( ! empty( $_SERVER['HTTP_CLIENT_IP'] ) ) {

        //check ip from share internet
        $ip = $_SERVER['HTTP_CLIENT_IP'];

    } elseif ( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) {

        // to check ip is pass from proxy
        $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];

    } else {

        $ip = $_SERVER['REMOTE_ADDR'];

    }

    return apply_filters( 'get_the_user_ip', $ip );

}

Then, you can store all data in a single post_meta field, you just need to structure your array correctly.

array(
    'like' => array(
        'ip1', 'ip2', 'ip3', 'etc'
    ),
    'dislike' => array(
        'ip4', 'ip5', 'ip6', 'etc'
    )
)

This way you can create a few helper functions ( or, better a class with some getter and setter methods ) to reference when loading the UI and when saving data.

function get_like_count( $type = 'like' ) {

    // get post meta ##
    $array = get_post_meta( get_the_ID(), 'post_meta_field' );

    // @todo -- validate it is an array and the requested key exists ##

    // return count ##
    return count( $array[ $type ] );

}
function set_like_count( $type = 'like' ) {

    // get post meta ##
    $array = get_post_meta( get_the_ID(), 'post_meta_field' );

    // @todo -- validate it is an array and the requested key exists ##

    // update count for post ##
    $array[ $type ][] = get_the_user_ip();

    // save ##
    update_post_meta( get_the_ID(), 'post_meta_field', $array );

}
/** check if the user IP is already stored for this post */
function has_liked() {

    // get post meta ##
    $array = get_post_meta( get_the_ID(), 'post_meta_field' );

    // @todo -- validate it is an array and the requested key exists ##

    // search the array for the IP value
    // this might need to search each array key if you want to know what action the user took ##
    return in_array( get_the_user_ip(), $array );

}
1
  • 1
    Nice. Thanks. I'll work on it from here. Commented Dec 27, 2020 at 14:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.