PluginProbe
WebberZone Top 10 — Popular Posts / 4.3.2
WebberZone Top 10 — Popular Posts v4.3.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 1.6.1 All 117 releases
top-10 / includes / class-counter.php

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

476 lines 13.8 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 if ( \tptn_get_option( 'dynamic_post_count' ) ) {
132 $nonce_action = 'tptn-nonce-' . $id;
133 $nonce = wp_create_nonce( $nonce_action );
134
135 $fetch_url = add_query_arg(
136 array(
137 'top_ten_id' => $id,
138 'view_counter' => 1,
139 '_wpnonce' => $nonce,
140 ),
141 $home_url
142 );
143
144 wp_enqueue_script(
145 'tptn-counter',
146 plugins_url( 'includes/js/top-10-counter.min.js', TOP_TEN_PLUGIN_FILE ),
147 array(),
148 TOP_TEN_VERSION,
149 true
150 );
151
152 $output = sprintf(
153 '<div class="tptn_counter" id="tptn_counter_%1$d" data-tptn-url="%2$s"></div>',
154 $id,
155 esc_url( $fetch_url )
156 );
157 } else {
158 $output = '<div class="tptn_counter" id="tptn_counter_' . $id . '">' . self::get_post_count( $id ) . '</div>';
159 }
160
161 /**
162 * Filter the viewed count script
163 *
164 * @since 2.0.0
165 *
166 * @param string $output Counter viewed count code
167 */
168 $output = apply_filters( 'tptn_view_post_count', $output );
169
170 if ( $echo_output ) {
171 echo $output; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
172 } else {
173 return $output;
174 }
175 }
176
177
178 /**
179 * Return the formatted post count for the supplied ID.
180 *
181 * @since 3.3.0
182 * @since 4.0.0 Added $args parameter.
183 *
184 * @param int|string|\WP_Post $post Post ID or WP_Post object.
185 * @param int|string $blog_id Blog ID.
186 * @param array $args Additional arguments.
187 * @return string Formatted post count
188 */
189 public static function get_post_count( $post = 0, $blog_id = 0, $args = array() ) {
190 if ( $post instanceof \WP_Post ) {
191 $id = $post->ID;
192 } else {
193 $id = absint( $post );
194 }
195
196 if ( $id <= 0 ) {
197 return '';
198 }
199
200 $count_disp_form = isset( $args['count_disp_form'] ) ? $args['count_disp_form'] : stripslashes( \tptn_get_option( 'count_disp_form' ) );
201 $count_disp_form_zero = isset( $args['count_disp_form_zero'] ) ? $args['count_disp_form_zero'] : stripslashes( \tptn_get_option( 'count_disp_form_zero' ) );
202 $total_count = self::get_post_count_only( $id, 'total', $blog_id );
203 $is_singular = is_singular();
204 $is_zero_total_count = ( 0 === (int) $total_count );
205
206 if ( $is_zero_total_count && ! $is_singular ) {
207 $count_disp_form_zero = str_replace(
208 '%totalcount%',
209 (string) $total_count,
210 $count_disp_form_zero
211 );
212 } else {
213 $count_disp_form = str_replace(
214 '%totalcount%',
215 Helpers::number_format_i18n( $is_zero_total_count ? $total_count + 1 : $total_count ),
216 $count_disp_form
217 );
218 }
219
220 foreach ( array( 'daily', 'overall' ) as $type ) {
221 if ( false !== strpos( $count_disp_form, "%{$type}count%" ) || false !== strpos( $count_disp_form_zero, "%{$type}count%" ) ) {
222 $count = self::get_post_count_only( $id, $type );
223 if ( $is_zero_total_count && ! $is_singular ) {
224 $count_disp_form_zero = str_replace(
225 "%{$type}count%",
226 (string) $count,
227 $count_disp_form_zero
228 );
229 } else {
230 $is_zero_cntaccess = ( 0 === (int) $count );
231 $count_disp_form = str_replace(
232 "%{$type}count%",
233 Helpers::number_format_i18n( $is_zero_cntaccess ? $count + 1 : $count ),
234 $count_disp_form
235 );
236 }
237 }
238 }
239
240 return apply_filters( 'tptn_post_count', ( $is_zero_total_count && ! $is_singular ) ? $count_disp_form_zero : $count_disp_form );
241 }
242
243 /**
244 * Returns the post count.
245 *
246 * @since 3.3.0
247 *
248 * @param int|\WP_Post $post Post ID or WP_Post object.
249 * @param string $counter Which count to return? total, daily or overall.
250 * @param int $blog_id Blog ID.
251 * @param array $args Additional arguments.
252 * @return int|string Post count
253 */
254 public static function get_post_count_only( $post = 0, $counter = 'total', $blog_id = 0, $args = array() ) {
255 global $wpdb;
256
257 if ( $post instanceof \WP_Post ) {
258 $id = $post->ID;
259 } else {
260 $id = absint( $post );
261 }
262
263 $defaults = array(
264 'format_number' => false,
265 'from_date' => '',
266 'to_date' => '',
267 );
268 $args = wp_parse_args( $args, $defaults );
269
270 // Sanitize the attributes.
271 $args = Helpers::sanitize_args( $args );
272
273 if ( empty( $blog_id ) ) {
274 $blog_id = get_current_blog_id();
275 }
276
277 if ( $id > 0 || 'overall' === $counter ) {
278 $post_count = 0;
279 switch ( $counter ) {
280 case 'total':
281 $post_count = Database::get_count( $id, $blog_id, false );
282 break;
283 case 'daily':
284 $date_range = array();
285 if ( ! empty( $args['from_date'] ) ) {
286 $date_range['from_date'] = Helpers::get_from_date( $args['from_date'], 0, 0 );
287 }
288 if ( ! empty( $args['to_date'] ) ) {
289 $date_range['to_date'] = Helpers::get_from_date( $args['to_date'], 0, 0 );
290 }
291 if ( empty( $date_range ) ) {
292 $date_range['from_date'] = Helpers::get_from_date();
293 }
294 $post_count = Database::get_count( $id, $blog_id, true, $date_range );
295 break;
296 case 'overall':
297 $post_count = Database::get_total_count( $blog_id, false );
298 break;
299 }
300 if ( $args['format_number'] ) {
301 $post_count = number_format_i18n( $post_count );
302 }
303
304 /**
305 * Returns the post count.
306 *
307 * @since 2.6.0
308 *
309 * @param int|string $post_count Post count.
310 * @param mixed $id Post ID.
311 * @param string $counter Which count to return? total, daily or overall.
312 * @param int $blog_id Blog ID.
313 */
314 return apply_filters( 'tptn_post_count_only', $post_count, $id, $counter, $blog_id );
315 } else {
316 return 0;
317 }
318 }
319
320
321 /**
322 * Delete the counts from the selected table.
323 *
324 * @since 3.3.0
325 *
326 * @param string|array $args {
327 * Optional. Array or string of Query parameters.
328 *
329 * @type bool $daily Set to true for daily table. False for overall.
330 * @type array|string $post_id An array or comma-separated string of post IDs. Empty string or array for all IDs. Default is blank.
331 * @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.
332 * @type string $db_date The date before which to delete data. Default is empty string which means all dates. Applies to daily table only.
333 * }
334 * @return int|false The number of rows updated, or false on error.
335 */
336 public static function delete_counts( $args = array() ) {
337 $defaults = array(
338 'daily' => true,
339 'post_id' => '',
340 'blog_id' => get_current_blog_id(),
341 'dp_date' => '',
342 );
343 $args = wp_parse_args( $args, $defaults );
344
345 // Convert the arguments to match Database class format.
346 $db_args = array(
347 'daily' => $args['daily'],
348 'post_ids' => wp_parse_id_list( $args['post_id'] ),
349 'to_date' => $args['dp_date'],
350 );
351
352 // Handle blog_id conversion.
353 if ( ! empty( $args['blog_id'] ) && is_array( $args['blog_id'] ) ) {
354 // If multiple blog IDs, we need to delete for each one.
355 $result = 0;
356 foreach ( $args['blog_id'] as $blog_id ) {
357 $db_args['blog_id'] = $blog_id;
358 $result += Database::delete_counts( $db_args );
359 }
360 return $result;
361 } else {
362 $db_args['blog_id'] = is_array( $args['blog_id'] ) ? reset( $args['blog_id'] ) : $args['blog_id'];
363 return Database::delete_counts( $db_args );
364 }
365 }
366
367
368 /**
369 * Delete post count.
370 *
371 * @since 3.3.0
372 *
373 * @param int $post_id Post ID.
374 * @param int $blog_id Blog ID.
375 * @param bool $daily Daily flag.
376 * @return bool|int Number of rows affected or false if error.
377 */
378 public static function delete_count( $post_id, $blog_id, $daily = false ) {
379 global $wpdb;
380
381 $post_id = intval( $post_id );
382 $blog_id = intval( $blog_id );
383
384 if ( empty( $post_id ) || empty( $blog_id ) ) {
385 return false;
386 }
387
388 $results = self::delete_counts(
389 array(
390 'post_id' => $post_id,
391 'blog_id' => $blog_id,
392 'daily' => $daily,
393 )
394 );
395
396 return $results;
397 }
398
399
400 /**
401 * Function to update the Top 10 count with ajax.
402 *
403 * @since 3.3.0
404 */
405 public static function edit_count_ajax() {
406 // Security check.
407 check_ajax_referer( 'top_ten_admin_nonce', 'top_ten_admin_nonce' );
408
409 if ( ! isset( $_REQUEST['total_count'] ) || ! isset( $_REQUEST['post_id'] ) || ! isset( $_REQUEST['total_count_original'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
410 wp_die();
411 }
412
413 $results = 0;
414
415 $post_id = absint( $_REQUEST['post_id'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
416 $blog_id = isset( $_REQUEST['blog_id'] ) ? absint( $_REQUEST['blog_id'] ) : get_current_blog_id(); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
417 $total_count = absint( filter_var( $_REQUEST['total_count'], FILTER_SANITIZE_NUMBER_INT ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
418 $total_count_original = absint( filter_var( $_REQUEST['total_count_original'], FILTER_SANITIZE_NUMBER_INT ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
419
420 // Check permissions.
421 if ( isset( $_REQUEST['blog_id'] ) && absint( $_REQUEST['blog_id'] ) !== get_current_blog_id() ) {
422 // In network mode (editing a different blog's data), require manage_network capability.
423 if ( ! current_user_can( 'manage_network' ) ) {
424 wp_die();
425 }
426 } else {
427 // Switch to the target blog to check edit permissions.
428 $target_blog_id = isset( $_REQUEST['blog_id'] ) ? absint( $_REQUEST['blog_id'] ) : get_current_blog_id();
429
430 if ( get_current_blog_id() !== $target_blog_id ) {
431 switch_to_blog( $target_blog_id );
432 }
433
434 $can_edit = current_user_can( 'edit_post', $post_id );
435
436 // Switch back if we switched.
437 if ( get_current_blog_id() !== $target_blog_id ) {
438 restore_current_blog();
439 }
440
441 if ( ! $can_edit ) {
442 wp_die();
443 }
444 }
445
446 if ( $total_count_original !== $total_count ) {
447 $results = self::edit_count( $post_id, $blog_id, $total_count );
448 }
449 echo wp_json_encode( $results );
450 wp_die();
451 }
452
453 /**
454 * Edit post count.
455 *
456 * @since 3.3.0
457 *
458 * @param int $post_id Post ID.
459 * @param int $blog_id Blog ID.
460 * @param int $total_count Total count.
461 * @return bool|int Number of rows affected or false if error.
462 */
463 public static function edit_count( $post_id, $blog_id, $total_count ) {
464
465 $post_id = intval( $post_id );
466 $blog_id = intval( $blog_id );
467 $total_count = intval( $total_count );
468
469 if ( empty( $post_id ) || empty( $blog_id ) || empty( $total_count ) ) {
470 return false;
471 }
472
473 return Database::set_count( $post_id, $total_count, $blog_id, false );
474 }
475 }
476