WC_Comments

Comments.

Defined (1)

The class is defined in the following location(s).

/includes/class-wc-comments.php  
  1. class WC_Comments { 
  2.  
  3. /** 
  4. * Hook in methods. 
  5. */ 
  6. public static function init() { 
  7. // Rating posts 
  8. add_filter( 'preprocess_comment', array( __CLASS__, 'check_comment_rating' ), 0 ); 
  9. add_action( 'comment_post', array( __CLASS__, 'add_comment_rating' ), 1 ); 
  10. add_action( 'comment_moderation_recipients', array( __CLASS__, 'comment_moderation_recipients' ), 10, 2 ); 
  11.  
  12. // Clear transients 
  13. add_action( 'wp_update_comment_count', array( __CLASS__, 'clear_transients' ) ); 
  14.  
  15. // Secure order notes 
  16. add_filter( 'comments_clauses', array( __CLASS__, 'exclude_order_comments' ), 10, 1 ); 
  17. add_action( 'comment_feed_join', array( __CLASS__, 'exclude_order_comments_from_feed_join' ) ); 
  18. add_action( 'comment_feed_where', array( __CLASS__, 'exclude_order_comments_from_feed_where' ) ); 
  19.  
  20. // Secure webhook comments 
  21. add_filter( 'comments_clauses', array( __CLASS__, 'exclude_webhook_comments' ), 10, 1 ); 
  22. add_action( 'comment_feed_join', array( __CLASS__, 'exclude_webhook_comments_from_feed_join' ) ); 
  23. add_action( 'comment_feed_where', array( __CLASS__, 'exclude_webhook_comments_from_feed_where' ) ); 
  24.  
  25. // Count comments 
  26. add_filter( 'wp_count_comments', array( __CLASS__, 'wp_count_comments' ), 10, 2 ); 
  27.  
  28. // Delete comments count cache whenever there is a new comment or a comment status changes 
  29. add_action( 'wp_insert_comment', array( __CLASS__, 'delete_comments_count_cache' ) ); 
  30. add_action( 'wp_set_comment_status', array( __CLASS__, 'delete_comments_count_cache' ) ); 
  31.  
  32. // Support avatars for `review` comment type 
  33. add_filter( 'get_avatar_comment_types', array( __CLASS__, 'add_avatar_for_review_comment_type' ) ); 
  34.  
  35. // Review of verified purchase 
  36. add_action( 'comment_post', array( __CLASS__, 'add_comment_purchase_verification' ) ); 
  37.  
  38. /** 
  39. * Exclude order comments from queries and RSS. 
  40. * This code should exclude shop_order comments from queries. Some queries (like the recent comments widget on the dashboard) are hardcoded. 
  41. * and are not filtered, however, the code current_user_can( 'read_post', $comment->comment_post_ID ) should keep them safe since only admin and. 
  42. * shop managers can view orders anyway. 
  43. * The frontend view order pages get around this filter by using remove_filter('comments_clauses', array( 'WC_Comments' , 'exclude_order_comments'), 10, 1 ); 
  44. * @param array $clauses 
  45. * @return array 
  46. */ 
  47. public static function exclude_order_comments( $clauses ) { 
  48. global $wpdb, $typenow; 
  49.  
  50. if ( is_admin() && in_array( $typenow, wc_get_order_types() ) && current_user_can( 'manage_woocommerce' ) ) { 
  51. return $clauses; // Don't hide when viewing orders in admin 
  52.  
  53. if ( ! $clauses['join'] ) { 
  54. $clauses['join'] = ''; 
  55.  
  56. if ( ! stristr( $clauses['join'], "JOIN $wpdb->posts ON" ) ) { 
  57. $clauses['join'] .= " LEFT JOIN $wpdb->posts ON comment_post_ID = $wpdb->posts.ID "; 
  58.  
  59. if ( $clauses['where'] ) { 
  60. $clauses['where'] .= ' AND '; 
  61.  
  62. $clauses['where'] .= " $wpdb->posts.post_type NOT IN ('" . implode( "', '", wc_get_order_types() ) . "') "; 
  63.  
  64. return $clauses; 
  65.  
  66. /** 
  67. * Exclude order comments from queries and RSS. 
  68. * @param string $join 
  69. * @return string 
  70. */ 
  71. public static function exclude_order_comments_from_feed_join( $join ) { 
  72. global $wpdb; 
  73.  
  74. if ( ! stristr( $join, "JOIN $wpdb->posts ON" ) ) { 
  75. $join = " LEFT JOIN $wpdb->posts ON $wpdb->comments.comment_post_ID = $wpdb->posts.ID "; 
  76.  
  77. return $join; 
  78.  
  79. /** 
  80. * Exclude order comments from queries and RSS. 
  81. * @param string $where 
  82. * @return string 
  83. */ 
  84. public static function exclude_order_comments_from_feed_where( $where ) { 
  85. global $wpdb; 
  86.  
  87. if ( $where ) { 
  88. $where .= ' AND '; 
  89.  
  90. $where .= " $wpdb->posts.post_type NOT IN ('" . implode( "', '", wc_get_order_types() ) . "') "; 
  91.  
  92. return $where; 
  93.  
  94. /** 
  95. * Exclude webhook comments from queries and RSS. 
  96. * @since 2.2 
  97. * @param array $clauses 
  98. * @return array 
  99. */ 
  100. public static function exclude_webhook_comments( $clauses ) { 
  101. global $wpdb; 
  102.  
  103. if ( ! $clauses['join'] ) { 
  104. $clauses['join'] = ''; 
  105.  
  106. if ( ! strstr( $clauses['join'], "JOIN $wpdb->posts" ) ) { 
  107. $clauses['join'] .= " LEFT JOIN $wpdb->posts ON comment_post_ID = $wpdb->posts.ID "; 
  108.  
  109. if ( $clauses['where'] ) { 
  110. $clauses['where'] .= ' AND '; 
  111.  
  112. $clauses['where'] .= " $wpdb->posts.post_type <> 'shop_webhook' "; 
  113.  
  114. return $clauses; 
  115.  
  116. /** 
  117. * Exclude webhook comments from queries and RSS. 
  118. * @since 2.2 
  119. * @param string $join 
  120. * @return string 
  121. */ 
  122. public static function exclude_webhook_comments_from_feed_join( $join ) { 
  123. global $wpdb; 
  124.  
  125. if ( ! strstr( $join, $wpdb->posts ) ) { 
  126. $join = " LEFT JOIN $wpdb->posts ON $wpdb->comments.comment_post_ID = $wpdb->posts.ID "; 
  127.  
  128. return $join; 
  129.  
  130. /** 
  131. * Exclude webhook comments from queries and RSS. 
  132. * @since 2.1 
  133. * @param string $where 
  134. * @return string 
  135. */ 
  136. public static function exclude_webhook_comments_from_feed_where( $where ) { 
  137. global $wpdb; 
  138.  
  139. if ( $where ) { 
  140. $where .= ' AND '; 
  141.  
  142. $where .= " $wpdb->posts.post_type <> 'shop_webhook' "; 
  143.  
  144. return $where; 
  145.  
  146. /** 
  147. * Validate the comment ratings. 
  148. * @param array $comment_data 
  149. * @return array 
  150. */ 
  151. public static function check_comment_rating( $comment_data ) { 
  152. // If posting a comment (not trackback etc) and not logged in 
  153. if ( ! is_admin() && isset( $_POST['comment_post_ID'], $_POST['rating'], $comment_data['comment_type'] ) && 'product' === get_post_type( $_POST['comment_post_ID'] ) && empty( $_POST['rating'] ) && '' === $comment_data['comment_type'] && 'yes' === get_option( 'woocommerce_enable_review_rating' ) && 'yes' === get_option( 'woocommerce_review_rating_required' ) ) { 
  154. wp_die( __( 'Please rate the product.', 'woocommerce' ) ); 
  155. exit; 
  156. return $comment_data; 
  157.  
  158. /** 
  159. * Rating field for comments. 
  160. * @param int $comment_id 
  161. */ 
  162. public static function add_comment_rating( $comment_id ) { 
  163. if ( isset( $_POST['rating'] ) && 'product' === get_post_type( $_POST['comment_post_ID'] ) ) { 
  164. if ( ! $_POST['rating'] || $_POST['rating'] > 5 || $_POST['rating'] < 0 ) { 
  165. return; 
  166. add_comment_meta( $comment_id, 'rating', (int) esc_attr( $_POST['rating'] ), true ); 
  167.  
  168. $post_id = isset( $_POST['comment_post_ID'] ) ? (int) $_POST['comment_post_ID'] : 0; 
  169. if ( $post_id ) { 
  170. self::clear_transients( $post_id ); 
  171.  
  172. /** 
  173. * Modify recipient of review email. 
  174. * @param array $emails 
  175. * @param int $comment_id 
  176. * @return array 
  177. */ 
  178. public static function comment_moderation_recipients( $emails, $comment_id ) { 
  179. $comment = get_comment( $comment_id ); 
  180.  
  181. if ( $comment && 'product' === get_post_type( $comment->comment_post_ID ) ) { 
  182. $emails = array( get_option( 'admin_email' ) ); 
  183.  
  184. return $emails; 
  185.  
  186. /** 
  187. * Ensure product average rating and review count is kept up to date. 
  188. * @param int $post_id 
  189. */ 
  190. public static function clear_transients( $post_id ) { 
  191.  
  192. if ( 'product' === get_post_type( $post_id ) ) { 
  193. $product = wc_get_product( $post_id ); 
  194. self::get_rating_counts_for_product( $product ); 
  195. self::get_average_rating_for_product( $product ); 
  196. self::get_review_count_for_product( $product ); 
  197.  
  198. /** 
  199. * Delete comments count cache whenever there is 
  200. * new comment or the status of a comment changes. Cache 
  201. * will be regenerated next time WC_Comments::wp_count_comments() 
  202. * is called. 
  203. * @return void 
  204. */ 
  205. public static function delete_comments_count_cache() { 
  206. delete_transient( 'wc_count_comments' ); 
  207.  
  208. /** 
  209. * Remove order notes and webhook delivery logs from wp_count_comments(). 
  210. * @since 2.2 
  211. * @param object $stats Comment stats. 
  212. * @param int $post_id Post ID. 
  213. * @return object 
  214. */ 
  215. public static function wp_count_comments( $stats, $post_id ) { 
  216. global $wpdb; 
  217.  
  218. if ( 0 === $post_id ) { 
  219. $stats = get_transient( 'wc_count_comments' ); 
  220.  
  221. if ( ! $stats ) { 
  222. $stats = array(); 
  223.  
  224. $count = $wpdb->get_results( " 
  225. SELECT comment_approved, COUNT(*) AS num_comments 
  226. FROM {$wpdb->comments} 
  227. WHERE comment_type NOT IN ('order_note', 'webhook_delivery') 
  228. GROUP BY comment_approved 
  229. ", ARRAY_A ); 
  230.  
  231. $total = 0; 
  232. $approved = array( 
  233. '0' => 'moderated',  
  234. '1' => 'approved',  
  235. 'spam' => 'spam',  
  236. 'trash' => 'trash',  
  237. 'post-trashed' => 'post-trashed',  
  238. ); 
  239.  
  240. foreach ( (array) $count as $row ) { 
  241. // Don't count post-trashed toward totals. 
  242. if ( 'post-trashed' !== $row['comment_approved'] && 'trash' !== $row['comment_approved'] ) { 
  243. $total += $row['num_comments']; 
  244. if ( isset( $approved[ $row['comment_approved'] ] ) ) { 
  245. $stats[ $approved[ $row['comment_approved'] ] ] = $row['num_comments']; 
  246.  
  247. $stats['total_comments'] = $total; 
  248. $stats['all'] = $total; 
  249. foreach ( $approved as $key ) { 
  250. if ( empty( $stats[ $key ] ) ) { 
  251. $stats[ $key ] = 0; 
  252.  
  253. $stats = (object) $stats; 
  254. set_transient( 'wc_count_comments', $stats ); 
  255.  
  256. return $stats; 
  257.  
  258. /** 
  259. * Make sure WP displays avatars for comments with the `review` type. 
  260. * @since 2.3 
  261. * @param array $comment_types 
  262. * @return array 
  263. */ 
  264. public static function add_avatar_for_review_comment_type( $comment_types ) { 
  265. return array_merge( $comment_types, array( 'review' ) ); 
  266.  
  267. /** 
  268. * Determine if a review is from a verified owner at submission. 
  269. * @param int $comment_id 
  270. * @return bool 
  271. */ 
  272. public static function add_comment_purchase_verification( $comment_id ) { 
  273. $comment = get_comment( $comment_id ); 
  274. $verified = false; 
  275. if ( 'product' === get_post_type( $comment->comment_post_ID ) ) { 
  276. $verified = wc_customer_bought_product( $comment->comment_author_email, $comment->user_id, $comment->comment_post_ID ); 
  277. add_comment_meta( $comment_id, 'verified', (int) $verified, true ); 
  278. return $verified; 
  279.  
  280. /** 
  281. * Get product rating for a product. Please note this is not cached. 
  282. * @since 3.0.0 
  283. * @param WC_Product $product 
  284. * @return float 
  285. */ 
  286. public static function get_average_rating_for_product( &$product ) { 
  287. global $wpdb; 
  288.  
  289. $count = $product->get_rating_count(); 
  290.  
  291. if ( $count ) { 
  292. $ratings = $wpdb->get_var( $wpdb->prepare(" 
  293. SELECT SUM(meta_value) FROM $wpdb->commentmeta 
  294. LEFT JOIN $wpdb->comments ON $wpdb->commentmeta.comment_id = $wpdb->comments.comment_ID 
  295. WHERE meta_key = 'rating' 
  296. AND comment_post_ID = %d 
  297. AND comment_approved = '1' 
  298. AND meta_value > 0 
  299. ", $product->get_id() ) ); 
  300. $average = number_format( $ratings / $count, 2, '.', '' ); 
  301. } else { 
  302. $average = 0; 
  303.  
  304. $product->set_average_rating( $average ); 
  305.  
  306. $data_store = $product->get_data_store(); 
  307. $data_store->update_average_rating( $product ); 
  308.  
  309. return $average; 
  310.  
  311. /** 
  312. * Get product review count for a product (not replies). Please note this is not cached. 
  313. * @since 3.0.0 
  314. * @param WC_Product $product 
  315. * @return int 
  316. */ 
  317. public static function get_review_count_for_product( &$product ) { 
  318. global $wpdb; 
  319.  
  320. $count = $wpdb->get_var( $wpdb->prepare(" 
  321. SELECT COUNT(*) FROM $wpdb->comments 
  322. WHERE comment_parent = 0 
  323. AND comment_post_ID = %d 
  324. AND comment_approved = '1' 
  325. ", $product->get_id() ) ); 
  326.  
  327. $product->set_review_count( $count ); 
  328.  
  329. $data_store = $product->get_data_store(); 
  330. $data_store->update_review_count( $product ); 
  331.  
  332. return $count; 
  333.  
  334. /** 
  335. * Get product rating count for a product. Please note this is not cached. 
  336. * @since 3.0.0 
  337. * @param WC_Product $product 
  338. * @return array of integers 
  339. */ 
  340. public static function get_rating_counts_for_product( &$product ) { 
  341. global $wpdb; 
  342.  
  343. $counts = array(); 
  344. $raw_counts = $wpdb->get_results( $wpdb->prepare( " 
  345. SELECT meta_value, COUNT( * ) as meta_value_count FROM $wpdb->commentmeta 
  346. LEFT JOIN $wpdb->comments ON $wpdb->commentmeta.comment_id = $wpdb->comments.comment_ID 
  347. WHERE meta_key = 'rating' 
  348. AND comment_post_ID = %d 
  349. AND comment_approved = '1' 
  350. AND meta_value > 0 
  351. GROUP BY meta_value 
  352. ", $product->get_id() ) ); 
  353.  
  354. foreach ( $raw_counts as $count ) { 
  355. $counts[ $count->meta_value ] = absint( $count->meta_value_count ); 
  356.  
  357. $product->set_rating_counts( $counts ); 
  358.  
  359. $data_store = $product->get_data_store(); 
  360. $data_store->update_rating_counts( $product ); 
  361.  
  362. return $counts;