diff --git a/README.md b/README.md index da721f8..14931ff 100644 --- a/README.md +++ b/README.md @@ -5,18 +5,21 @@ A simple and efficient post like system for WordPress. this post on Sven Hofmann's site for more information. +Originally, this system utilized Font Awesome for the heart and gear icons. The Font Awesome version is still available in the vendor folder for those who are already using Font Awesome in their theme. +

Four Steps to Glory

    -
  1. Add the styles from like-styles.css to your theme's main stylesheet.
  2. -
  3. Add post-like.js to your theme's js folder (if it exists). If there is no js folder, create one and add post-like.js to it.
  4. +
  5. Add the CSS to your theme's main stylesheet.
  6. +
  7. Add post-like.min.js to your theme's js folder (if it exists). If there is no js folder at your theme's root level, create one and add post-like.min.js to it.
  8. +
  9. Add all the fonts to your theme's fonts folder (if it exists). If there is no fonts folder at your theme's root level, create one and add all the fonts to it.
  10. Add the contents of post-like.php to your theme's functions.php file.
  11. Implement the button by doing one of the following:
      -
    1. Add the button function ( echo getPostLikeLink( get_the_ID() ); ) to your theme's single page template (typically content-single.php)
    2. +
    3. Add the button function to your theme's single page template (typically content-single.php) — 
    4. Include the [jmliker] shortcode in your posts

Troubleshooting

