Completed
Pull Request — master (#11471)
by Claudio
09:36
created

WC_Comments::delete_comments_count_cache()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

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