Registers a Custom Post Type A hidden post type (snn_like
) is created to store like counts.
Retrieves or Creates a Like Record When a like button is clicked, the system checks if a record for the given identifier exists.
If not, it creates one and initializes the like count to zero.
Handles Like Requests via REST API A custom REST API endpoint (snn/v1/like
) is registered to process like
The SNN Like Button Shortcode generates a simple thumbs-up button that allows users to like a specific item (e.g., a post, product, or any unique entity).
By the way this will work fine for any wordpress theme or builder ..etc doesnt matter the system.
/** * SNN Like Button Shortcode * * This code registers a hidden custom post type for storing like counts, * sets up a REST API endpoint to handle AJAX like requests, * and defines a shortcode * that outputs a thumbs‑up button. * * Place this code in your theme’s functions.php file. */ /* ============================================================================ 1. Register Custom Post Type for Storing Likes ============================================================================ */ add_action( 'init', 'snn_register_like_post_type' ); function snn_register_like_post_type() { $args = [ 'public' => false, 'show_ui' => false, 'capability_type' => 'post', 'supports' => [ 'title' ], ]; register_post_type( 'snn_like', $args ); } /* ============================================================================ 2. Helper Functions to Retrieve/Create a Like Record and Get the Count ============================================================================ */ /** * Retrieve (or create) the like record (post) for a given identifier. * * @param string $identifier Sanitized identifier. * @return WP_Post|false */ function snn_get_like_post( $identifier ) { // Try to find the post by its slug. $post = get_page_by_path( $identifier, OBJECT, 'snn_like' ); if ( ! $post ) { // Create a new post if not found. $post_id = wp_insert_post( [ 'post_title' => $identifier, 'post_name' => $identifier, 'post_type' => 'snn_like', 'post_status' => 'private', ] ); if ( ! is_wp_error( $post_id ) ) { $post = get_post( $post_id ); update_post_meta( $post->ID, '_snn_like_count', 0 ); update_post_meta( $post->ID, '_snn_like_ips', [] ); } } return $post; } /** * Get the current like count for a given identifier. * * @param string $identifier * @return int */ function snn_get_like_count( $identifier ) { $post = snn_get_like_post( $identifier ); $count = get_post_meta( $post->ID, '_snn_like_count', true ); return $count ? intval( $count ) : 0; } /* ============================================================================ 3. REST API Endpoint to Handle Like Requests ============================================================================ */ add_action( 'rest_api_init', function() { register_rest_route( 'snn/v1', '/like', [ 'methods' => 'POST', 'callback' => 'snn_handle_like', 'permission_callback' => '__return_true', ] ); } ); function snn_handle_like( WP_REST_Request $request ) { // Sanitize and validate the identifier. $identifier = $request->get_param( 'identifier' ); $identifier = sanitize_key( $identifier ); if ( empty( $identifier ) ) { return new WP_Error( 'no_identifier', 'No identifier provided', [ 'status' => 400 ] ); } // Get the visitor’s IP address. $user_ip = $_SERVER['REMOTE_ADDR']; // Retrieve (or create) the like record. $post = snn_get_like_post( $identifier ); if ( ! $post ) { return new WP_Error( 'post_error', 'Could not create like record', [ 'status' => 500 ] ); } // Retrieve saved IPs for this like. $ips = get_post_meta( $post->ID, '_snn_like_ips', true ); if ( ! is_array( $ips ) ) { $ips = []; } // If this IP already liked this identifier, do nothing. if ( in_array( $user_ip, $ips, true ) ) { return rest_ensure_response( [ 'count' => intval( get_post_meta( $post->ID, '_snn_like_count', true ) ) ] ); } // Increment the like count. $count = intval( get_post_meta( $post->ID, '_snn_like_count', true ) ); $count++; update_post_meta( $post->ID, '_snn_like_count', $count ); // Save the IP. $ips[] = $user_ip; update_post_meta( $post->ID, '_snn_like_ips', $ips ); return rest_ensure_response( [ 'count' => $count ] ); } /* ============================================================================ 4. Shortcode to Output the Like Button ============================================================================ */ /** * Shortcode: * * @param array $atts Shortcode attributes. * @return string HTML for the like button. */ function snn_like_button_shortcode( $atts ) { $atts = shortcode_atts( [ 'identifier' => '', ], $atts, 'snn_like_button' ); $identifier = sanitize_key( $atts['identifier'] ); if ( empty( $identifier ) ) { return 'Identifier missing'; } $like_count = snn_get_like_count( $identifier ); $button = '<button class="snn-like-button" data-identifier="' . esc_attr( $identifier ) . '" onclick="snn_likeButton(this)">👍' . esc_html( $like_count ) . '</button>'; return $button; } add_shortcode( 'snn_like_button', 'snn_like_button_shortcode' ); /* ============================================================================ 5. Inline JavaScript for AJAX Handling (No External JS File) ============================================================================ */ add_action( 'wp_footer', 'snn_inline_like_script' ); function snn_inline_like_script() { ?> <script type="text/javascript"> // Define the global object with the REST API endpoint and nonce. var snnLike = { endpoint: "<?php echo esc_url( rest_url( 'snn/v1/like' ) ); ?>", nonce: "<?php echo wp_create_nonce( 'wp_rest' ); ?>" }; function snn_likeButton(el) { var identifier = el.getAttribute('data-identifier'); // Prevent multiple rapid clicks. if ( el.getAttribute('data-processing') === 'true' ) { return; } el.setAttribute('data-processing', 'true'); var xhr = new XMLHttpRequest(); xhr.open("POST", snnLike.endpoint, true); xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); xhr.onload = function() { if ( xhr.status >= 200 && xhr.status < 300 ) { var response = JSON.parse(xhr.responseText); if ( response.count !== undefined ) { el.innerHTML = '👍' + response.count; } } el.removeAttribute('data-processing'); }; xhr.onerror = function() { el.removeAttribute('data-processing'); }; xhr.send(JSON.stringify({ identifier: identifier, nonce: snnLike.nonce })); } </script> <?php }