PluginProbe
WebberZone Top 10 — Popular Posts / 4.3.0
WebberZone Top 10 — Popular Posts v4.3.0
4.5.2 4.5.1 4.5.0 4.4.3 4.4.2 4.4.1 4.4.0 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 trunk 1.0 1.0.1 1.1 1.2 1.3 1.4 1.4.1 1.5 1.5.1 1.5.2 1.5.3 1.6 All 118 releases
top-10 / includes / class-counter.php

class-counter.php in WebberZone Top 10 — Popular Posts 4.3.0, at includes/class-counter.php

460 lines 13.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Counter class.
4 *
5 * @package WebberZone\Top_Ten
6 */
7
8 namespace WebberZone\Top_Ten;
9
10 use WebberZone\Top_Ten\Database;
11 use WebberZone\Top_Ten\Util\Helpers;
12 use WebberZone\Top_Ten\Util\Hook_Registry;
13
14 if ( ! defined( 'WPINC' ) ) {
15 exit;
16 }
17
18 /**
19 * Admin Columns Class.
20 *
21 * @since 3.3.0
22 */
23 class Counter {
24
25 /**
26 * Constructor class.
27 *
28 * @since 3.3.0
29 */
30 public function __construct() {
31 Hook_Registry::add_filter( 'the_content', array( __CLASS__, 'the_content' ) );
32 Hook_Registry::add_filter( 'the_excerpt_rss', array( __CLASS__, 'rss_filter' ) );
33 Hook_Registry::add_filter( 'the_content_feed', array( __CLASS__, 'rss_filter' ) );
34 Hook_Registry::add_action( 'wp_ajax_tptn_edit_count_ajax', array( __CLASS__, 'edit_count_ajax' ) );
35 }
36
37 /**
38 * Adds the viewed count to the post content. Filters `the_content`.
39 *
40 * @since 3.3.0
41 *
42 * @param string $content Post content.
43 * @return string Filtered post content.
44 */
45 public static function the_content( $content ) {
46 global $post, $wp_filters;
47
48 // Track the number of times this function is called.
49 static $filter_calls = 0;
50 ++$filter_calls;
51
52 // Check if this is the last call of 'the_content' and only process for the main query.
53 if ( ! ( in_the_loop() && is_main_query() && (int) get_queried_object_id() === (int) $post->ID ) || ( doing_filter( 'the_content' ) && isset( $wp_filters['the_content'] ) && (int) $wp_filters['the_content'] !== $filter_calls ) ) {
54 return $content;
55 }
56
57 // Exclude posts that should not display the viewed count.
58 $exclude_on_post_ids = explode( ',', \tptn_get_option( 'exclude_on_post_ids' ) );
59 if ( isset( $post ) && in_array( $post->ID, $exclude_on_post_ids, true ) ) {
60 return $content;
61 }
62
63 // Determine where to add the viewed count.
64 $add_to = wp_parse_list( \tptn_get_option( 'add_to', array() ) );
65
66 $conditions = array(
67 'single' => is_single(),
68 'page' => is_page(),
69 'home' => is_home(),
70 'category_archives' => is_category(),
71 'tag_archives' => is_tag(),
72 'other_archives' => is_tax() || is_author() || is_date(),
73 );
74
75 foreach ( $conditions as $key => $condition ) {
76 if ( $condition && in_array( $key, $add_to, true ) ) {
77 return $content . self::echo_post_count( 0 );
78 }
79 }
80
81 return $content;
82 }
83
84
85 /**
86 * Filter to display the post count when viewing feeds.
87 *
88 * @since 1.9.8
89 *
90 * @param string $content Post content.
91 * @return string Filtered post content
92 */
93 public static function rss_filter( $content ) {
94 global $post;
95
96 $id = intval( $post->ID );
97
98 $add_to = \tptn_get_option( 'add_to', false );
99
100 if ( ! empty( $add_to['feed'] ) ) {
101 return $content . '<div class="tptn_counter" id="tptn_counter_' . $id . '">' . self::get_post_count( $id ) . '</div>';
102 } else {
103 return $content;
104 }
105 }
106
107 /**
108 * Function to manually display count.
109 *
110 * @since 1.0
111 * @param int|boolean $echo_output Flag to echo the output.
112 * @return string|void Formatted string if $echo_output is set to 0|false
113 */
114 public static function echo_post_count( $echo_output = 1 ) {
115 global $post;
116
117 $home_url = home_url( '/' );
118
119 /**
120 * Filter the script URL of the counter.
121 *
122 * @since 2.0
123 */
124 $home_url = apply_filters( 'tptn_view_counter_script_url', $home_url );
125
126 // Strip any query strings since we don't need them.
127 $home_url = strtok( $home_url, '?' );
128
129 $id = intval( $post->ID );
130
131 $nonce_action = 'tptn-nonce-' . $id;
132 $nonce = wp_create_nonce( $nonce_action );
133
134 if ( \tptn_get_option( 'dynamic_post_count' ) ) {
135 $output = sprintf(
136 '<div class="tptn_counter" id="tptn_counter_%1$d"><script type="text/javascript" data-cfasync="false" src="%2$s?top_ten_id=%1$d&view_counter=1&_wpnonce=%3$s"></script></div>', // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript
137 $id,
138 $home_url,
139 $nonce
140 );
141 } else {
142 $output = '<div class="tptn_counter" id="tptn_counter_' . $id . '">' . self::get_post_count( $id ) . '</div>';
143 }
144
145 /**
146 * Filter the viewed count script
147 *
148 * @since 2.0.0
149 *
150 * @param string $output Counter viewed count code
151 */
152 $output = apply_filters( 'tptn_view_post_count', $output );
153
154 if ( $echo_output ) {
155 echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
156 } else {
157 return $output;
158 }
159 }
160
161
162 /**
163 * Return the formatted post count for the supplied ID.
164 *
165 * @since 3.3.0
166 * @since 4.0.0 Added $args parameter.
167 *
168 * @param int|string|\WP_Post $post Post ID or WP_Post object.
169 * @param int|string $blog_id Blog ID.
170 * @param array $args Additional arguments.
171 * @return string Formatted post count
172 */
173 public static function get_post_count( $post = 0, $blog_id = 0, $args = array() ) {
174 if ( $post instanceof \WP_Post ) {
175 $id = $post->ID;
176 } else {
177 $id = absint( $post );
178 }
179
180 if ( $id <= 0 ) {
181 return '';
182 }
183
184 $count_disp_form = isset( $args['count_disp_form'] ) ? $args['count_disp_form'] : stripslashes( \tptn_get_option( 'count_disp_form' ) );
185 $count_disp_form_zero = isset( $args['count_disp_form_zero'] ) ? $args['count_disp_form_zero'] : stripslashes( \tptn_get_option( 'count_disp_form_zero' ) );
186 $total_count = self::get_post_count_only( $id, 'total', $blog_id );
187 $is_singular = is_singular();
188 $is_zero_total_count = ( 0 === (int) $total_count );
189
190 if ( $is_zero_total_count && ! $is_singular ) {
191 $count_disp_form_zero = str_replace(
192 '%totalcount%',
193 (string) $total_count,
194 $count_disp_form_zero
195 );
196 } else {
197 $count_disp_form = str_replace(
198 '%totalcount%',
199 Helpers::number_format_i18n( $is_zero_total_count ? $total_count + 1 : $total_count ),
200 $count_disp_form
201 );
202 }
203
204 foreach ( array( 'daily', 'overall' ) as $type ) {
205 if ( false !== strpos( $count_disp_form, "%{$type}count%" ) || false !== strpos( $count_disp_form_zero, "%{$type}count%" ) ) {
206 $count = self::get_post_count_only( $id, $type );
207 if ( $is_zero_total_count && ! $is_singular ) {
208 $count_disp_form_zero = str_replace(
209 "%{$type}count%",
210 (string) $count,
211 $count_disp_form_zero
212 );
213 } else {
214 $is_zero_cntaccess = ( 0 === (int) $count );
215 $count_disp_form = str_replace(
216 "%{$type}count%",
217 Helpers::number_format_i18n( $is_zero_cntaccess ? $count + 1 : $count ),
218 $count_disp_form
219 );
220 }
221 }
222 }
223
224 return apply_filters( 'tptn_post_count', ( $is_zero_total_count && ! $is_singular ) ? $count_disp_form_zero : $count_disp_form );
225 }
226
227 /**
228 * Returns the post count.
229 *
230 * @since 3.3.0
231 *
232 * @param int|\WP_Post $post Post ID or WP_Post object.
233 * @param string $counter Which count to return? total, daily or overall.
234 * @param int $blog_id Blog ID.
235 * @param array $args Additional arguments.
236 * @return int|string Post count
237 */
238 public static function get_post_count_only( $post = 0, $counter = 'total', $blog_id = 0, $args = array() ) {
239 global $wpdb;
240
241 if ( $post instanceof \WP_Post ) {
242 $id = $post->ID;
243 } else {
244 $id = absint( $post );
245 }
246
247 $defaults = array(
248 'format_number' => false,
249 'from_date' => '',
250 'to_date' => '',
251 );
252 $args = wp_parse_args( $args, $defaults );
253
254 // Sanitize the attributes.
255 $args = Helpers::sanitize_args( $args );
256
257 if ( empty( $blog_id ) ) {
258 $blog_id = get_current_blog_id();
259 }
260
261 if ( $id > 0 || 'overall' === $counter ) {
262 $post_count = 0;
263 switch ( $counter ) {
264 case 'total':
265 $post_count = Database::get_count( $id, $blog_id, false );
266 break;
267 case 'daily':
268 $date_range = array();
269 if ( ! empty( $args['from_date'] ) ) {
270 $date_range['from_date'] = Helpers::get_from_date( $args['from_date'], 0, 0 );
271 }
272 if ( ! empty( $args['to_date'] ) ) {
273 $date_range['to_date'] = Helpers::get_from_date( $args['to_date'], 0, 0 );
274 }
275 if ( empty( $date_range ) ) {
276 $date_range['from_date'] = Helpers::get_from_date();
277 }
278 $post_count = Database::get_count( $id, $blog_id, true, $date_range );
279 break;
280 case 'overall':
281 $post_count = Database::get_total_count( $blog_id, false );
282 break;
283 }
284 if ( $args['format_number'] ) {
285 $post_count = number_format_i18n( $post_count );
286 }
287
288 /**
289 * Returns the post count.
290 *
291 * @since 2.6.0
292 *
293 * @param int|string $post_count Post count.
294 * @param mixed $id Post ID.
295 * @param string $counter Which count to return? total, daily or overall.
296 * @param int $blog_id Blog ID.
297 */
298 return apply_filters( 'tptn_post_count_only', $post_count, $id, $counter, $blog_id );
299 } else {
300 return 0;
301 }
302 }
303
304
305 /**
306 * Delete the counts from the selected table.
307 *
308 * @since 3.3.0
309 *
310 * @param string|array $args {
311 * Optional. Array or string of Query parameters.
312 *
313 * @type bool $daily Set to true for daily table. False for overall.
314 * @type array|string $post_id An array or comma-separated string of post IDs. Empty string or array for all IDs. Default is blank.
315 * @type array|string $blog_id An array or comma-separated string of blog IDs. Empty string or array for all IDs. Default is current blog ID.
316 * @type string $db_date The date before which to delete data. Default is empty string which means all dates. Applies to daily table only.
317 * }
318 * @return int|false The number of rows updated, or false on error.
319 */
320 public static function delete_counts( $args = array() ) {
321 $defaults = array(
322 'daily' => true,
323 'post_id' => '',
324 'blog_id' => get_current_blog_id(),
325 'dp_date' => '',
326 );
327 $args = wp_parse_args( $args, $defaults );
328
329 // Convert the arguments to match Database class format.
330 $db_args = array(
331 'daily' => $args['daily'],
332 'post_ids' => wp_parse_id_list( $args['post_id'] ),
333 'to_date' => $args['dp_date'],
334 );
335
336 // Handle blog_id conversion.
337 if ( ! empty( $args['blog_id'] ) && is_array( $args['blog_id'] ) ) {
338 // If multiple blog IDs, we need to delete for each one.
339 $result = 0;
340 foreach ( $args['blog_id'] as $blog_id ) {
341 $db_args['blog_id'] = $blog_id;
342 $result += Database::delete_counts( $db_args );
343 }
344 return $result;
345 } else {
346 $db_args['blog_id'] = is_array( $args['blog_id'] ) ? reset( $args['blog_id'] ) : $args['blog_id'];
347 return Database::delete_counts( $db_args );
348 }
349 }
350
351
352 /**
353 * Delete post count.
354 *
355 * @since 3.3.0
356 *
357 * @param int $post_id Post ID.
358 * @param int $blog_id Blog ID.
359 * @param bool $daily Daily flag.
360 * @return bool|int Number of rows affected or false if error.
361 */
362 public static function delete_count( $post_id, $blog_id, $daily = false ) {
363 global $wpdb;
364
365 $post_id = intval( $post_id );
366 $blog_id = intval( $blog_id );
367
368 if ( empty( $post_id ) || empty( $blog_id ) ) {
369 return false;
370 }
371
372 $results = self::delete_counts(
373 array(
374 'post_id' => $post_id,
375 'blog_id' => $blog_id,
376 'daily' => $daily,
377 )
378 );
379
380 return $results;
381 }
382
383
384 /**
385 * Function to update the Top 10 count with ajax.
386 *
387 * @since 3.3.0
388 */
389 public static function edit_count_ajax() {
390 // Security check.
391 check_ajax_referer( 'top_ten_admin_nonce', 'top_ten_admin_nonce' );
392
393 if ( ! isset( $_REQUEST['total_count'] ) || ! isset( $_REQUEST['post_id'] ) || ! isset( $_REQUEST['total_count_original'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
394 wp_die();
395 }
396
397 $results = 0;
398
399 $post_id = absint( $_REQUEST['post_id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
400 $blog_id = isset( $_REQUEST['blog_id'] ) ? absint( $_REQUEST['blog_id'] ) : get_current_blog_id(); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
401 $total_count = absint( filter_var( $_REQUEST['total_count'], FILTER_SANITIZE_NUMBER_INT ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
402 $total_count_original = absint( filter_var( $_REQUEST['total_count_original'], FILTER_SANITIZE_NUMBER_INT ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
403
404 // Check permissions.
405 if ( isset( $_REQUEST['blog_id'] ) && absint( $_REQUEST['blog_id'] ) !== get_current_blog_id() ) {
406 // In network mode (editing a different blog's data), require manage_network capability.
407 if ( ! current_user_can( 'manage_network' ) ) {
408 wp_die();
409 }
410 } else {
411 // Switch to the target blog to check edit permissions.
412 $target_blog_id = isset( $_REQUEST['blog_id'] ) ? absint( $_REQUEST['blog_id'] ) : get_current_blog_id();
413
414 if ( get_current_blog_id() !== $target_blog_id ) {
415 switch_to_blog( $target_blog_id );
416 }
417
418 $can_edit = current_user_can( 'edit_post', $post_id );
419
420 // Switch back if we switched.
421 if ( get_current_blog_id() !== $target_blog_id ) {
422 restore_current_blog();
423 }
424
425 if ( ! $can_edit ) {
426 wp_die();
427 }
428 }
429
430 if ( $total_count_original !== $total_count ) {
431 $results = self::edit_count( $post_id, $blog_id, $total_count );
432 }
433 echo wp_json_encode( $results );
434 wp_die();
435 }
436
437 /**
438 * Edit post count.
439 *
440 * @since 3.3.0
441 *
442 * @param int $post_id Post ID.
443 * @param int $blog_id Blog ID.
444 * @param int $total_count Total count.
445 * @return bool|int Number of rows affected or false if error.
446 */
447 public static function edit_count( $post_id, $blog_id, $total_count ) {
448
449 $post_id = intval( $post_id );
450 $blog_id = intval( $blog_id );
451 $total_count = intval( $total_count );
452
453 if ( empty( $post_id ) || empty( $blog_id ) || empty( $total_count ) ) {
454 return false;
455 }
456
457 return Database::set_count( $post_id, $total_count, $blog_id, false );
458 }
459 }
460