-This plugin is pretty simple, and does not have many moving parts. Some folks have encountered issues with AJAX-loaded content, and others have had some trouble with plugin conflicts. Feel free to open an issue if your stuck, and I will do my best to help you solve it. +This post like system is pretty simple, and does not have many moving parts. Some folks have encountered issues with AJAX-loaded content, and others have had some trouble with plugin conflicts. Feel free to open an issue if your stuck, and I will do my best to help you solve it. diff --git a/css/like-styles.css b/css/like-styles.css new file mode 100644 index 0000000..de0d007 --- /dev/null +++ b/css/like-styles.css @@ -0,0 +1,94 @@ +/* Post Like System */ +@font-face { + font-family: "like_font"; + src: url("./fonts/like_font.eot"); + src: url("./fonts/like_font.eot?#iefix") format("embedded-opentype"), + url("./fonts/like_font.woff") format("woff"), + url("./fonts/like_font.ttf") format("truetype"), + url("./fonts/like_font.svg#like_font") format("svg"); + font-weight: normal; + font-style: normal; +} + +@media screen and (-webkit-min-device-pixel-ratio:0) { + @font-face { + font-family: "like_font"; + src: url("./fonts/like_font.svg#like_font") format("svg"); + } +} + +[data-icon]:before { content: attr(data-icon); } + +[data-icon]:before, +.icon-gear:before, +.icon-like:before, +.icon-unlike:before { + display: inline-block; + font-family: "like_font"; + font-style: normal; + font-weight: normal; + font-variant: normal; + line-height: 1; + text-decoration: inherit; + text-rendering: optimizeLegibility; + text-transform: none; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + font-smoothing: antialiased; +} + +.icon-like:before { content: "\f105"; } +.icon-unlike:before { content: "\f106"; } +.icon-gear:before { + content: "\f104"; + -webkit-animation: spin 2s infinite linear; + -moz-animation: spin 2s infinite linear; + -o-animation: spin 2s infinite linear; + animation: spin 2s infinite linear; +} + +@-moz-keyframes spin { + 0% { -moz-transform: rotate(0deg); } + 100% { -moz-transform: rotate(359deg); } +} + +@-webkit-keyframes spin { + 0% { -webkit-transform: rotate(0deg); } + 100% { -webkit-transform: rotate(359deg); } +} + +@-o-keyframes spin { + 0% { -o-transform: rotate(0deg); } + 100% { -o-transform: rotate(359deg); } +} + +@keyframes spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} + +a.jm-post-like { + font-weight: normal; + display: inline-block; + width: auto; + -moz-transition: all 0.3s ease-out 0.2s; + -webkit-transition: all 0.3s ease-out 0.2s; + -o-transition: all 0.3s ease-out 0.2s; +} + +a.jm-post-like.liked { color: #da1b1b; } + +a.jm-post-like:hover, +a.jm-post-like:active, +a.jm-post-like:focus, +a.liked:hover, +a.liked:active, +a.liked:focus { + color: #000; +} \ No newline at end of file diff --git a/css/like-styles.min.css b/css/like-styles.min.css new file mode 100644 index 0000000..b47c507 --- /dev/null +++ b/css/like-styles.min.css @@ -0,0 +1 @@ +@font-face{font-family:like_font;src:url(./fonts/like_font.eot);src:url(./fonts/like_font.eot?#iefix) format("embedded-opentype"),url(./fonts/like_font.woff) format("woff"),url(./fonts/like_font.ttf) format("truetype"),url(./fonts/like_font.svg#like_font) format("svg");font-weight:400;font-style:normal}@media screen and (-webkit-min-device-pixel-ratio:0){@font-face{font-family:like_font;src:url(./fonts/like_font.svg#like_font) format("svg")}}[data-icon]:before{content:attr(data-icon)}.icon-gear:before,.icon-like:before,.icon-unlike:before,[data-icon]:before{display:inline-block;font-family:like_font;font-style:normal;font-weight:400;font-variant:normal;line-height:1;text-decoration:inherit;text-rendering:optimizeLegibility;text-transform:none;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;font-smoothing:antialiased}.icon-like:before{content:"\f105"}.icon-unlike:before{content:"\f106"}.icon-gear:before{content:"\f104";-webkit-animation:spin 2s infinite linear;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;animation:spin 2s infinite linear}@-moz-keyframes spin{0%{-moz-transform:rotate(0deg)}100%{-moz-transform:rotate(359deg)}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg)}}@-o-keyframes spin{0%{-o-transform:rotate(0deg)}100%{-o-transform:rotate(359deg)}}@keyframes spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}100%{-webkit-transform:rotate(359deg);transform:rotate(359deg)}}a.jm-post-like{font-weight:400;display:inline-block;width:auto;-moz-transition:all .3s ease-out .2s;-webkit-transition:all .3s ease-out .2s;-o-transition:all .3s ease-out .2s}a.jm-post-like.liked{color:#da1b1b}a.jm-post-like:active,a.jm-post-like:focus,a.jm-post-like:hover,a.liked:active,a.liked:focus,a.liked:hover{color:#000} \ No newline at end of file diff --git a/fonts/like_font.eot b/fonts/like_font.eot new file mode 100644 index 0000000..f16f310 Binary files /dev/null and b/fonts/like_font.eot differ diff --git a/fonts/like_font.svg b/fonts/like_font.svg new file mode 100644 index 0000000..3bda639 --- /dev/null +++ b/fonts/like_font.svg @@ -0,0 +1,45 @@ + + + + + +Created by FontForge 20120731 at Thu Aug 7 16:56:22 2014 + By Mastersons +Created by Mastersons with FontForge 2.0 (http://fontforge.sf.net) + + + + + + + + + + diff --git a/fonts/like_font.ttf b/fonts/like_font.ttf new file mode 100644 index 0000000..1b667b8 Binary files /dev/null and b/fonts/like_font.ttf differ diff --git a/fonts/like_font.woff b/fonts/like_font.woff new file mode 100644 index 0000000..14343e4 Binary files /dev/null and b/fonts/like_font.woff differ diff --git a/js/post-like.js b/js/post-like.js new file mode 100755 index 0000000..876c19b --- /dev/null +++ b/js/post-like.js @@ -0,0 +1,32 @@ +jQuery(document).ready(function() { + jQuery('body').on('click','.jm-post-like',function(event){ + event.preventDefault(); + heart = jQuery(this); + post_id = heart.data("post_id"); + heart.html(""); + jQuery.ajax({ + type: "post", + url: ajax_var.url, + data: "action=jm-post-like&nonce="+ajax_var.nonce+"&jm_post_like=&post_id="+post_id, + success: function(count){ + if( count.indexOf( "already" ) !== -1 ) + { + var lecount = count.replace("already",""); + if (lecount === "0") + { + lecount = "Like"; + } + heart.prop('title', 'Like'); + heart.removeClass("liked"); + heart.html(" "+lecount); + } + else + { + heart.prop('title', 'Unlike'); + heart.addClass("liked"); + heart.html(" "+count); + } + } + }); + }); +}); diff --git a/js/post-like.min.js b/js/post-like.min.js new file mode 100644 index 0000000..319221d --- /dev/null +++ b/js/post-like.min.js @@ -0,0 +1 @@ +jQuery(document).ready(function(){jQuery('body').on('click','.jm-post-like',function(event){event.preventDefault();heart=jQuery(this);post_id=heart.data("post_id");heart.html("");jQuery.ajax({type:"post",url:ajax_var.url,data:"action=jm-post-like&nonce="+ajax_var.nonce+"&jm_post_like=&post_id="+post_id,success:function(count){if(count.indexOf("already")!==-1){var lecount=count.replace("already","");if(lecount==="0"){lecount="Like"}heart.prop('title','Like');heart.removeClass("liked");heart.html(" "+lecount)}else{heart.prop('title','Unlike');heart.addClass("liked");heart.html(" "+count)}}})})}); \ No newline at end of file diff --git a/post-like.php b/post-like.php index f5364eb..3b18f1b 100644 --- a/post-like.php +++ b/post-like.php @@ -2,7 +2,7 @@ /* Name: WordPress Post Like System Description: A simple and efficient post like system for WordPress. -Version: 0.3.3 +Version: 0.4 Author: Jon Masterson Author URI: http://jonmasterson.com/ @@ -27,7 +27,7 @@ * (1) Enqueue scripts for like system */ function like_scripts() { - wp_enqueue_script( 'jm_like_post', get_template_directory_uri().'/js/post-like.js', array('jquery'), '1.0', 1 ); + wp_enqueue_script( 'jm_like_post', get_template_directory_uri().'/js/post-like.min.js', array('jquery'), '1.0', 1 ); wp_localize_script( 'jm_like_post', 'ajax_var', array( 'url' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'ajax-nonce' ) @@ -37,16 +37,7 @@ function like_scripts() { add_action( 'init', 'like_scripts' ); /** - * (2) Add Fontawesome Icons - */ -function enqueue_icons () { - wp_register_style( 'icon-style', 'http://netdna.bootstrapcdn.com/font-awesome/4.0.0/css/font-awesome.css' ); - wp_enqueue_style( 'icon-style' ); -} -add_action( 'wp_enqueue_scripts', 'enqueue_icons' ); - -/** - * (3) Save like data + * (2) Save like data */ add_action( 'wp_ajax_nopriv_jm-post-like', 'jm_post_like' ); add_action( 'wp_ajax_jm-post-like', 'jm_post_like' ); @@ -141,7 +132,7 @@ function jm_post_like() { } /** - * (4) Test if user already liked post + * (3) Test if user already liked post */ function AlreadyLiked( $post_id ) { // test if user liked before if ( is_user_logged_in() ) { // user is logged in @@ -183,7 +174,7 @@ function AlreadyLiked( $post_id ) { // test if user liked before } /** - * (5) Front end button + * (4) Front end button */ function getPostLikeLink( $post_id ) { $like_count = get_post_meta( $post_id, "_post_like_count", true ); // get post likes @@ -191,18 +182,18 @@ function getPostLikeLink( $post_id ) { if ( AlreadyLiked( $post_id ) ) { $class = esc_attr( ' liked' ); $title = esc_attr( 'Unlike' ); - $heart = ''; + $heart = ''; } else { $class = esc_attr( '' ); $title = esc_attr( 'Like' ); - $heart = ''; + $heart = ''; } $output = ''.$heart.' '.$count.''; return $output; } /** - * (6) Retrieve User Likes and Show on Profile + * (5) Retrieve User Likes and Show on Profile */ add_action( 'show_user_profile', 'show_user_likes' ); add_action( 'edit_user_profile', 'show_user_likes' ); @@ -241,7 +232,7 @@ function show_user_likes( $user ) { ?>  ");jQuery.ajax({type:"post",url:ajax_var.url,data:"action=jm-post-like&nonce="+ajax_var.nonce+"&jm_post_like=&post_id="+post_id,success:function(count){if(count.indexOf("already")!==-1){var lecount=count.replace("already","");if(lecount==="0"){lecount="Like"}heart.prop('title','Like');heart.removeClass("liked");heart.html(" "+lecount)}else{heart.prop('title','Unlike');heart.addClass("liked");heart.html(" "+count)}}})})}); \ No newline at end of file diff --git a/vendor/fontawesome/post-like.php b/vendor/fontawesome/post-like.php new file mode 100755 index 0000000..7650e41 --- /dev/null +++ b/vendor/fontawesome/post-like.php @@ -0,0 +1,405 @@ +. +*/ + +/** + * (1) Enqueue scripts for like system + */ +function like_scripts() { + wp_enqueue_script( 'jm_like_post', get_template_directory_uri().'/js/post-like.min.js', array('jquery'), '1.0', 1 ); + wp_localize_script( 'jm_like_post', 'ajax_var', array( + 'url' => admin_url( 'admin-ajax.php' ), + 'nonce' => wp_create_nonce( 'ajax-nonce' ) + ) + ); +} +add_action( 'init', 'like_scripts' ); + +/** + * (2) Add Fontawesome Icons (optional, if not already added in theme) + * +function enqueue_icons () { + wp_register_style( 'icon-style', 'http://netdna.bootstrapcdn.com/font-awesome/4.0.0/css/font-awesome.css' ); + wp_enqueue_style( 'icon-style' ); +} +add_action( 'wp_enqueue_scripts', 'enqueue_icons' ); +*/ + +/** + * (3) Save like data + */ +add_action( 'wp_ajax_nopriv_jm-post-like', 'jm_post_like' ); +add_action( 'wp_ajax_jm-post-like', 'jm_post_like' ); +function jm_post_like() { + $nonce = $_POST['nonce']; + if ( ! wp_verify_nonce( $nonce, 'ajax-nonce' ) ) + die ( 'Nope!' ); + + if ( isset( $_POST['jm_post_like'] ) ) { + + $post_id = $_POST['post_id']; // post id + $post_like_count = get_post_meta( $post_id, "_post_like_count", true ); // post like count + + if ( is_user_logged_in() ) { // user is logged in + $user_id = get_current_user_id(); // current user + $meta_POSTS = get_user_option( "_liked_posts", $user_id ); // post ids from user meta + $meta_USERS = get_post_meta( $post_id, "_user_liked" ); // user ids from post meta + $liked_POSTS = NULL; // setup array variable + $liked_USERS = NULL; // setup array variable + + if ( count( $meta_POSTS ) != 0 ) { // meta exists, set up values + $liked_POSTS = $meta_POSTS; + } + + if ( !is_array( $liked_POSTS ) ) // make array just in case + $liked_POSTS = array(); + + if ( count( $meta_USERS ) != 0 ) { // meta exists, set up values + $liked_USERS = $meta_USERS[0]; + } + + if ( !is_array( $liked_USERS ) ) // make array just in case + $liked_USERS = array(); + + $liked_POSTS['post-'.$post_id] = $post_id; // Add post id to user meta array + $liked_USERS['user-'.$user_id] = $user_id; // add user id to post meta array + $user_likes = count( $liked_POSTS ); // count user likes + + if ( !AlreadyLiked( $post_id ) ) { // like the post + update_post_meta( $post_id, "_user_liked", $liked_USERS ); // Add user ID to post meta + update_post_meta( $post_id, "_post_like_count", ++$post_like_count ); // +1 count post meta + update_user_option( $user_id, "_liked_posts", $liked_POSTS ); // Add post ID to user meta + update_user_option( $user_id, "_user_like_count", $user_likes ); // +1 count user meta + echo $post_like_count; // update count on front end + + } else { // unlike the post + $pid_key = array_search( $post_id, $liked_POSTS ); // find the key + $uid_key = array_search( $user_id, $liked_USERS ); // find the key + unset( $liked_POSTS[$pid_key] ); // remove from array + unset( $liked_USERS[$uid_key] ); // remove from array + $user_likes = count( $liked_POSTS ); // recount user likes + update_post_meta( $post_id, "_user_liked", $liked_USERS ); // Remove user ID from post meta + update_post_meta($post_id, "_post_like_count", --$post_like_count ); // -1 count post meta + update_user_option( $user_id, "_liked_posts", $liked_POSTS ); // Remove post ID from user meta + update_user_option( $user_id, "_user_like_count", $user_likes ); // -1 count user meta + echo "already".$post_like_count; // update count on front end + + } + + } else { // user is not logged in (anonymous) + $ip = $_SERVER['REMOTE_ADDR']; // user IP address + $meta_IPS = get_post_meta( $post_id, "_user_IP" ); // stored IP addresses + $liked_IPS = NULL; // set up array variable + + if ( count( $meta_IPS ) != 0 ) { // meta exists, set up values + $liked_IPS = $meta_IPS[0]; + } + + if ( !is_array( $liked_IPS ) ) // make array just in case + $liked_IPS = array(); + + if ( !in_array( $ip, $liked_IPS ) ) // if IP not in array + $liked_IPS['ip-'.$ip] = $ip; // add IP to array + + if ( !AlreadyLiked( $post_id ) ) { // like the post + update_post_meta( $post_id, "_user_IP", $liked_IPS ); // Add user IP to post meta + update_post_meta( $post_id, "_post_like_count", ++$post_like_count ); // +1 count post meta + echo $post_like_count; // update count on front end + + } else { // unlike the post + $ip_key = array_search( $ip, $liked_IPS ); // find the key + unset( $liked_IPS[$ip_key] ); // remove from array + update_post_meta( $post_id, "_user_IP", $liked_IPS ); // Remove user IP from post meta + update_post_meta( $post_id, "_post_like_count", --$post_like_count ); // -1 count post meta + echo "already".$post_like_count; // update count on front end + + } + } + } + + exit; +} + +/** + * (4) Test if user already liked post + */ +function AlreadyLiked( $post_id ) { // test if user liked before + if ( is_user_logged_in() ) { // user is logged in + $user_id = get_current_user_id(); // current user + $meta_USERS = get_post_meta( $post_id, "_user_liked" ); // user ids from post meta + $liked_USERS = ""; // set up array variable + + if ( count( $meta_USERS ) != 0 ) { // meta exists, set up values + $liked_USERS = $meta_USERS[0]; + } + + if( !is_array( $liked_USERS ) ) // make array just in case + $liked_USERS = array(); + + if ( in_array( $user_id, $liked_USERS ) ) { // True if User ID in array + return true; + } + return false; + + } else { // user is anonymous, use IP address for voting + + $meta_IPS = get_post_meta( $post_id, "_user_IP" ); // get previously voted IP address + $ip = $_SERVER["REMOTE_ADDR"]; // Retrieve current user IP + $liked_IPS = ""; // set up array variable + + if ( count( $meta_IPS ) != 0 ) { // meta exists, set up values + $liked_IPS = $meta_IPS[0]; + } + + if ( !is_array( $liked_IPS ) ) // make array just in case + $liked_IPS = array(); + + if ( in_array( $ip, $liked_IPS ) ) { // True is IP in array + return true; + } + return false; + } + +} + +/** + * (5) Front end button + */ +function getPostLikeLink( $post_id ) { + $like_count = get_post_meta( $post_id, "_post_like_count", true ); // get post likes + $count = ( empty( $like_count ) || $like_count == "0" ) ? 'Like' : esc_attr( $like_count ); + if ( AlreadyLiked( $post_id ) ) { + $class = esc_attr( ' liked' ); + $title = esc_attr( 'Unlike' ); + $heart = ''; + } else { + $class = esc_attr( '' ); + $title = esc_attr( 'Like' ); + $heart = ''; + } + $output = ''.$heart.' '.$count.''; + return $output; +} + +/** + * (6) Retrieve User Likes and Show on Profile + */ +add_action( 'show_user_profile', 'show_user_likes' ); +add_action( 'edit_user_profile', 'show_user_likes' ); +function show_user_likes( $user ) { ?> + + + + + +
+ ID ); + if ( !empty( $user_likes ) && count( $user_likes ) > 0 ) { + $the_likes = $user_likes; + } else { + $the_likes = ''; + } + if ( !is_array( $the_likes ) ) + $the_likes = array(); + $count = count( $the_likes ); + $i=0; + if ( $count > 0 ) { + $like_list = ''; + echo "

\n"; + foreach ( $the_likes as $the_like ) { + $i++; + $like_list .= "" . get_the_title( $the_like ) . "\n"; + if ($count != $i) $like_list .= " · "; + else $like_list .= "

\n"; + } + echo $like_list; + } else { + echo "

" . _e( 'You don\'t like anything yet.' ) . "

\n"; + } ?> +
+ 0 ) { + $the_likes = $user_likes; + } else { + $the_likes = ''; + } + if ( !is_array( $the_likes ) ) + $the_likes = array(); + $count = count( $the_likes ); + if ( $count > 0 ) { + $limited_likes = array_slice( $the_likes, 0, 5 ); // this will limit the number of posts returned to 5 + $like_list .= "\n"; + } + echo $like_list; + } +} + +/** + * (9) Outputs a list of the 5 posts with the most user likes TODAY + * Markup assumes sidebar/widget usage + */ +function jm_most_popular_today() { + global $post; + $today = date('j'); + $year = date('Y'); + $args = array( + 'year' => $year, + 'day' => $today, + 'post_type' => array( 'post', 'enter-your-comma-separated-post-types-here' ), + 'meta_key' => '_post_like_count', + 'orderby' => 'meta_value_num', + 'order' => 'DESC', + 'posts_per_page' => 5 + ); + $pop_posts = new WP_Query( $args ); + if ( $pop_posts->have_posts() ) { + echo "\n"; + } + wp_reset_postdata(); +} + +/** + * (10) Outputs a list of the 5 posts with the most user likes for THIS MONTH + * Markup assumes sidebar/widget usage + */ +function jm_most_popular_month() { + global $post; + $month = date('m'); + $year = date('Y'); + $args = array( + 'year' => $year, + 'monthnum' => $month, + 'post_type' => array( 'post', 'enter-your-comma-separated-post-types-here' ), + 'meta_key' => '_post_like_count', + 'orderby' => 'meta_value_num', + 'order' => 'DESC', + 'posts_per_page' => 5 + ); + $pop_posts = new WP_Query( $args ); + if ( $pop_posts->have_posts() ) { + echo "\n"; + } + wp_reset_postdata(); +} + +/** + * (11) Outputs a list of the 5 posts with the most user likes for THIS WEEK + * Markup assumes sidebar/widget usage + */ +function jm_most_popular_week() { + global $post; + $week = date('W'); + $year = date('Y'); + $args = array( + 'year' => $year, + 'w' => $week, + 'post_type' => array( 'post', 'enter-your-comma-separated-post-types-here' ), + 'meta_key' => '_post_like_count', + 'orderby' => 'meta_value_num', + 'order' => 'DESC', + 'posts_per_page' => 5 + ); + $pop_posts = new WP_Query( $args ); + if ( $pop_posts->have_posts() ) { + echo "\n"; + } + wp_reset_postdata(); +} + +/** + * (12) Outputs a list of the 5 posts with the most user likes for ALL TIME + * Markup assumes sidebar/widget usage + */ +function jm_most_popular() { + global $post; + echo "\n"; +}