init_vars(); $this->hooks(); } /** * Initialize main settings values. * * @since 9.1.3 * * @return void */ public function init_vars() { $postfix = '_advanced'; $settings = (array)get_option('xstore_sales_booster_settings', array()); $default = array( 'rating_summary_position' => 'comments_start', 'rating_summary' => 'on', 'pros_cons' => false, 'likes' => 'on', 'reset_likes' => false, 'verified_owner_badge' => 'on', 'rating_criteria' => false, 'rating_criteria_required' => false, 'criteria' => '', 'criteria_ready' => [], 'circle_avatars' => false, 'date_format' => 'ago', 'date_format_custom' => wc_date_format() ); $local_settings = $default; if (count($settings) && isset($settings[self::$option_name . $postfix])) { $local_settings = wp_parse_args( $settings[ self::$option_name . $postfix ], $default ); } $force_check_switchers = array( 'rating_summary', 'pros_cons', 'likes', 'reset_likes', 'verified_owner_badge', 'rating_criteria', 'rating_criteria_required', 'circle_avatars' ); foreach ($force_check_switchers as $switcher) { $local_settings[$switcher] = $local_settings[$switcher] == 'on'; } if ($local_settings['criteria'] ) { $criteria_unique_slugs = array(); $criteria = explode(',', $local_settings['criteria']); if (count($criteria)) { foreach ($criteria as $criteria_key) { if ('' == $criteria_key || '' == $local_settings[$criteria_key . '_slug']) continue; if ( in_array($local_settings[$criteria_key . '_slug'], $criteria_unique_slugs)) continue; $criteria_ready = array( 'slug' => $local_settings[$criteria_key . '_slug'], 'name' => $local_settings[$criteria_key . '_name'], ); if (array_filter($criteria_ready)) { $local_settings['criteria_ready'][] = $criteria_ready; $criteria_unique_slugs[] = $criteria_ready['slug']; } } // empty all values if (!array_filter($local_settings['criteria_ready'])) $local_settings['criteria_ready'] = array(); } } $this->settings = $local_settings; } /** * Hooks for creating/saving/removing data in comment form. * * @since 9.1.3 * * @return void */ public function hooks() { add_action('wp_enqueue_scripts', array($this, 'load_styles'), 40); // change the position of star rating in review comment remove_action('woocommerce_review_before_comment_meta', 'woocommerce_review_display_rating', 10); add_action('woocommerce_review_before_comment_text', 'woocommerce_review_display_rating', 5); if (in_array($this->settings['date_format'], array('ago', 'custom'))) { add_action('woocommerce_review_meta', array($this, 'set_comment_date_format_custom'), 1); add_action('woocommerce_review_meta', array($this, 'reset_comment_date_format_custom'), 100); } // pros and cons if ( $this->settings['pros_cons'] ) { add_action('comment_post', array($this, 'save_comment_pros_cons')); add_filter('comment_text', array($this, 'render_pros_cons'), 30, 2); add_filter('woocommerce_product_review_comment_form_args', array($this, 'add_pros_cons_fields')); } if ( $this->settings['rating_summary'] ) { add_filter('comment_post_redirect', array($this, 'redirect_after_comment')); $summary_hook = str_replace( array('above_all', 'comments_start', 'review_start'), array('etheme_before_product_comments_wrapper', 'etheme_before_product_comments', 'etheme_before_product_review_form'), $this->settings['rating_summary_position'] ); add_action($summary_hook, array($this, 'render_rating_summary')); } if ( $this->settings['verified_owner_badge'] ) { add_filter( 'comment_author', array( $this, 'add_author_icon' ), 10, 2 ); } if ( $this->settings['rating_criteria'] && count($this->settings['criteria_ready']) ) { remove_action( 'woocommerce_review_before_comment_text', 'woocommerce_review_display_rating', 5 ); add_action( 'woocommerce_review_before_comment_text', array( $this, 'render_criteria_star_rating' ), 7 ); add_filter('etheme_product_review_rating_html', array($this, 'add_criteria_ratings'), 10); add_filter('cr_review_form_before_comment', array($this, 'add_criteria_ratings'), 10); add_action( 'comment_post', array( $this, 'save_comment_rating_criteria' ) ); add_filter('etheme_et_js_config', function ($config) { if ( get_query_var('is_single_product', false) || get_query_var('is_single_product_shortcode', false) ) { if ( !array_key_exists('sales_booster_reviews_advanced', $config) ) $config['sales_booster_reviews_advanced'] = array(); $config['sales_booster_reviews_advanced'] = array_merge(array( 'criteria_list' => wp_json_encode($this->settings['criteria_ready']), 'criteria_required' => $this->settings['rating_criteria_required'] ), $config['sales_booster_reviews_advanced']); } return $config; }); } if ( $this->settings['circle_avatars'] ) { add_action('woocommerce_review_before', array($this, 'set_avatar_circle'), 1); add_action('woocommerce_review_before', array($this, 'reset_avatar_circle'), 100); } if ( $this->settings['likes'] ) { add_action( 'comment_post', array( $this, 'save_comment_likes' ) ); add_action( 'woocommerce_review_after_comment_text', array( $this, 'render_likes' ) ); add_filter('etheme_et_js_config', function ($config) { if ( get_query_var('is_single_product', false) || get_query_var('is_single_product_shortcode', false) ) { $config['is_loggedIn'] = get_query_var( 'et_is-loggedin', false); $config['woocommerceSettings'] = array_merge($config['woocommerceSettings'], array( 'myaccount_url' => $config['woocommerceSettings']['is_woocommerce'] ? esc_url(get_permalink(get_option('woocommerce_myaccount_page_id'))) : '', 'voted_text' => esc_html__('Voted', 'xstore') )); if ( !array_key_exists('sales_booster_reviews_advanced', $config) ) $config['sales_booster_reviews_advanced'] = array(); $config['sales_booster_reviews_advanced'] = array_merge(array( 'cheating_likes' => esc_html__('Cheating huh?', 'xstore'), 'reset_likes' => $this->settings['reset_likes'] ), $config['sales_booster_reviews_advanced']); } return $config; }); } } public function load_styles() { if ( get_query_var('is_single_product', false) || get_query_var('is_single_product_shortcode', false) ) { wp_enqueue_style('etheme-sale-booster-reviews-advanced'); if ( $this->settings['likes'] ) wp_enqueue_script( 'et_reviews_likes' ); if ( $this->settings['rating_criteria'] && count($this->settings['criteria_ready']) ) wp_enqueue_script( 'et_reviews_criteria' ); } } /** * Converting data to human-readable version (X days ago) * @param $date * @param $format * @param $comment * @return string */ public function human_time_ago($date, $format, $comment) { return sprintf(_x( '%s ago', '%s = human-readable time difference', 'xstore' ), human_time_diff( get_comment_time( 'U', false, true, $comment->comment_ID ), current_time( 'timestamp' ) ) ); } /** * Set the date format to custom one if the options are set. * @param $format * @return mixed */ public function custom_date_format($format) { if ( empty($this->settings['date_format_custom']) ) return $format; return $this->settings['date_format_custom']; } /** * Setter of custom date format */ public function set_comment_date_format_custom() { if ( $this->settings['date_format'] == 'ago' ) add_filter('get_comment_date', array($this, 'human_time_ago'), 10, 3); else add_filter('woocommerce_date_format', array($this, 'custom_date_format'), 10, 1); } /** * Resetter of custom date format */ public function reset_comment_date_format_custom() { if ( $this->settings['date_format'] == 'ago' ) remove_filter('get_comment_date', array($this, 'human_time_ago'), 10, 3); else remove_filter('woocommerce_date_format', array($this, 'custom_date_format'), 10, 1); } /** * Render rating summary. * * @return string|void */ public function render_rating_summary() { if ( ! function_exists( 'wc_review_ratings_enabled' ) || ! wc_review_ratings_enabled() ) { return ''; } global $product; $rating_count = $product->get_rating_count(); if ( $rating_count < 1 ) return; $rating_item = array( 5 => $product->get_rating_count(5), 4 => $product->get_rating_count(4), 3 => $product->get_rating_count(3), 2 => $product->get_rating_count(2), 1 => $product->get_rating_count(1) ); $average_rating = $product->get_average_rating(); ?>

= 1; $i--): ?>
settings['pros_cons'] ) { return $comment_form; } $comment_form['comment_field'] .= '

'; $comment_form['comment_field'] .= '

'; return $comment_form; } /** * Render pros & cons for each comment if one's has such data set on posting. * @param $comment_content * @param $comment * @return string */ public function render_pros_cons( $comment_content, $comment ) { if ( ! $this->settings['pros_cons'] || ( ! wp_doing_ajax() && ( is_admin() || ! is_singular( 'product' ) ) ) ) { return $comment_content; } $pros_list = array_filter( get_comment_meta( $comment->comment_ID, 'et_pros' ) ); $cons_list = array_filter( get_comment_meta( $comment->comment_ID, 'et_cons' ) ); if ( empty( $pros_list ) && empty( $cons_list ) ) return $comment_content; ob_start(); ?>
get_review_icon('pros', true); ?>

get_review_icon('cons', true); ?>

is_parent_comment( $comment_ID ) && ! $this->is_user_purchased_product( $comment_ID ) ) || ( ! wp_doing_ajax() && is_admin() ) ) { return $author; } return $this->get_review_icon('verified-owner') . $author; } /** * Saving of comment likes/dislikes * @param $comment_id */ public function save_comment_likes( $comment_id ) { if ( 'product' !== get_post_type( absint( $_POST['comment_post_ID'] ) ) ) { return; } update_comment_meta( $comment_id, 'et_likes', 0 ); update_comment_meta( $comment_id, 'et_dislikes', 0 ); update_comment_meta( $comment_id, 'et_total_votes', 0 ); } /** * Ajax technique for recounting like/dislikes on clicking the relative icons * @return int */ public function ajax_comments_likes() { if ( ! isset( $_POST['comment_id'], $_POST['vote'] ) ) { return 0; } $comment_id = $_POST['comment_id']; $vote = $_POST['vote']; $reset_vote = $_POST['reset_vote']; $current_user_id = get_current_user_id(); if ( metadata_exists( 'comment', $comment_id, 'et_votes' ) ) { $meta_votes = get_comment_meta($comment_id, 'et_votes', true); $meta_votes[$current_user_id] = $vote; } else $meta_votes[$current_user_id] = $vote; foreach ( $meta_votes as $user_id => $meta_vote ) { if ( $user_id !== $current_user_id ) $meta_votes[$current_user_id] = $vote; else $meta_votes[$user_id] = $vote; } if ( in_array($reset_vote, array('like', 'dislike')) && isset($meta_votes[$current_user_id])) { unset($meta_votes[$current_user_id]); } $votes_counted = array_count_values( $meta_votes ); if ( ! isset( $votes_counted['like'] ) ) { $votes_counted['like'] = 0; } if ( ! isset( $votes_counted['dislike'] ) ) { $votes_counted['dislike'] = 0; } $likes = $votes_counted['like']; $dislike = $votes_counted['dislike']; $total = $votes_counted['like'] + $votes_counted['dislike']; update_comment_meta( $comment_id, 'et_votes', $meta_votes ); update_comment_meta( $comment_id, 'et_likes', $likes ); update_comment_meta( $comment_id, 'et_dislikes', $dislike ); update_comment_meta( $comment_id, 'et_total_votes', $total ); wp_send_json( array( 'likes' => $likes, 'dislikes' => $dislike, ) ); } /** * Render likes/dislikes html for each comment with count and tooltip if customer is not logged in. * @param $data_object */ public function render_likes( $data_object ) { if ( '0' !== $data_object->comment_parent || ( ! wp_doing_ajax() && ( is_admin() || ! is_singular( 'product' ) ) ) ) { return; } $likes = metadata_exists( 'comment', $data_object->comment_ID, 'et_likes' ) ? get_comment_meta( $data_object->comment_ID, 'et_likes', true ) : 0; $dislikes = metadata_exists( 'comment', $data_object->comment_ID, 'et_dislikes' ) ? get_comment_meta( $data_object->comment_ID, 'et_dislikes', true ) : 0; $current_user_id = get_current_user_id(); $voters = get_comment_meta($data_object->comment_ID, 'et_votes', true); $like_left = isset($voters[$current_user_id]) && $voters[$current_user_id] == 'like'; $dislike_left = isset($voters[$current_user_id]) && $voters[$current_user_id] == 'dislike'; $like_text = $dislike_text = esc_attr__('Log in to leave your voice', 'xstore'); if ( get_query_var( 'et_is-loggedin', false) ) { $like_text = $dislike_text = false; if ( $like_left ) $like_text = esc_html__('Voted', 'xstore'); elseif ( $dislike_left ) $dislike_text = esc_html__('Voted', 'xstore'); } ?>
> get_review_icon('like', true); ?>
> get_review_icon('dislike', true); ?>
' ', 'pros' => ' ', 'cons' => ' ', 'like' => ' ', 'dislike' => ' ' ); } else { $icons_package = array( 'verified-owner' => ' ', 'pros' => ' ', 'cons' => ' ', 'like' => ' ', 'dislike' => ' ' ); } if ( $echo ) echo array_key_exists($icon_key, $icons_package) ? $icons_package[$icon_key] : ''; else return array_key_exists($icon_key, $icons_package) ? $icons_package[$icon_key] : ''; } /** * Setter filter for adding class for circle avatar */ public function set_avatar_circle() { add_filter('get_avatar', array($this, 'avatar_circle_classes'), 10); } /** * Resetter filter for adding class for circle avatar */ public function reset_avatar_circle() { remove_filter('get_avatar', array($this, 'avatar_circle_classes'), 10); } /** * Adds class for know the avatar should be styled in circle style * @param $avatar * @return string|string[] */ public function avatar_circle_classes($avatar) { return str_replace( "class='","class='avatar-circle ",$avatar ); } /** * Modify default ratings with new additions of ratings by criteria * @param $html * @return string */ public function add_criteria_ratings($html) { $stars_options = ' '; // replace html so text in label should be another $html = ''; foreach ($this->settings['criteria_ready'] as $criteria) { $html .= ''; } $html .= ''; return '
'.$html.'
'; } /** * Saving criteria ratings * @param $comment_id */ public function save_comment_rating_criteria( $comment_id ) { $summary_criteria_list = $this->get_rating_criteria_slugs(); if ( 0 === count( $summary_criteria_list ) ) { return; } foreach ( $summary_criteria_list as $criteria_key ) { if ( isset( $_POST[ $criteria_key ], $_POST['comment_post_ID'] ) && in_array( $_POST[ $criteria_key ], array( '1', '2', '3', '4', '5' ), true ) && 'product' === get_post_type( absint( $_POST['comment_post_ID'] ) ) ) { add_comment_meta( $comment_id, $criteria_key, $_POST[ $criteria_key ], true ); } } } /** * Getter of rating criteria slugs for saving it as comment_meta for comment data. * @return array|false|string[] */ public function get_rating_criteria_slugs() { return isset( $_REQUEST['et_reviews_criteria_ids'] ) ? explode( ',', $_REQUEST['et_reviews_criteria_ids'] ) : array(); } /** * Showing ratings by criteria or only total if no criteria ratings are left * @param $comment */ public function render_criteria_star_rating($comment) { $comment_id = $comment->comment_ID; $reviews_enabled = function_exists('wc_review_ratings_enabled') && wc_review_ratings_enabled(); $ratings = ''; foreach ($this->settings['criteria_ready'] as $criteria) { $rating = intval( get_comment_meta( $comment_id, $criteria['slug'], true ) ); if ( $rating && $reviews_enabled ) { $ratings .= '
' . wc_get_rating_html( $rating ) . ''.$criteria['name'].'' . '
'; // WPCS: XSS ok. } } if ( $ratings ) { echo '
'; } woocommerce_review_display_rating(); if ( $ratings ) { echo '' . esc_html__('Total rating', 'xstore') . ''; echo '
'; echo '
' . $ratings . '
'; } } /** * Check if user is verified (bought this product before) * It is not used yet but could be used in the near future after some testing time * @param $comment_id * @return bool */ protected function is_user_purchased_product( $comment_id ) { $comment = get_comment( $comment_id ); if ( empty( $comment ) || ! class_exists('WooCommerce') || ! is_singular( 'product' ) || ! function_exists( 'wc_customer_bought_product' ) || ! function_exists( 'wc_review_is_from_verified_owner' ) ) { return false; } global $product; if ( $product && $product->get_ID() && wc_customer_bought_product( $comment->comment_author_email, $comment->user_id, $product->get_ID() ) && wc_review_is_from_verified_owner( $comment_id ) ) { return true; } return false; } /** * Check for parents comment * It is not used yet but could be used in the near future after some testing time * @param $comment_id * @return bool */ protected function is_parent_comment( $comment_id ) { global $wpdb; $comment_info = $wpdb->get_results( $wpdb->prepare( "SELECT $wpdb->comments.comment_parent FROM $wpdb->comments WHERE $wpdb->comments.comment_ID = %d;", $comment_id ), ARRAY_A ); return '0' === $comment_info[0]['comment_parent']; } } new Etheme_WooCommerce_Product_Reviews_Advanced();