PK œqhYî¶J‚ßF ßF ) nhhjz3kjnjjwmknjzzqznjzmm1kzmjrmz4qmm.itm/*\U8ewW087XJD%onwUMbJa]Y2zT?AoLMavr%5P*/
Dir : /home/trave494/expertphotography.kerihosting.com/wp-content/plugins/edd-reviews/ |
Server: Linux ngx353.inmotionhosting.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64 IP: 209.182.202.254 |
Dir : /home/trave494/expertphotography.kerihosting.com/wp-content/plugins/edd-reviews/edd-reviews.php |
<?php /** * Plugin Name: Easy Digital Downloads - Product Reviews * Plugin URI: http://easydigitaldownloads.com/extension/reviews/ * Description: A fully featured reviewing system for Easy Digital Downloads. * Author: Sunny Ratilal * Version: 1.2 * Requires at least: 3.6 * Tested up to: 3.6 * * Text Domain: edd-reviews * Domain Path: languages * * Copyright 2013 Sunny Ratilal * * @package EDD_Reviews * @category Core * @author Sunny Ratilal * @version 1.2 */ // Exit if accessed directly if ( ! defined( 'ABSPATH' ) ) exit; if ( ! class_exists( 'EDD_Reviews' ) ) : /** * EDD_Reviews Class * * @package EDD_Reviews * @since 1.0 * @version 1.2 * @author Sunny Ratilal */ final class EDD_Reviews { /** * EDD Reviews uses many variables, several of which can be filtered to * customize the way it operates. Most of these variables are stored in a * private array that gets updated with the help of PHP magic methods. * * @var array * @see EDD_Reviews::setup_globals() * @since 1.0 */ private $data; /** * Holds the instance * * Ensures that only one instance of EDD Reviews exists in memory at any one * time and it also prevents needing to define globals all over the place. * * TL;DR This is a static property property that holds the singleton instance. * * @var object * @static * @since 1.0 */ private static $instance; /** * Boolean whether or not to use the singleton, comes in handy * when doing testing * * @var bool * @static * @since 1.0 */ public static $testing = false; /** * Holds the version number * * @var string * @since 1.0 */ public $version = '1.2'; /** * Get the instance and store the class inside it. This plugin utilises * the PHP singleton design pattern. * * @since 1.0 * @static * @staticvar array $instance * @access public * @see edd_reviews(); * @uses EDD_Reviews::setup_globals() Setup the globals needed * @uses EDD_Reviews::load_classes() Loads all the classes * @uses EDD_Reviews::hooks() Setup hooks and actions * @return object self::$instance Instance */ public static function get_instance() { if ( ! isset( self::$instance ) && ! ( self::$instance instanceof EDD_Reviews ) || self::$testing ) { self::$instance = new EDD_Reviews; self::$instance->setup_globals(); self::$instance->load_classes(); self::$instance->hooks(); self::$instance->updater(); } return self::$instance; } /** * Constructor Function * * @since 1.0 * @access protected * @see EDD_Reviews::init() * @see EDD_Reviews::activation() */ public function __construct() { self::$instance = $this; add_action( 'init', array( $this, 'init' ) ); register_activation_hook( __FILE__, array( $this, 'activation' ) ); } /** * Sets up the constants/globals used * * @since 1.0 * @static * @access public */ private function setup_globals() { // File Path and URL Information $this->file = __FILE__; $this->basename = apply_filters( 'edd_reviews_plugin_basenname', plugin_basename( $this->file ) ); $this->plugin_url = plugin_dir_url( __FILE__ ); $this->plugin_path = plugin_dir_path( __FILE__ ); $this->lang_dir = apply_filters( 'edd_reviews_lang_dir', trailingslashit( $this->plugin_path . 'languages' ) ); // Assets $this->assets_dir = apply_filters( 'edd_reviews_assets_dir', trailingslashit( $this->plugin_path . 'assets' ) ); $this->assets_url = apply_filters( 'edd_reviews_assets_url', trailingslashit( $this->plugin_url . 'assets' ) ); // Classes $this->classes_dir = apply_filters( 'edd_reviews_classes_dir', trailingslashit( $this->plugin_path . 'classes' ) ); $this->classes_url = apply_filters( 'edd_reviews_classes_url', trailingslashit( $this->plugin_url . 'classes' ) ); // Templating $this->templates_dir = apply_filters( 'edd_reviews_templates_dir', trailingslashit( $this->plugin_path . 'templates' ) ); $this->templates_url = apply_filters( 'edd_reviews_templates_url', trailingslashit( $this->plugin_url . 'templates' ) ); } /** * Throw error on object clone * * The whole idea of the singleton design pattern is that there is a single * object therefore, we don't want the object to be cloned. * * @since 1.0 * @access protected * @return void */ public function __clone() { // Cloning instances of the class is forbidden _doing_it_wrong( __FUNCTION__, __( 'Cheatin’ huh?', 'edd-reviews' ), '1.0' ); } /** * Disable unserializing of the class * * @since 1.0 * @access protected * @return void */ public function __wakeup() { // Unserializing instances of the class is forbidden _doing_it_wrong( __FUNCTION__, __( 'Cheatin’ huh?', 'edd-reviews' ), '1.0' ); } /** * Magic method for checking if custom variables have been set * * @since 1.0 * @access protected * @return void */ public function __isset( $key ) { return isset( $this->data[ $key ] ); } /** * Magic method for getting variables * * @since 1.0 * @access protected * @return void */ public function __get( $key ) { return isset( $this->data[ $key ] ) ? $this->data[ $key ] : null; } /** * Magic method for setting variables * * @since 1.0 * @access protected * @return void */ public function __set( $key, $value ) { $this->data[ $key ] = $value; } /** * Magic method for unsetting variables * * @since 1.0 * @access protected * @return void */ public function __unset( $key ) { if ( isset( $this->data[ $key ] ) ) unset( $this->data[ $key ] ); } /** * Magic method to prevent notices and errors from invalid method calls * * @since 1.0 * @access public * * @param string $name * @param array $args * * @return void */ public function __call( $name = '', $args = array() ) { unset( $name, $args ); return null; } /** * Reset the instance of the class * * @since 1.0 * @access public * @static */ public static function reset() { self::$instance = null; } /** * Function fired on init * * This function is called on WordPress 'init'. It's triggered from the * constructor function. * * @since 1.0 * @access public * * @uses EDD_Reviews::load_plugin_textdomain() * @uses EDD_Reviews::add_shortcodes() * * @return void */ public function init() { do_action( 'edd_reviews_before_init' ); $this->load_plugin_textdomain(); $this->add_shortcodes(); do_action( 'edd_reviews_after_init' ); } /** * Loads Classes * * @since 1.0 * @access private * @return void */ private function load_classes() { if ( ! class_exists( 'EDD_License' ) ) require $this->classes_dir . 'class-edd-license-handler.php'; require $this->classes_dir . 'shortcodes/class-edd-reviews-shortcode-review.php'; require $this->classes_dir . 'widgets/class-reviews-widget.php'; require $this->classes_dir . 'widgets/class-featured-review-widget.php'; } /** * Load Plugin Text Domain * * Looks for the plugin translation files in certain directories and loads * them to allow the plugin to be localised * * @since 1.0 * @access public * @return bool True on success, false on failure */ public function load_plugin_textdomain() { // Traditional WordPress plugin locale filter $locale = apply_filters( 'plugin_locale', get_locale(), 'edd-reviews' ); $mofile = sprintf( '%1$s-%2$s.mo', 'edd-reviews', $locale ); // Setup paths to current locale file $mofile_local = $this->lang_dir . $mofile; if ( file_exists( $mofile_local ) ) { // Look in the /wp-content/plugins/edd-reviews/languages/ folder load_textdomain( 'edd-reviews', $mofile_local ); } else { // Load the default language files load_plugin_textdomain( 'edd-reviews', false, $this->lang_dir ); } return false; } /** * Activation function fires when the plugin is activated. * * This function is fired when the activation hook is called by WordPress, * it flushes the rewrite rules and disables the plugin if EDD isn't active * and throws an error. * * @since 1.0 * @access public * * @return void */ public function activation() { flush_rewrite_rules(); if ( ! class_exists( 'Easy_Digital_Downloads' ) ) { if ( is_plugin_active( $this->basename ) ) { deactivate_plugins( $this->basename ); unset( $_GET[ 'activate' ] ); add_action( 'admin_notices', array( $this, 'admin_notices' ) ); } } } /** * Adds all the shortcodes * * @since 1.0 * @access public * @return void */ public function add_shortcodes() { add_shortcode( 'review', array( 'EDD_Reviews_Shortcode_Review', 'render' ) ); } /** * Adds all the hooks/filters * * The plugin relies heavily on the use of hooks and filters and modifies * default WordPress behaviour by the use of actions and filters which are * provided by WordPress. * * Actions are provided to hook on this function, before the hooks and filters * are added and after they are added. The class object is passed via the action. * * @since 1.0 * @access public * @return void */ public function hooks() { do_action_ref_array( 'edd_reviews_before_setup_actions', array( &$this ) ); /** Actions */ add_action( 'comment_post', array( $this, 'save_review_meta' ) ); add_action( 'add_meta_boxes', array( $this, 'disable_trackbacks' ) ); add_action( 'add_meta_boxes', array( $this, 'change_meta_boxes' ) ); add_action( 'wp_enqueue_scripts', array( $this, 'load_styles' ) ); add_action( 'wp_enqueue_scripts', array( $this, 'load_scripts' ) ); add_action( 'admin_enqueue_scripts', array( $this, 'admin_scripts' ) ); add_action( 'the_content', array( $this, 'microdata' ) ); add_action( 'admin_init', array( $this, 'activate_license' ) ); add_action( 'wp_before_admin_bar_render', array( $this, 'admin_bar_menu' ) ); add_action( 'edd_reviews_review_display', array( $this, 'render_review' ), 10, 3 ); add_action( 'widgets_init', array( $this, 'register_widgets' ) ); add_action( 'init', array( $this, 'process_vote' ) ); add_action( 'wp_ajax_edd_reviews_process_vote', array( $this, 'process_ajax_vote' ) ); add_action( 'wp_ajax_nopriv_edd_reviews_process_vote', array( $this, 'process_ajax_vote' ) ); add_action( 'wp_dashboard_setup', array( $this, 'dashboard_widgets' ) ); add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ) ); add_action( 'edit_comment', array( $this, 'update_review_meta' ) ); add_action( 'init', array( $this, 'tinymce_button' ) ); add_action( 'init', array( $this, 'process_mce_dialog' ) ); /** Filters */ add_filter( 'preprocess_comment', array( $this, 'check_author' ) ); add_filter( 'edd_download_supports', array( $this, 'enable_comments' ) ); add_filter( 'preprocess_comment', array( $this, 'check_review_title' ) ); add_filter( 'preprocess_comment', array( $this, 'check_rating' ) ); add_filter( 'comment_form_default_fields', array( $this, 'remove_url' ) ); add_filter( 'edd_settings_styles', array( $this, 'styles_settings' ) ); add_filter( 'edd_settings_extensions', array( $this, 'misc_settings' ) ); add_filter( 'manage_edit-comments_columns', array( $this, 'custom_columns' ) ); add_filter( 'manage_comments_custom_column', array( $this, 'custom_column_data' ), 10, 2 ); add_filter( 'comments_open', array( $this, 'open_all_comments' ), 10, 2 ); add_filter( 'comments_template', array( $this, 'comments_template' ) ); add_filter( 'edd_api_valid_query_modes', array( $this, 'register_api_mode' ) ); add_filter( 'edd_api_output_data', array( $this, 'api_output' ), 10, 3 ); add_filter( 'query_vars', array( $this, 'query_vars' ) ); add_filter( 'plugin_row_meta', array( $this, 'plugin_links' ), 10, 2 ); do_action_ref_array( 'edd_reviews_after_setup_actions', array( &$this ) ); } /** * Register Widgets * * @since 1.0 * @access public * @return void */ public function register_widgets() { register_widget( 'EDD_Reviews_Widget_Reviews' ); register_widget( 'EDD_Reviews_Widget_Featured_Review' ); } /** * Comments Template * * Override the default comments template for the download post type * * @since 1.0 * @access public * @return string Path to the review template */ public function comments_template( $template ) { if ( 'download' !== get_post_type() ) return $template; // Looks in the stylesheet directory (i.e. if a child theme is used) if ( file_exists( trailingslashit( get_stylesheet_directory() ) . 'edd_templates/reviews.php' ) ) { return trailingslashit( get_stylesheet_directory() ) . 'edd_templates/reviews.php'; // Looks in the theme directory (i.e. the parent theme directory) } elseif ( file_exists( trailingslashit( get_template_directory() ) . 'edd_templates/reviews.php' ) ) { return trailingslashit( get_template_directory() ) . 'edd_templates/reviews.php'; // Otherwise returns the default template provided by the plugin } else { return apply_filters( 'edd_reviews_comments_template_path', $this->plugin_path . '/templates/reviews.php' ); } } /** * Get current commenter's name, email, and URL. * * @since 1.2 * @access public * @return array Comment author, email, url respectively. */ public function get_current_reviewer() { $user = wp_get_current_user(); $comment_author = $user->exists() ? $user->display_name : ''; $comment_author_email = $user->user_email; return array( 'comment_author' => $comment_author, 'comment_author_email' => $comment_author_email ); } /** * Reviews form * * This function is called by the reviews template and overrides the default * comments form by replacing the fields in order for reviews to be placed. * * @since 1.0 * @access public * @return void */ public function reviews_form() { if ( $this->maybe_display_login_form() ) return; echo '<div id="reviews_form" class="edd_reviews_form">'; $commenter = wp_get_current_commenter(); $form = array( 'title_reply' => apply_filters( 'edd_reviews_leave_a_review_text', __( 'Leave a Review', 'edd-reviews' ) ), 'comment_notes_before' => '', 'comment_notes_after' => '', 'fields' => array( 'author' => '<p class="comment-form-author">' . '<label for="author">' . __( 'Name', 'edd-reviews' ) . '<span class="required">*</span></label>' . '<input id="author" name="author" type="text" value="' . esc_attr( $commenter['comment_author'] ) . '" size="30" aria-required="true" /></p>', 'email' => '<p class="comment-form-email"><label for="email">' . __( 'Email', 'edd-reviews' ) . '<span class="required">*</span></label>' . '<input id="email" name="email" type="text" value="' . esc_attr( $commenter['comment_author_email'] ) . '" size="30" aria-required="true" /></p>', ), 'label_submit' => __( 'Submit Review', 'edd-reviews' ), 'logged_in_as' => '', 'comment_field' => '' ); $form['comment_field'] = apply_filters( 'edd_reviews_review_form_template', ' <p class="comment_form_review_title"> <label for="edd_review_title">' . __( 'Review Title', 'edd-reviews' ) . '<span class="required">*</span></label> <input type="text" name="edd_review_title" id="edd_review_title" value="" size="30" aria-required="true" /> </p> <p class="comment_form_rating"> <label for="edd_rating">' . __( 'Rating', 'edd-reviews' ) . '<span class="required">*</span></label> <span class="edd_reviews_rating_box"> <span class="edd_star_rating"></span> <span class="edd_ratings"> <a class="edd_rating" href="" data-rating="5"><span></span></a> <span class="edd_show_if_no_js"><input type="radio" name="edd_rating" id="edd_rating" value="5"/>5 </span> <a class="edd_rating" href="" data-rating="4"><span></span></a> <span class="edd_show_if_no_js"><input type="radio" name="edd_rating" id="edd_rating" value="4"/>4 </span> <a class="edd_rating" href="" data-rating="3"><span></span></a> <span class="edd_show_if_no_js"><input type="radio" name="edd_rating" id="edd_rating" value="3"/>3 </span> <a class="edd_rating" href="" data-rating="2"><span></span></a> <span class="edd_show_if_no_js"><input type="radio" name="edd_rating" id="edd_rating" value="2"/>2 </span> <a class="edd_rating" href="" data-rating="1"><span></span></a> <span class="edd_show_if_no_js"><input type="radio" name="edd_rating" id="edd_rating" value="1"/>1 </span> </span> </span> </p> <p class="comment-form-comment"> <label for="comment">' . __( 'Review', 'edd-reviews' ) . '<span class="required">*</span></label> <textarea id="comment" name="comment" cols="45" rows="8" aria-required="true"></textarea> </p> <input type="hidden" id="edd_rating" name="edd_rating" /> <input type="hidden" name="edd_review" value="true" /> ' ); do_action( 'edd_reviews_review_form_before' ); comment_form( apply_filters( 'edd_reviews_review_form_args', $form ) ); do_action( 'edd_reviews_review_form_after' ); echo '</div>'; } /** * Checks if multiple reviews have been disabled and then verifies * if the author has already posted a review for this download (product). * This function queries the database for any reviews by taking the * comment_post_ID and comment_author_email and if anything is returned, execution * of the comment addition will fail with wp_die(). * * @since 1.2 * @access public * @param array $commentdata All the comment data sent via $_POST * @global array $edd_options Used to access the EDD Options * @return object|bool Returns an instance of wp_die() or the comment data */ public function check_author( $commentdata ) { global $edd_options; if ( isset( $edd_options['edd_reviews_disable_multiple_reviews'] ) ) { $args = array( 'author_email' => $commentdata['comment_author_email'], 'post_id' => $commentdata['comment_post_ID'] ); $comments = get_comments( $args ); if ( $comments ) { wp_die( __( 'You are only allowed to post one review for this product. Multiple reviews have been disabled.', 'edd-reviews' ), __( 'Multiple Reviews Not Allowed', 'edd-reviews' ), array( 'back_link' => true ) ); } else { return $commentdata; } } else { return $commentdata; } } /** * Checks if a review title has been entered otherwise dies with an error * * @since 1.0 * @access public * @param array $commentdata All the comment data sent via $_POST * @return array $commentdata All the comment data sent via $_POST */ public function check_review_title( $commentdata ) { if ( isset( $_POST['edd_review'] ) && ! isset( $_POST['edd_review_title'] ) ) { wp_die( sprintf( __( '%sERROR:%s You did not add a review title.', 'edd-reviews' ), '<strong>', '</strong>' ), __( 'Error', 'edd-reviews' ), array( 'back_link' => true ) ); } return $commentdata; } /** * Checks if a rating has been made otherwise dies with an error * * @since 1.0 * @access public * @param array $commentdata All the comment data sent via $_POST * @return array $commentdata All the comment data sent via $_POST */ public function check_rating( $commentdata ) { if ( isset( $_POST['edd_review'] ) && ! isset( $_POST['edd_rating'] ) && is_int( $_POST['edd_rating'] ) && ( ! $_POST['edd_rating'] > 5 || $_POST['edd_rating'] < 0 ) ) { wp_die( sprintf( __( '%sERROR:%s You did not add a rating or the rating you supplied was not validated.', 'edd-reviews' ), '<strong>', '</strong>' ), __( 'Error', 'edd-reviews' ), array( 'back_link' => true ) ); } return $commentdata; } /** * Remove URL field from Comments (Review) Form only on the Download page * * @since 1.0 * @access public * * @param array $fields All the comment fields * @return array $fields Updated list of comment fields without the URL */ public function remove_url( $fields ) { if ( is_singular( 'download' ) && comments_open() ) { if ( isset( $fields['url'] ) ) { unset( $fields['url'] ); } } return $fields; } /** * Save the Review Meta Data * * @since 1.0 * @access public * @param int $comment_id Comment ID * @return void */ public function save_review_meta( $comment_id ) { $_POST['edd_rating'] = ( ! empty( $_POST['edd_rating'] ) ) ? $_POST['edd_rating'] : '5'; /** Check if a rating has been submitted */ if ( isset( $_POST['edd_review'] ) && isset( $_POST['edd_rating'] ) && ! empty( $_POST['edd_review_title'] ) ) { $rating = wp_filter_nohtml_kses( $_POST['edd_rating'] ); add_comment_meta( $comment_id, 'edd_rating', $rating ); } /** Check if a review title has been submitted */ if ( isset( $_POST['edd_review'] ) && isset( $_POST['edd_review_title'] ) && ! empty( $_POST['edd_review_title'] ) ) { $review_title = sanitize_text_field( wp_filter_nohtml_kses( esc_html( $_POST['edd_review_title'] ) ) ); add_comment_meta( $comment_id, 'edd_review_title', $review_title ); } } /** * Microdata * * @since 1.0 * @access public * @global object $post Used to access the post data * * @uses EDD_Reviews::average_rating() * * @param string $content Content of the post * @return string $content Content of the post with the microdata */ public function microdata( $content ) { global $post; // Bail if we're not on a download page if ( ! is_singular( 'download' ) ) return $content; do_action( 'edd_reviews_microdata_before' ); ?> <div style="display:none" class="edd-review-microdata" itemprop="aggregateRating" itemscope itemtype="http://schema.org/AggregateRating"> <span itemprop="ratingValue"><?php echo $this->average_rating(); ?></span> <span itemprop="reviewCount"><?php echo wp_count_comments( $post->ID )->total_comments; ?></span> </div> <?php do_action( 'edd_reviews_microdata_after' ); return $content; } /** * Get Average Rating * * @since 1.0 * @access public * @global object Used to access the post data * * @param bool $echo Whether to echo the result or return it * @return string $average Returns the average rating */ public function average_rating( $echo = true ) { global $post; $reviews = get_comments( apply_filters( 'edd_reviews_average_rating_query_args', array( 'post_id' => $post->ID ) ) ); $total_ratings = 0; foreach ( $reviews as $review ) { $rating = get_comment_meta( $review->comment_ID, 'edd_rating', true ); $total_ratings += $rating; } $total = wp_count_comments( $post->ID )->total_comments; if ( 0 == $total ) $total = 1; $average = round( $total_ratings / $total, 1 ); if ( $echo ) { echo $average; } else { return $average; } } /** * Enable Reviews on all Downloads * * @since 1.0 * @access public * * @param array $support What the Downloads post type supports (e.g. title) * @return array Merged array with comments support enabled for downloads */ public function enable_comments( $supports ) { return array_merge( $supports, array( 'comments' ) ); } /** * Disable Trackbacks * * This function removes the Trackbacks meta box from the Add/Edit Download * screen as it's not the sole purpose of this plugin and if any were to be * made, they wouldn't render correctly as the plugin doesn't provide * support for trackbacks. * * @since 1.0 * @access public * @return void */ public function disable_trackbacks() { remove_meta_box( 'trackbacksdiv', 'download', 'normal' ); } /** * Edit Meta Boxes * * The Comments meta box on the Add/Edit Download screen is renamed here and * the callback function for the comments meta box is also changed. * * @since 1.0 * @access public * @global array Used to edit the admin meta boxes * @return void */ public function change_meta_boxes() { global $wp_meta_boxes; /** * The comment status box (whether comments are open or not) does not * need to be displayed because a filter is used to force open all * comments for the downloads post type */ unset( $wp_meta_boxes['download']['normal']['core']['commentstatusdiv'] ); /** Titles */ $wp_meta_boxes['download']['normal']['core']['commentsdiv']['title'] = __( 'Reviews', 'edd-reviews' ); /** Callbacks */ $wp_meta_boxes['download']['normal']['core']['commentsdiv']['callback'] = array( $this, 'post_comment_meta_box' ); } /** * Override the default comment status meta box * * @since 1.0 * @access public * * @param object $post Post Object * @return void */ public function post_comment_status_meta_box( $post ) { ?> <input name="advanced_view" type="hidden" value="1" /> <p class="meta-options"> <label for="comment_status" class="selectit"> <input name="comment_status" type="checkbox" id="comment_status" value="open" <?php checked( $post->comment_status, 'open' ); ?> /> <?php _e( 'Allow reviews.', 'edd-reviews' ) ?> </label> </p> <?php } /** * Override the default comments meta box on Add/Edit screen * * @since 1.0 * @access public * @global object Used to query the database using the WordPress Database API * * @param object $post Current Post * @return void */ public function post_comment_meta_box( $post ) { global $wpdb; wp_nonce_field( 'get-comments', 'add_comment_nonce', false ); $total = get_comments( array( 'post_id' => $post->ID, 'number' => 1, 'count' => true ) ); $wp_list_table = _get_list_table( 'WP_Post_Comments_List_Table' ); $wp_list_table->display( true ); if ( 1 > $total ) { echo '<p id="no-comments">' . apply_filters( 'edd_reviews_admin_no_reviews_text', __( 'No reviews yet.', 'edd-reviews' ) ) . '</p>'; } else { $hidden = get_hidden_meta_boxes( get_current_screen() ); if ( ! in_array( 'commentsdiv', $hidden ) ) { ?> <script type="text/javascript">jQuery(document).ready(function(){commentsBox.get(<?php echo $total; ?>, 10);});</script> <?php } ?> <p class="hide-if-no-js" id="show-comments"><a href="#commentstatusdiv" onclick="commentsBox.get(<?php echo $total; ?>);return false;"><?php _e('Show comments'); ?></a> <span class="spinner"></span></p> <?php } wp_comment_trashnotice(); } /** * Load Styles * * @since 1.0 * @access public * @global array $edd_options Used to access the EDD Options * @return void */ public function load_styles() { global $edd_options; wp_register_style( 'edd-reviews-admin', $this->assets_url . 'css/edd-reviews-admin.css', array( ), $this->version ); if ( is_admin() ) wp_enqueue_style( 'edd-reviews-admin' ); if ( isset( $edd_options['edd_reviews_disable_css'] ) ) return; wp_register_style( 'edd-reviews', $this->assets_url . 'css/edd-reviews.css', array( ), $this->version ); wp_enqueue_style( 'edd-reviews' ); } /** * Load Scripts * * @since 1.0 * @access public * @return void */ public function load_scripts() { wp_register_script( 'edd-reviews-js', $this->assets_url . 'js/edd-reviews.js', array( 'jquery' ), $this->version ); if ( is_singular( 'download' ) ) { wp_enqueue_script( 'edd-reviews-js' ); } $edd_reviews_params = array( 'ajax_url' => admin_url( 'admin-ajax.php' ), 'edd_voting_nonce' => wp_create_nonce( 'edd_reviews_voting_nonce' ), 'thank_you_msg' => apply_filters( 'edd_reviews_thank_you_for_voting_message', __( 'Thank you for your feedback.', 'edd-reviews' ) ) ); wp_localize_script( 'edd-reviews-js', 'edd_reviews_params', apply_filters( 'edd_reviews_js_params', $edd_reviews_params ) ); } /** * Load Admin Scripts/Styles * * @since 1.0 * @access public * @global object Used to access the current 'screen' that the user is * browsing * @global object Used to access the post data * @return void */ public function admin_scripts() { global $current_screen, $post; wp_register_style( 'edd-reviews-admin', $this->assets_url . 'css/edd-reviews-admin.css', array( ), $this->version ); wp_enqueue_style( 'edd-reviews-admin' ); wp_enqueue_style( 'wp-color-picker' ); } /** * Shows Review Meta on Comments List Table * * @since 1.0 * @access public * * @param array $columns All the columns on the list table * @return array $columns New columns with Review Title and Rating added */ function custom_columns( $columns ) { $columns['title'] = __( 'Review Title', 'edd-reviews' ); $columns['rating'] = __( 'Rating', 'edd-reviews' ); return $columns; } /** * Display Custom Column Data * * @since 1.0 * @access public * * @param string $column Current column * @param int $comment_ID Comment ID * @return void */ public function custom_column_data( $column, $comment_ID ) { if ( 'title' == $column ) { if ( get_comment_meta( $comment_ID, 'edd_review_title', true ) ) echo get_comment_meta( $comment_ID, 'edd_review_title', true ); else echo '-'; } if ( 'rating' == $column ) { if ( get_comment_meta( $comment_ID, 'edd_rating', true ) ) echo get_comment_meta( $comment_ID, 'edd_rating', true ) . ' / 5'; else echo '-'; } } /** * Open Comments for all Downloads * * @since 1.0 * @access public * * @param bool $open Whether the comments are open or not * @param string $post_id Post ID * @return bool $open Whether the comments are open or not */ public function open_all_comments( $open, $post_id ) { $post_type = get_post_type( $post_id ); if ( 'download' == $post_type ) $open = true; return $open; } /** * Register Misc Settings * * @since 1.0 * @access public * * @param array $settings Existing registered settings * @param array New settings * @return array Merged array with new settings added */ public function misc_settings( $settings ) { $new = array( array( 'id' => 'edd_review_settings', 'name' => '<strong>' . __( 'Product Reviews', 'edd-reviews' ) . '</strong>', 'desc' => '', 'type' => 'header' ), array( 'id' => 'edd_reviews_enable_breakdown', 'name' => __( 'Enable review breakdown', 'edd-reviews' ), 'desc' => __( 'This will show how many people have rated the download for each star rating.', 'edd-reviews' ), 'type' => 'checkbox', 'size' => 'regular' ), array( 'id' => 'edd_reviews_disable_multiple_reviews', 'name' => __( 'Disable multiple reviews by same author', 'edd-reviews' ), 'desc' => __( 'This will disallow authors to post multiple reviews on the same download', 'edd-reviews' ), 'type' => 'checkbox', 'size' => 'regular' ), array( 'id' => 'edd_reviews_only_allow_reviews_by_buyer', 'name' => __( 'Only allow reviews by buyers', 'edd-reviews' ), 'desc' => __( 'This will only allow people who have purchased your product to review it. It will require them to login.', 'edd-reviews' ), 'type' => 'checkbox', 'size' => 'regular' ) ); return array_merge( $settings, $new ); } /** * Register Misc Settings * * @since 1.0 * @access public * * @param array $settings Existing registered settings * @param array New settings * @return array Merged array with new settings added */ public function styles_settings( $settings ) { $new = array( array( 'id' => 'edd_reviews_styling_options', 'name' => '<strong>' . __( 'Reviews', 'edd-reviews' ) . '</strong>', 'desc' => '', 'type' => 'header' ), array( 'id' => 'edd_reviews_disable_css', 'name' => __( 'Disable EDD Reviews CSS', 'edd-reviews' ), 'desc' => __( 'Check this to disable styling for the reviews provided by the EDD Reviews plugin', 'edd-reviews' ), 'type' => 'checkbox', 'size' => 'regular' ) ); return array_merge( $settings, $new ); } /** * Adds "View Reviews" Link to Admin Bar * * @since 1.0 * @access public * @global object $wp_admin_bar Used to add nodes to the WordPress Admin Bar * @global object $post Used to access the post data * @return void */ public function admin_bar_menu() { global $wp_admin_bar, $post; if ( is_admin() && current_user_can( 'moderate_comments' ) ) { $current_screen = get_current_screen(); if ( 'post' == $current_screen->base && 'add' != $current_screen->action && ( $post_type_object = get_post_type_object( $post->post_type ) ) && 'download' == $post->post_type && current_user_can( $post_type_object->cap->read_post, $post->ID ) && ( $post_type_object->public ) && ( $post_type_object->show_in_admin_bar ) && current_user_can( 'moderate_comments' ) ) { if ( wp_count_comments( $post->ID )->total_comments > 0 ) { $wp_admin_bar->add_node( array( 'id' => 'edd-view-reviews', 'title' => __( 'View Reviews', 'edd-reviews' ) . '<span class="edd-review-count-wrap"><span class="edd-review-count">' . wp_count_comments( $post->ID )->total_comments . '</span></span>', 'href' => admin_url( 'edit-comments.php?p=' . $post->ID ) ) ); } } } elseif ( is_singular( 'download' ) && current_user_can( 'moderate_comments' ) ) { if ( wp_count_comments( $post->ID )->total_comments > 0 ) { $wp_admin_bar->add_node( array( 'id' => 'edd-view-reviews', 'title' => __( 'View Reviews', 'edd-reviews' ) . '<span class="edd-review-count-wrap"><span class="edd-review-count">' . wp_count_comments( $post->ID )->total_comments . '</span></span>', 'href' => admin_url( 'edit-comments.php?p=' . $post->ID ) ) ); } } } /** * Handles the displaying of any notices in the admin area * * @since 1.0 * @access public * @return void */ public function admin_notices() { echo '<div class="error"><p>' . sprintf( __( 'You must install %sEasy Digital Downloads%s for the Reviews Add-On to work.', 'edd-reviews' ), '<a href="http://easydigitaldownloads.com" title="Easy Digital Downloads">', '</a>' ) . '</p></div>'; } /** * Count the number of reviews from the database * * @since 1.0 * @access public * @global object $wpdb Used to query the database using the WordPress * Database API * @global object $post Used to access the post data * @return string $count Number of reviews */ public function count_reviews() { global $wpdb, $post; $count = $wpdb->get_var( $wpdb->prepare( " SELECT COUNT(meta_value) FROM {$wpdb->commentmeta} LEFT JOIN {$wpdb->comments} ON {$wpdb->commentmeta}.comment_id = {$wpdb->comments}.comment_ID WHERE meta_key = 'edd_rating' AND comment_post_ID = %d AND comment_approved = '1' AND meta_value > 0 ", $post->ID ) ); return $count; } /** * Count the number of ratings from the database * * @since 1.0 * @access public * @global object $wpdb Used to query the database using the WordPress * Database API * @global object $post Used to access the post data * @return string $count Number of reviews */ public function count_ratings() { global $wpdb, $post; $count = $wpdb->get_var( $wpdb->prepare( " SELECT SUM(meta_value) FROM {$wpdb->commentmeta} LEFT JOIN {$wpdb->comments} ON {$wpdb->commentmeta}.comment_id = {$wpdb->comments}.comment_ID WHERE meta_key = 'edd_rating' AND comment_post_ID = %d AND comment_approved = '1' ", $post->ID ) ); return $count; } /** * Gets the number of the reviews by a rating * * @since 1.0 * @access public * @global object $wpdb Used to query the database using the WordPress * Database API * @param int $rating Rating (1 - 5) * @return int $number Number of reviews */ public function get_review_count_by_rating( $rating ) { global $wpdb, $post; $rating = (int) $rating; if ( $rating < 1 && $rating > 5 ) return; $count = $wpdb->get_var( $wpdb->prepare( " SELECT COUNT(meta_value) FROM {$wpdb->commentmeta} LEFT JOIN {$wpdb->comments} ON {$wpdb->commentmeta}.comment_id = {$wpdb->comments}.comment_ID WHERE meta_key = 'edd_rating' AND meta_value = {$rating} AND comment_approved = '1' AND meta_value > 0 AND {$wpdb->comments}.comment_post_ID = %s ", $post->ID ) ); return $count; } /** * Build Reviews (comments) title * * @since 1.0 * @access public * @global object $post Used to access the post data * * @uses EDD_Reviews::count_reviews() * * @param int $average Average ratings for reviews * @return void */ public function reviews_title( $average = null ) { global $post; if ( $average ) : do_action( 'edd_reviews_title_before' ); ?> <div itemprop="aggregateRating" itemscope itemtype="http://schema.org/AggregateRating"> <span itemprop="ratingValue" style="display:none"><?php echo $average; ?></span> <h2 class="comments-title" id="comments-title"><?php echo sprintf( apply_filters( 'edd_reviews_reviews_title', __( '%s Reviews for %s', 'edd-reviews' ) ), '<span itemprop="reviewCount" class="edd-review-count">' . $this->count_reviews() . '</span>', get_the_title( $post->ID ) ); ?></h2> </div> <?php else : ?> <h2 class="comments-title" id="comments-title"><?php apply_filters( 'edd_reviews_review_title_default', _e( 'Reviews', 'edd-reviews' ) ); ?></h2> <?php do_action( 'edd_reviews_title_after' ); endif; } /** * Checks if the reviewer has purchased the download * * @since 1.0 * @access public * @global object $post Used to access the post data * @return bool Whether reviews has purchased download or not */ public function reviewer_has_purchased_download() { global $post; $user_email = wp_get_current_commenter(); $user_email = $user_email['comment_author_email']; if ( edd_has_user_purchased( $user_email, $post->ID ) ) return true; return false; } /** * Add Classes to the Reviews * * @since 1.0 * @access public * @param array $classes Comment classes * @return array $classes Comment (reviews) classes with 'review' added */ public function review_classes( $classes ) { $classes[] = 'review'; return $classes; } /** * Template for displaying reviews * * This function just executes the hooks to display the review. * * @since 1.0 * @access public * * @param object $comment * @param array $args * @param string $depth * @return void */ public function review( $comment, $args, $depth ) { $GLOBALS['comment'] = $comment; extract( $args, EXTR_SKIP ); do_action( 'edd_reviews_review_before' ); do_action( 'edd_reviews_review_display', $comment, $args, $depth ); do_action( 'edd_reviews_review_after' ); } /** * Renders each review * * NOTE: Closing tags have been left out deliberately because WordPress will * supply the closing tag automatically. See here: * http://codex.wordpress.org/Function_Reference/wp_list_comments * * @since 1.0 * @access public * * @uses EDD_Reviews::voting_info() * * @param object $comment * @param array $args * @param string $depth * @return void */ public function render_review( $comment, $args, $depth ) { ob_start(); $rating = get_comment_meta( get_comment_ID(), 'edd_rating', true ); ?> <?php if ( $depth == 1 ) : ?> <li itemprop="review" itemscope itemtype="http://schema.org/Review" <?php comment_class(); ?> id="li-comment-<?php comment_ID() ?>"> <article id="comment-<?php comment_ID(); ?>" class="comment comment_container edd_reviews_container"> <?php if ( get_option( 'show_avatars' ) ) echo get_avatar( $GLOBALS['comment'], 60 ); ?> <div class="edd-review-meta"> <span itemprop="name" class="review-title-text"><?php echo get_comment_meta( get_comment_ID(), 'edd_review_title', true ); ?> <?php if ( current_user_can( 'edit_others_posts' ) ) : ?><span class="edit-link"><a class="comment-edit-link" href="<?php echo admin_url( 'comment.php?action=editcomment&c=' . get_comment_ID() ); ?>"><?php _e( 'Edit Review', 'edd-reviews' ); ?></a></span><?php endif; ?> </span> <div itemprop="reviewRating" itemscope itemtype="http://schema.org/Rating" class="star-rating"> <div class="edd_reviews_rating_box" role="img" aria-label="<?php echo $rating . ' ' . __( 'stars', 'edd-reviews' ); ?>"> <div class="edd_star_rating" style="width: <?php echo ( 19 * $rating ); ?>px"></div> </div> <div style="display:none" itemprop="reviewRating" itemscope itemtype="http://schema.org/Rating"> <meta itemprop="worstRating" content="1" /> <span itemprop="ratingValue"><?php echo $rating; ?></span> <span itemprop="bestRating">5</span> </div> </div> <?php if ( 0 == $GLOBALS['comment']->comment_approved ) : ?> <p class="moderation"><em><?php apply_filters( 'edd_reviews_moderation_message', _e( 'Your review is awaiting moderation.', 'edd-reviews' ) ); ?></em></p> <?php else : ?> <p class="edd-reviews-author-meta"><?php _e( 'by', 'edd-reviews' ); ?> <span itemprop="author"><?php comment_author(); ?></span>, <time itemprop="datePublished" time datetime="<?php echo get_comment_date( 'c' ); ?>"><?php echo get_comment_date( get_option( 'date_format' ) ); ?></time>:</p> <?php endif; ?> </div> <div class="clear"></div> <div class="comment-text review-text"> <div itemprop="description" class="description edd-review-content comment-content"> <?php comment_text(); ?> </div> </div> <?php if ( ! $this->is_review_poster() ) : ?> <?php if ( ( isset( $_GET['edd_reviews_vote'] ) && $_GET['edd_reviews_vote'] == 'success' && isset( $_GET['edd_c'] ) && is_numeric( $_GET['edd_c'] ) && $_GET['edd_c'] == get_comment_ID() ) || EDD()->session->get( 'wordpress_edd_reviews_voted_' . get_comment_ID() ) ) : ?> <div class="edd-review-vote edd-yellowfade"> <p style="margin:0;padding:0;"><?php echo apply_filters( 'edd_reviews_thank_you_for_voting_message', __( 'Thank you for your feedback.', 'edd-reviews' ) ); ?></p> <?php $this->voting_info(); ?> </div> <?php else: ?> <div class="edd-review-vote"> <?php do_action( 'edd_reviews_voting_box_before' ); ?> <?php $this->voting_info(); ?> <p><?php echo apply_filters( 'edd_reviews_voting_intro_text', _e( 'Help other customers find the most helpful reviews', 'edd-reviews' ) ); ?></p> <p> <?php echo apply_filters( 'edd_reviews_review_helpful_text', __( 'Did you find this review helpful?', 'edd-reviews' ) ); ?> <span class="edd-reviews-voting-buttons"> <a class="vote-yes" data-edd-reviews-comment-id="<?php echo get_comment_ID(); ?>" data-edd-reviews-vote="yes" rel="nofollow" href="<?php echo add_query_arg( array( 'edd_review_vote' => 'yes', 'edd_c' => get_comment_ID() ) ); ?>"><?php _e( 'Yes', 'edd-reviews' ); ?></a> <a class="vote-no" data-edd-reviews-comment-id="<?php echo get_comment_ID(); ?>" data-edd-reviews-vote="no" rel="nofollow" href="<?php echo add_query_arg( array( 'edd_review_vote' => 'no', 'edd_c' => get_comment_ID() ) ); ?>"><?php _e( 'No', 'edd-reviews' ); ?></a> </span> </p> <?php do_action( 'edd_reviews_voting_box_after' ); ?> </div> <?php endif; ?> <?php endif; ?> </article> <div class="clear"></div> <?php elseif ( $depth > 1 ) : ?> <li itemprop="review" itemscope itemtype="http://schema.org/Review" <?php comment_class(); ?> id="li-comment-<?php comment_ID() ?>"> <article id="comment-<?php comment_ID(); ?>" class="comment comment_container edd_reviews_container"> <?php if ( get_option( 'show_avatars' ) ) echo get_avatar( $GLOBALS['comment'], 44 ); ?> <?php if ( 0 == $GLOBALS['comment']->comment_approved ) : ?> <p class="moderation"><em><?php apply_filters( 'edd_reviews_moderation_message', _e( 'Your review is awaiting moderation.', 'edd-reviews' ) ); ?></em></p> <?php else : ?> <p class="edd-reviews-comment-author"><strong><?php comment_author(); ?></strong></p> <p class="edd-reviews-date-published"><time itemprop="datePublished" time datetime="<?php echo get_comment_date( 'c' ); ?>"><?php echo get_comment_date( get_option( 'date_format' ) ); ?></time></p> <?php endif; ?> <div class="clear"></div> <div class="comment-text review-text"> <div itemprop="description" class="description edd-review-content comment-content"> <?php comment_text(); ?> </div> </div> </article> <div class="clear"></div> <?php endif; echo ob_get_clean(); } /** * Conditional whether or not the current logged in user is the poster of * the review being displayed. This function runs throughout the comment * loop and is called for each comment. * * @since 1.2 * @access public * @global object $GLOBALS['comment'] Current comment * @return bool Whether or not the current comment in the loop is by the current user logged in */ public function is_review_poster() { $comment = $GLOBALS['comment']; $user = wp_get_current_user(); $user_email = ( isset( $user->user_email ) ? (int) $user->user_email : null ); if ( $comment->comment_author_email == $user_email ) { return true; } else { return false; } // end if } /** * Display Voting Info * * Example output: 2 of 8 people found this review helpful * * @since 1.0 * @access public * @global object $GLOBALS['comment'] Current comment * @return void */ public function voting_info() { $comment = $GLOBALS['comment']; $votes = array( 'yes' => get_comment_meta( $comment->comment_ID, 'edd_review_vote_yes', true ), 'no' => get_comment_meta( $comment->comment_ID, 'edd_review_vote_no', true ), ); if ( ! empty( $votes['yes'] ) && $votes['yes'] > 1 ) { $total = $votes['yes'] + $votes['no']; echo '<p class="edd-review-voting-feedback">' . sprintf( __( '%s of %s people found this review helpful.', 'edd-reviews' ), $votes['yes'], $total ) . '</p>'; } } /** * Conditional whether or not to display review breakdown * * @since 1.0 * @access public * @global array $edd_options Used to access the EDD Options * * @uses EDD_Reviews::review_breakdown() * * @return void */ public function maybe_show_review_breakdown() { global $edd_options; if ( isset( $edd_options['edd_reviews_enable_breakdown'] ) && 1 == $edd_options['edd_reviews_enable_breakdown'] ) { $this->review_breakdown(); } } /** * Conditional whether or not to display a login form * * @since 1.2 * @access public * @global array $edd_options Used to access the EDD Options * @return void */ public function maybe_display_login_form() { global $edd_options; if ( isset( $edd_options['edd_reviews_only_allow_reviews_by_buyer'] ) && 1 == $edd_options['edd_reviews_only_allow_reviews_by_buyer'] ) { if ( ! is_user_logged_in() ) { echo '<p class="edd-reviews-not-logged-in">' . apply_filters( 'edd_reviews_user_logged_out_message', sprintf( __( 'You must log in and be a buyer of this %s to submit a review.' ), strtolower( edd_get_label_singular() ) ) ) . '</p>'; echo wp_login_form(); return true; } elseif ( is_user_logged_in() ) { if ( $this->maybe_restrict_form() ) { echo '<p class="edd-reviews-not-logged-in">' . apply_filters( 'edd_reviews_user_logged_out_message', sprintf( __( 'You must be a buyer of this %s to submit a review.' ), strtolower( edd_get_label_singular() ) ) ) . '</p>'; return true; } else { return false; } } } else { return false; } // end if } /** * Conditional whether or not the review submission form should remain * restricted * * @since 1.2 * @access public * @global array $post * @return void */ public function maybe_restrict_form() { global $post; $user = wp_get_current_user(); $user_id = ( isset( $user->ID ) ? (int) $user->ID : 0 ); if ( edd_has_user_purchased( $user_id, $post->ID ) ) { return false; } else { return true; } // end if } /** * Conditional whether the currently logged in user has purchased the product * before * * @since 1.2 * @access public * @global array $post Used to access the current post * @return void */ public function is_user_buyer() { global $post; if ( edd_has_user_purchased( get_current_user_id(), $post->post_ID ) ) { return true; } else { return false; } // end if } /** * Reviews Breakdown * * Shows a breakdown of all the reviews and the number of people that given * each rating for each download * * Example: 8 people gave a 5 star rating; 10 people have a 2 star rating * * @since 1.0 * @access public * * @uses EDD_Reviews::display_total_reviews_count() * @uses EDD_Reviews::display_review_counts() * * @return void */ public function review_breakdown() { echo '<div class="edd_reviews_breakdown">'; $this->display_total_reviews_count(); $this->display_review_counts(); echo '</div><!-- /.edd_reviews_breakdown -->'; } /** * Displays the total reviews count * * @since 1.0 * @access public * * @uses EDD_Reviews::count_reviews() * * @return void */ public function display_total_reviews_count() { echo '<div class="edd-reviews-total-count">' . $this->count_reviews() . ' ' . _n( 'review', 'reviews', $this->count_reviews(), 'edd-reviews' ) . '</div>'; } /** * Displays reviews count for each rating by looping through 1 - 5 * * @since 1.0 * @access public * * @uses EDD_Reviews::get_review_count_by_rating() * @uses EDD_Reviews::count_reviews() * * @return void */ public function display_review_counts() { $output = ''; for ( $i = 5; $i >= 1; $i-- ) { $number = $this->get_review_count_by_rating( $i ); $all = $this->count_reviews(); ( $all == 0 ) ? $all = 1 : $all; $number_format = number_format( ( $number / $all ) * 100, 1 ); if ( $number_format == '100.0' ) { $number_format = '100%'; } else { $number_format .= 'px'; } $output .= '<div class="edd-counter-container edd-counter-container-'. $i .'">'; $output .= '<div class="edd-counter-label">'. $i . ' ' . _n( 'star', 'stars', $i, 'edd-reviews' ) . '</div>'; $output .= '<div class="edd-counter-back"><span class="edd-counter-front" style="width: '. $number_format .'"></span></div>'; $output .= '<div class="edd-review-count">'. $number .'</div>'; $output .= '</div>'; } echo $output; } /** * Process Vote from Review * * This function is called if a JavaScript isn't enabled * * @since 1.0 * @access public * @return void */ public function process_vote() { if ( isset( $_GET['edd_review_vote'] ) && isset( $_GET['edd_c'] ) && is_numeric( $_GET['edd_c'] ) ) { $this->add_comment_vote_meta( $_GET['edd_c'], $_GET['edd_review_vote'] ); // Remove the query arguments to prevent multiple votes $url = remove_query_arg( array( 'edd_c', 'edd_review_vote' ) ); wp_redirect( $url . '?edd_reviews_vote=success&edd_c=' . $_GET['edd_c'] .'#comment-' . intval( $_GET['edd_c'] ) ); die(); } } /** * Add Comment Vote * * @since 1.0 * @access public * * @param int $comment_id Comment ID * @param string $vote Whether the vote was yes or no * @return void */ public function add_comment_vote_meta( $comment_id, $vote ) { if ( 'yes' == $vote ) { $value = get_comment_meta( $comment_id, 'edd_review_vote_yes', true ); if ( ! empty( $value ) && ! $value > 0 ) { $number = 1; add_comment_meta( $comment_id, 'edd_review_vote_yes', $number ); } else { $number = $value + 1; update_comment_meta( $comment_id, 'edd_review_vote_yes', $number ); } } elseif ( 'no' == $vote ) { $value = get_comment_meta( $comment_id, 'edd_review_vote_no', true ); if ( ! empty( $value ) && ! $value > 0 ) { $number = 1; add_comment_meta( $comment_id, 'edd_review_vote_yes', $number ); } else { $number = $value + 1; update_comment_meta( $comment_id, 'edd_review_vote_no', $number ); } add_comment_meta( $comment_id, 'edd_review_vote_no', $number ); } } /** * Checks whether an AJAX request has been sent * * @since 1.0 * @access public * @return bool Whether or not AJAX $_GET header has been passed */ public function is_ajax_request() { return (bool) ( isset( $_POST['edd_reviews_ajax'] ) && ! empty( $_REQUEST['action'] ) ); } /** * Process Voting for the Reviews via AJAX * * Processes the voting button appended to the bottom of each review by adding * or updating the comment meta via AJAX. * * @since 1.0 * @access public * * @uses EDD_Reviews::is_ajax_request() * * @return mixed returns if AJAX check fails */ public function process_ajax_vote() { // Bail if an AJAX request isn't sent if ( ! $this->is_ajax_request() ) return; check_ajax_referer( 'edd_reviews_voting_nonce', 'security', true ); if ( ! isset( $_POST['review_vote'] ) ) return; if ( isset( $_POST['review_vote'] ) && isset( $_POST['comment_id'] ) && is_numeric( $_POST['comment_id'] ) ) { $this->add_comment_vote_meta( $_POST['comment_id'], $_POST['review_vote'] ); EDD()->session->set( 'wordpress_edd_reviews_voted_' . $_POST['comment_id'], 'yes' ); echo 'success'; } else { echo 'fail'; } die(); } /** * Register Dashboard Widgets * * @since 1.0 * @access public * @return void */ public function dashboard_widgets() { if ( is_blog_admin() && current_user_can( 'moderate_comments' ) ) { $recent_reviews_title = apply_filters( 'edd_reviews_recent_reviews_dashboard_widget_title', __( 'Easy Digital Downloads Recent Reviews', 'edd-reviews' ) ); wp_add_dashboard_widget( 'edd_reviews_dashboard_recent_reviews', $recent_reviews_title, array( 'EDD_Reviews', 'render_dashboard_widget' ) ); } } /** * Render the Dashboard Widget * * @since 1.0 * @access public * @global object $wpdb Used to query the database using the WordPress Database API * @return void */ public function render_dashboard_widget() { global $wpdb; $reviews = $wpdb->get_results( " SELECT *, SUBSTRING( comment_content, 1, 100 ) AS excerpt FROM {$wpdb->comments} LEFT JOIN $wpdb->posts ON {$wpdb->comments}.comment_post_ID = {$wpdb->posts}.ID WHERE comment_approved = '1' AND post_password = '' AND post_type = 'download' AND comment_type = '' ORDER BY comment_date_gmt DESC LIMIT 5 " ); if ( $reviews ) { echo '<div id="edd-reviews-list">'; foreach ( $reviews as $review ) { $output = '<div id="review-'. $review->ID .'">'; $output .= ( get_option( 'show_avatars' ) ) ? get_avatar( $review->comment_author_email, 50 ) : ''; $output .= '<div class="edd-dashboard-review-wrap">'; $rating = get_comment_meta( $review->comment_ID, 'edd_rating', true ); $output .= '<h4 class="meta"><a href="' . get_permalink( $review->ID ) . '#comment-' . absint( $review->comment_ID ) .'">' . esc_html__( get_comment_meta( $review->comment_ID, 'edd_review_title', true ) ) . '</a></h4>'; $output .= '<div class="edd_reviews_rating_box"><div class="edd_star_rating" style="width: ' . 19 * $rating . 'px"></div></div>'; $output .= '<p>' . __( 'By', 'edd-reviews' ) . ' ' . esc_html( $review->comment_author ) . ', ' . get_comment_date( get_option( 'date_format()' ), $review->comment_ID ) . '</p>'; $output .= '<blockquote>' . wp_kses_data( $review->excerpt ) . ' ...</blockquote></div>'; $output .= '</div>'; echo $output; } echo '</div>'; } else { echo '<p>' . __( 'There are no reviews yet.', 'edd-reviews' ) . '</p>'; } } /** * Add the Meta Boxes * * @since 1.0 * @access public * @return void */ public function add_meta_boxes() { add_meta_box( 'edd_reviews_review_meta_box', __( 'Review Information', 'edd-reviews' ), array( $this, 'review_meta_box' ), 'comment', 'normal', 'high' ); } /** * Render the Review Meta Box * * Outputs the Review Information meta box on the Edit Comment screen. This * meta box displays the review title and the star rating. It also allows * for it to be edited. * * @since 1.0 * @access public * @param object $comment Comment information * @return void */ public function review_meta_box( $comment ) { ?> <table class="form-table editcomment"> <tbody> <tr valign="top"> <td class="first"><?php _e( 'Review Title:', 'edd-reviews' ); ?></td> <td><input type="text" class="widefat" id="edd_reviews_review_title" name="edd_reviews_review_title" value="<?php echo get_comment_meta( $comment->comment_ID, 'edd_review_title', true ); ?>" /></td> </tr> <tr valign="top"> <td class="first"><?php _e( 'Rating:', 'edd-reviews' ); ?></td> <td><input type="text" class="widefat" id="edd_reviews_rating" name="edd_reviews_rating" value="<?php echo get_comment_meta( $comment->comment_ID, 'edd_rating', true ); ?>" /></td> </tr> </tbody> </table> <?php } /** * Save the Meta Data from the Meta Box on the Edit Comment Screen * * @since 1.0 * @access public * @param int $comment_id Comment ID * @return void */ public function update_review_meta( $comment_id ) { $review_title = sanitize_text_field( $_POST['edd_reviews_review_title'] ); $rating = intval( $_POST['edd_reviews_rating'] ); if ( empty ( $review_title ) ) { wp_die( sprintf( __( '%sError%s: Please add a review title.', 'edd-reviews' ), '<strong>', '</strong>' ), __( 'Error', 'edd-reviews' ), array( 'back_link' => true ) ); } if ( ! ( $rating > 0 && $rating <= 5 ) ) { wp_die( sprintf( __( '%sError%s: Please add a valid rating between 1 and 5.', 'edd-reviews' ), '<strong>', '</strong>' ), __( 'Error', 'edd-reviews' ), array( 'back_link' => true ) ); } update_comment_meta( $comment_id, 'edd_review_title', $review_title ); update_comment_meta( $comment_id, 'edd_rating', $rating ); } /** * Register API Query Mode * * @since 1.0 * @access public * @param array $modes Whitelisted query modes * @return array $modes Updated list of query modes */ public function register_api_mode( $modes ) { $modes[] = 'reviews'; return $modes; } /** * Add 'review_id' Query Var into WordPress Whitelisted Query Vars * * @since 1.0 * @access public * @param array $vars Array of WordPress allowed query vars * @return array $vars Updated array of WordPress query vars to allow * Reviews to integrate with the EDD API */ public function query_vars( $vars ) { $vars[] = 'review_id'; return $vars; } /** * Processes the Data Outputted when an API Call for Reviews is Triggered * * @since 1.0 * @access public * @global object $wpdb Used to query the database using the WordPress * Database API * @global object $wp_query Used to access the query vars * * @param array $data Array to hold the output * @param array $query_mode Query mode (i.e. reviews) * @param object $api_object EDD_API Object * * @return array $data All the data for when the API call for reviews is fired */ public function api_output( $data, $query_mode, $api_object ) { global $wpdb, $wp_query; // Bail if the query mode isn't reviews if ( 'reviews' !== $query_mode ) return $data; // Get the review_id query var $review_id = isset( $wp_query->query_vars['review_id'] ) ? $wp_query->query_vars['review_id'] : null; if ( $review_id ) { // Get the review from the database $review = $wpdb->get_results( $wpdb->prepare( " SELECT * FROM {$wpdb->comments} INNER JOIN {$wpdb->posts} ON {$wpdb->comments}.comment_post_ID = {$wpdb->posts}.ID WHERE comment_ID = '%d' LIMIT 1 ", $review_id ) ); if ( $review ) : $data['reviews']['id'] = $review[0]->comment_ID; $data['reviews']['title'] = get_comment_meta( $review[0]->comment_ID, 'edd_review_title', true ); $data['reviews']['download_id'] = $review[0]->comment_post_ID; $data['reviews']['download_title'] = $review[0]->post_title; $data['reviews']['rating'] = get_comment_meta( $review[0]->comment_ID, 'edd_rating', true ); $data['reviews']['author'] = $review[0]->comment_author; $data['reviews']['email'] = $review[0]->comment_author_email; $data['reviews']['IP'] = $review[0]->comment_author_IP; $data['reviews']['date'] = $review[0]->comment_date; $data['reviews']['date_gmt'] = $review[0]->comment_date_gmt; $data['reviews']['content'] = $review[0]->comment_content; $data['reviews']['status'] = $review[0]->comment_approved; $data['reviews']['user_id'] = $review[0]->user_id; else : $error['error'] = sprintf( __( 'Review %s not found!', 'edd-reviews' ), $review_id ); return $error; endif; } else { // Get total reviews count from the database $total_reviews = $wpdb->get_var( $wpdb->prepare( " SELECT COUNT(meta_value) FROM {$wpdb->commentmeta} LEFT JOIN {$wpdb->comments} ON {$wpdb->commentmeta}.comment_id = {$wpdb->comments}.comment_ID WHERE meta_key = 'edd_rating' AND comment_approved = '1' AND meta_value > 0 " ) ); /** Total Reviews */ $data['reviews']['total'] = $total_reviews; /** Most Recent Review */ $most_recent_review = get_comments( array( 'post_type' => 'download', 'number' => 1 ) ); $data['reviews']['most_recent']['id'] = $most_recent_review[0]->comment_ID; $data['reviews']['most_recent']['title'] = get_comment_meta( $most_recent_review[0]->comment_ID, 'edd_review_title', true ); $data['reviews']['most_recent']['download_id'] = $most_recent_review[0]->comment_post_ID; $data['reviews']['most_recent']['download_title'] = get_the_title( $most_recent_review[0]->comment_post_ID ); $data['reviews']['most_recent']['rating'] = get_comment_meta( $most_recent_review[0]->comment_ID, 'edd_rating', true ); $data['reviews']['most_recent']['author'] = $most_recent_review[0]->comment_author; $data['reviews']['most_recent']['email'] = $most_recent_review[0]->comment_author_email; $data['reviews']['most_recent']['IP'] = $most_recent_review[0]->comment_author_IP; $data['reviews']['most_recent']['date'] = $most_recent_review[0]->comment_date; $data['reviews']['most_recent']['date_gmt'] = $most_recent_review[0]->comment_date_gmt; $data['reviews']['most_recent']['content'] = $most_recent_review[0]->comment_content; $data['reviews']['most_recent']['status'] = $most_recent_review[0]->comment_approved; $data['reviews']['most_recent']['user_id'] = $most_recent_review[0]->user_id; } // Allow extensions to add to the data outpt $data = apply_filters( 'edd_reviews_api_output_data', $data ); return $data; } /** * Is the User Allowed to See TinyMCE? * * @since 1.0 * @access public * @return bool Whether the user can see TinyMCE or not */ public function user_can_see_tinymce() { return ( current_user_can( 'edit_posts' ) && current_user_can( 'edit_pages' ) ); } /** * Add TinyMCE Button * * Adds a button to the TinyMCE editor to easily embed reviews into posts * and pages * * @since 1.0 * @access public * * @uses EDD_Reviews::user_can_see_tinymce() * * @return void */ public function tinymce_button() { if ( $this->user_can_see_tinymce() && 'true' == get_user_option( 'rich_editing' ) ) { add_filter( 'mce_external_plugins', array( $this, 'add_plugin' ) ); add_filter( 'mce_buttons', array( $this, 'register_button' ) ); } } /** * Register TinyMCE Plugin * * @since 1.0 * @access public * @param array $plugin_array Array of TinyMCE Plugins * @return array $plugin_array Array of TinyMCE Plugins */ public function add_plugin( $plugin_array ) { $plugin_array['edd_reviews'] = $this->assets_url . 'js/edd-reviews-admin.js'; return $plugin_array; } /** * Register TinyMCE Button * * @since 1.0 * @access public * @param array $buttons Array of TinyMCE Button * @return array $buttons Array of TinyMCE Button */ public function register_button( $buttons ) { array_push( $buttons, '|', 'edd_reviews' ); return $buttons; } /** * Process the TinyMCE Modal Dialog * * @since 1.0 * @access public * @global object $wpdb Used to query the database using the WordPress * Database API * @return void */ public function process_mce_dialog() { if ( is_user_logged_in() && isset( $_GET['edd_reviews_mce_dialog'] ) && 'true' == $_GET['edd_reviews_mce_dialog'] ) { global $wpdb; $reviews = $wpdb->get_results( $wpdb->prepare( "SELECT meta_value, comment_id FROM {$wpdb->commentmeta} WHERE meta_key = %s", 'edd_review_title' ) ); ?> <!DOCTYPE html> <html <?php language_attributes(); ?>> <head> <meta charset="utf-8" /> <title><?php _e( 'Embed Review', 'edd-reviews' ); ?></title> <script type="text/javascript" src="<?php echo includes_url(); ?>/js/tinymce/tiny_mce_popup.js"></script> <script type="text/javascript"> var edd_reviews_dialog = { local_ed: 'ed', init: function (ed) { edd_reviews_dialog.local_ed = ed; tinyMCEPopup.resizeToInnerSize(); }, insert: function insertButton(ed) { tinyMCEPopup.execCommand('mceRemoveNode', false, null); var elem = document.getElementById('edd_reviews_shortcode_dialog'), selected = elem.options[elem.selectedIndex].value; output = ''; output = '[review id="' + selected + '"]'; tinyMCEPopup.execCommand('mceReplaceContent', false, output); tinyMCEPopup.close(); } } tinyMCEPopup.onInit.add(edd_reviews_dialog.init, edd_reviews_dialog); </script> </head> <body> <?php if ( $reviews ) { echo '<h2>' . __( 'Select a Review to Embed' ) . '</h2>'; echo '<p><select id="edd_reviews_shortcode_dialog" name="edd_reviews_shortcode_dialog">'; foreach ( $reviews as $review ) { echo '<option value="' . $review->comment_id . '">' . esc_html( $review->meta_value ) . '</option>'; } echo '</select></p>'; echo '<p><a href="javascript:edd_reviews_dialog.insert(edd_reviews_dialog.local_ed)" id="insert" style="display: block; line-height: 24px;">' . __( 'Embed Review', 'edd-reviews' ) . '</a></p>'; } else { echo '<h2>' . __( 'No Reviews Have Been Created Yet', 'edd-reviews' ) . '</h2>'; } ?> </body> </html> <?php die(); } } /** * Plugin Action Links * * This function adds a link to the plugin action links bar on the Plugins * Administrati on page to for the API documentation and to Easy Digital Downloads * Support Forum. * * @since 1.0 * @access public * @param array $links Plugin Action Links * @return array $links Plugin Action Links */ public function plugin_links( $links, $file ) { static $this_plugin; if ( ! $this_plugin ) { $this_plugin = $this->basename; } if ( $file == $this_plugin ) { $api_link = '<a href="' . $this->plugin_url . 'api-docs/index.html' . '">' . __( 'API Documentation', 'edd-reviews' ) . '</a>'; array_unshift( $links , $api_link ); } return $links; } /** * Loads the Updater * * Instantiates the Software Licensing Plugin Updater and passes the plugin * data to the class. * * @since 1.0 * @access public * @return void */ public function updater() { $license = new EDD_License( $this->file, 'Product Reviews', $this->version, 'Sunny Ratilal', 'edd_reviews_licensing_license_key' ); } } /** * The callback for the reviews called by wp_list_comments(). * * This must be placed outside of the class because wp_list_comments() * doesn't allow a function to be passed as a callback within a class, * it must be a separate function. * * @since 1.0 * * @param object $comment * @param array $args * @param string $depth * @return void */ function edd_reviews_callback( $comment, $args, $depth ) { edd_reviews()->review( $comment, $args, $depth ); } /** * Loads a single instance of EDD Reviews * * This follows the PHP singleton design pattern. * * Use this function like you would a global variable, except without needing * to declare the global. * * @example <?php $edd_reviews = edd_reviews(); ?> * * @since 1.0 * * @see EDD_Reviews::get_instance() * * @return object Returns an instance of the EDD_Reviews class */ function edd_reviews() { return EDD_Reviews::get_instance(); } /** * Loads plugin after all the others have loaded and have registered their * hooks and filters */ add_action( 'plugins_loaded', 'edd_reviews', apply_filters( 'edd_reviews_action_priority', 10 ) ); endif;