PluginProbe ʕ •ᴥ•ʔ
WP Popular Posts / 5.2.4
WP Popular Posts v5.2.4
4.0.8 4.0.9 4.1.0 4.1.1 4.1.2 4.2.0 4.2.1 4.2.2 5.0.0 5.0.1 5.0.2 5.1.0 5.2.0 5.2.1 5.2.2 5.2.3 5.2.4 5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.4.0 5.4.1 5.4.2 5.5.0 5.5.1 6.0.0 6.0.1 6.0.2 6.0.3 6.0.4 6.0.5 6.1.0 6.1.1 6.1.2 6.1.3 6.1.4 6.2.0 6.2.1 6.3.0 6.3.1 6.3.2 6.3.3 6.3.4 6.4.0 6.4.1 6.4.2 7.0.0 7.0.1 7.1.0 7.2.0 7.3.0 7.3.1 7.3.2 7.3.3 7.3.4 7.3.5 7.3.6 7.3.7 7.3.8 7.4.0 trunk 2.3.7 3.0.0 3.0.1 3.0.2 3.0.3 3.1.0 3.1.1 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 4.0.0 4.0.1 4.0.10 4.0.11 4.0.12 4.0.13 4.0.2 4.0.3 4.0.5 4.0.6
wordpress-popular-posts / src / Front / Front.php
wordpress-popular-posts / src / Front Last commit date
Front.php 5 years ago
Front.php
475 lines
1 <?php
2 /**
3 * The public-facing functionality of the plugin.
4 *
5 * Defines hooks to enqueue the public-specific stylesheet and JavaScript.
6 *
7 * @package WordPressPopularPosts
8 * @subpackage WordPressPopularPosts/Front
9 * @author Hector Cabrera <me@cabrerahector.com>
10 */
11
12 namespace WordPressPopularPosts\Front;
13
14 use WordPressPopularPosts\Helper;
15 use WordPressPopularPosts\Output;
16 use WordPressPopularPosts\Query;
17
18 class Front {
19
20 /**
21 * Plugin options.
22 *
23 * @var array $config
24 * @access private
25 */
26 private $config;
27
28 /**
29 * Translate object.
30 *
31 * @var \WordPressPopularPosts\Translate $translate
32 * @access private
33 */
34 private $translate;
35
36 /**
37 * Output object.
38 *
39 * @var \WordPressPopularPosts\Output $output
40 * @access private
41 */
42 private $output;
43
44 /**
45 * Construct.
46 *
47 * @since 5.0.0
48 * @param array $config Admin settings.
49 * @param \WordPressPopularPosts\Translate $translate Translate class.
50 */
51 public function __construct(array $config, \WordPressPopularPosts\Translate $translate, \WordPressPopularPosts\Output $output)
52 {
53 $this->config = $config;
54 $this->translate = $translate;
55 $this->output = $output;
56 }
57
58 /**
59 * WordPress public-facing hooks.
60 *
61 * @since 5.0.0
62 */
63 public function hooks()
64 {
65 add_shortcode('wpp', [$this, 'wpp_shortcode']);
66 add_action('wp_ajax_update_views_ajax', [$this, 'update_views']);
67 add_action('wp_ajax_nopriv_update_views_ajax', [$this, 'update_views']);
68 add_action('wp_enqueue_scripts', [$this, 'enqueue_assets']);
69 add_filter('script_loader_tag', [$this, 'convert_inline_js_into_json'], 10, 3);
70 }
71
72 /**
73 * Enqueues public facing assets.
74 *
75 * @since 5.0.0
76 */
77 public function enqueue_assets()
78 {
79 // Enqueue WPP's stylesheet.
80 if ( $this->config['tools']['css'] ) {
81 $theme_file = get_stylesheet_directory() . '/wpp.css';
82
83 if ( @is_file($theme_file) ) {
84 wp_enqueue_style('wordpress-popular-posts-css', get_stylesheet_directory_uri() . "/wpp.css", [], WPP_VERSION, 'all');
85 } // Load stock stylesheet
86 else {
87 wp_enqueue_style('wordpress-popular-posts-css', plugin_dir_url(dirname(dirname(__FILE__))) . 'assets/css/wpp.css', [], WPP_VERSION, 'all');
88 }
89 }
90
91 // Enqueue WPP's library.
92 $is_single = 0;
93
94 if (
95 ( 0 == $this->config['tools']['log']['level'] && ! is_user_logged_in() )
96 || ( 1 == $this->config['tools']['log']['level'] )
97 || ( 2 == $this->config['tools']['log']['level'] && is_user_logged_in() )
98 ) {
99 $is_single = Helper::is_single();
100 }
101
102 wp_register_script('wpp-js', plugin_dir_url(dirname(dirname(__FILE__))) . 'assets/js/wpp.min.js', [], WPP_VERSION, false);
103 $params = [
104 'sampling_active' => (int) $this->config['tools']['sampling']['active'],
105 'sampling_rate' => (int) $this->config['tools']['sampling']['rate'],
106 'ajax_url' => esc_url_raw(rest_url('wordpress-popular-posts/v1/popular-posts')),
107 'ID' => (int) $is_single,
108 'token' => wp_create_nonce('wp_rest'),
109 'lang' => function_exists('PLL') ? $this->translate->get_current_language() : 0,
110 'debug' => (int) WP_DEBUG
111 ];
112 wp_enqueue_script('wpp-js');
113 wp_add_inline_script('wpp-js', json_encode($params), 'before');
114 }
115
116 /**
117 * Converts inline script tag into type=application/json.
118 *
119 * This function mods the original script tag as printed
120 * by WordPress which contains the data for the wpp_params
121 * object into a JSON script. This improves compatibility
122 * with Content Security Policy (CSP).
123 *
124 * @since 5.2.0
125 * @param string $tag
126 * @param string $handle
127 * @param string $src
128 * @return string $tag
129 */
130 function convert_inline_js_into_json($tag, $handle, $src)
131 {
132 if ( 'wpp-js' === $handle ) {
133 // id attribute found, replace it
134 if ( false !== strpos($tag, 'wpp-js-js-before') ) {
135 $tag = str_replace('wpp-js-js-before', 'wpp-json', $tag);
136 } // id attribute missing, let's add it
137 else {
138 $pos = strpos($tag, '>');
139 $tag = substr_replace($tag, ' id="wpp-json">', $pos, 1);
140 }
141
142 // type attribute found, replace it
143 if ( false !== strpos($tag, 'type') ) {
144 $pos = strpos($tag, 'text/javascript');
145
146 if ( false !== $pos )
147 $tag = substr_replace($tag, 'application/json', $pos, strlen('text/javascript'));
148 } // type attribute missing, let's add it
149 else {
150 $pos = strpos($tag, '>');
151 $tag = substr_replace($tag, ' type="application/json">', $pos, 1);
152 }
153 }
154
155 return $tag;
156 }
157
158 /**
159 * Updates views count on page load via AJAX.
160 *
161 * @since 2.0.0
162 */
163 public function update_views()
164 {
165 if ( ! wp_verify_nonce($_POST['token'], 'wpp-token') || ! Helper::is_number($_POST['wpp_id']) ) {
166 die( "WPP: Oops, invalid request!" );
167 }
168
169 $nonce = $_POST['token'];
170 $post_ID = $_POST['wpp_id'];
171 $exec_time = 0;
172
173 $start = Helper::microtime_float();
174 $result = $this->update_views_count($post_ID);
175 $end = Helper::microtime_float();
176 $exec_time += round($end - $start, 6);
177
178 if ( $result ) {
179 die("WPP: OK. Execution time: " . $exec_time . " seconds");
180 }
181
182 die("WPP: Oops, could not update the views count!");
183 }
184
185 /**
186 * Updates views count.
187 *
188 * @since 1.4.0
189 * @access private
190 * @global object $wpdb
191 * @param int $post_ID
192 * @return bool|int FALSE if query failed, TRUE on success
193 */
194 private function update_views_count($post_ID) {
195 /*
196 TODO:
197 For WordPress Multisite, we must define the DIEONDBERROR constant for database errors to display like so:
198 <?php define( 'DIEONDBERROR', true ); ?>
199 */
200 global $wpdb;
201 $table = $wpdb->prefix . "popularposts";
202 $wpdb->show_errors();
203
204 // Get translated object ID
205 $post_ID = $this->translate->get_object_id(
206 $post_ID,
207 get_post_type($post_ID),
208 true,
209 $this->translate->get_default_language()
210 );
211 $now = Helper::now();
212 $curdate = Helper::curdate();
213 $views = ( $this->config['tools']['sampling']['active'] )
214 ? $this->config['tools']['sampling']['rate']
215 : 1;
216
217 // Allow WP themers / coders perform an action
218 // before updating views count
219 if ( has_action('wpp_pre_update_views') )
220 do_action('wpp_pre_update_views', $post_ID, $views);
221
222 // Update all-time table
223 $result1 = $wpdb->query($wpdb->prepare(
224 "INSERT INTO {$table}data
225 (postid, day, last_viewed, pageviews) VALUES (%d, %s, %s, %d)
226 ON DUPLICATE KEY UPDATE pageviews = pageviews + %d, last_viewed = %s;",
227 $post_ID,
228 $now,
229 $now,
230 $views,
231 $views,
232 $now
233 ));
234
235 // Update range (summary) table
236 $result2 = $wpdb->query($wpdb->prepare(
237 "INSERT INTO {$table}summary
238 (postid, pageviews, view_date, view_datetime) VALUES (%d, %d, %s, %s)
239 ON DUPLICATE KEY UPDATE pageviews = pageviews + %d, view_datetime = %s;",
240 $post_ID,
241 $views,
242 $curdate,
243 $now,
244 $views,
245 $now
246 ));
247
248 if ( !$result1 || !$result2 )
249 return false;
250
251 // Allow WP themers / coders perform an action
252 // after updating views count
253 if ( has_action('wpp_post_update_views' ))
254 do_action('wpp_post_update_views', $post_ID);
255
256 return true;
257 }
258
259 /**
260 * WPP shortcode handler.
261 *
262 * @since 1.4.0
263 * @param array $atts User defined attributes in shortcode tag
264 * @return string
265 */
266 public function wpp_shortcode($atts = null) {
267 /**
268 * @var string $header
269 * @var int $limit
270 * @var int $offset
271 * @var string $range
272 * @var bool $freshness
273 * @var string $order_by
274 * @var string $post_type
275 * @var string $pid
276 * @var string $cat
277 * @var string $author
278 * @var int $title_length
279 * @var int $title_by_words
280 * @var int $excerpt_length
281 * @var int $excerpt_format
282 * @var int $excerpt_by_words
283 * @var int $thumbnail_width
284 * @var int $thumbnail_height
285 * @var bool $rating
286 * @var bool $stats_comments
287 * @var bool $stats_views
288 * @var bool $stats_author
289 * @var bool $stats_date
290 * @var string $stats_date_format
291 * @var bool $stats_category
292 * @var string $wpp_start
293 * @var string $wpp_end
294 * @var string $header_start
295 * @var string $header_end
296 * @var string $post_html
297 * @var bool $php
298 */
299 extract(shortcode_atts([
300 'header' => '',
301 'limit' => 10,
302 'offset' => 0,
303 'range' => 'daily',
304 'time_unit' => 'hour',
305 'time_quantity' => 24,
306 'freshness' => false,
307 'order_by' => 'views',
308 'post_type' => 'post',
309 'pid' => '',
310 'cat' => '',
311 'taxonomy' => 'category',
312 'term_id' => '',
313 'author' => '',
314 'title_length' => 0,
315 'title_by_words' => 0,
316 'excerpt_length' => 0,
317 'excerpt_format' => 0,
318 'excerpt_by_words' => 0,
319 'thumbnail_width' => 0,
320 'thumbnail_height' => 0,
321 'rating' => false,
322 'stats_comments' => false,
323 'stats_views' => true,
324 'stats_author' => false,
325 'stats_date' => false,
326 'stats_date_format' => 'F j, Y',
327 'stats_category' => false,
328 'stats_taxonomy' => false,
329 'wpp_start' => '<ul class="wpp-list">',
330 'wpp_end' => '</ul>',
331 'header_start' => '<h2>',
332 'header_end' => '</h2>',
333 'post_html' => '',
334 'php' => false
335 ], $atts, 'wpp'));
336
337 // possible values for "Time Range" and "Order by"
338 $time_units = ["minute", "hour", "day", "week", "month"];
339 $range_values = ["daily", "last24hours", "weekly", "last7days", "monthly", "last30days", "all", "custom"];
340 $order_by_values = ["comments", "views", "avg"];
341
342 $shortcode_ops = [
343 'title' => strip_tags($header),
344 'limit' => ( ! empty($limit ) && Helper::is_number($limit) && $limit > 0 ) ? $limit : 10,
345 'offset' => ( ! empty($offset) && Helper::is_number($offset) && $offset >= 0 ) ? $offset : 0,
346 'range' => ( in_array($range, $range_values) ) ? $range : 'daily',
347 'time_quantity' => ( ! empty($time_quantity ) && Helper::is_number($time_quantity) && $time_quantity > 0 ) ? $time_quantity : 24,
348 'time_unit' => ( in_array($time_unit, $time_units) ) ? $time_unit : 'hour',
349 'freshness' => empty($freshness) ? false : $freshness,
350 'order_by' => ( in_array($order_by, $order_by_values) ) ? $order_by : 'views',
351 'post_type' => empty($post_type) ? 'post,page' : $post_type,
352 'pid' => rtrim(preg_replace('|[^0-9,]|', '', $pid), ","),
353 'cat' => rtrim(preg_replace('|[^0-9,-]|', '', $cat), ","),
354 'taxonomy' => empty($taxonomy) ? 'category' : $taxonomy,
355 'term_id' => rtrim(preg_replace('|[^0-9,;-]|', '', $term_id), ","),
356 'author' => rtrim(preg_replace('|[^0-9,]|', '', $author), ","),
357 'shorten_title' => [
358 'active' => ( ! empty($title_length) && Helper::is_number($title_length) && $title_length > 0 ),
359 'length' => ( ! empty($title_length) && Helper::is_number($title_length) ) ? $title_length : 0,
360 'words' => ( ! empty($title_by_words) && Helper::is_number($title_by_words) && $title_by_words > 0 ),
361 ],
362 'post-excerpt' => [
363 'active' => ( ! empty($excerpt_length) && Helper::is_number($excerpt_length) && $excerpt_length > 0 ),
364 'length' => ( ! empty($excerpt_length) && Helper::is_number($excerpt_length) ) ? $excerpt_length : 0,
365 'keep_format' => ( ! empty($excerpt_format) && Helper::is_number($excerpt_format) && $excerpt_format > 0 ),
366 'words' => ( ! empty($excerpt_by_words) && Helper::is_number($excerpt_by_words) && $excerpt_by_words > 0 ),
367 ],
368 'thumbnail' => [
369 'active' => ( ! empty($thumbnail_width) && Helper::is_number($thumbnail_width) && $thumbnail_width > 0 ),
370 'width' => ( ! empty($thumbnail_width) && Helper::is_number($thumbnail_width) && $thumbnail_width > 0 ) ? $thumbnail_width : 0,
371 'height' => ( ! empty($thumbnail_height) && Helper::is_number($thumbnail_height) && $thumbnail_height > 0 ) ? $thumbnail_height : 0,
372 ],
373 'rating' => empty($rating) ? false : $rating,
374 'stats_tag' => [
375 'comment_count' => empty($stats_comments) ? false : $stats_comments,
376 'views' => empty($stats_views) ? false : $stats_views,
377 'author' => empty($stats_author) ? false : $stats_author,
378 'date' => [
379 'active' => empty($stats_date) ? false : $stats_date,
380 'format' => empty($stats_date_format) ? 'F j, Y' : $stats_date_format
381 ],
382 'category' => empty($stats_category) ? false : $stats_category,
383 'taxonomy' => [
384 'active' => empty($stats_taxonomy) ? false : $stats_taxonomy,
385 'name' => empty($taxonomy) ? 'category' : $taxonomy,
386 ]
387 ],
388 'markup' => [
389 'custom_html' => true,
390 'wpp-start' => empty($wpp_start) ? '' : $wpp_start,
391 'wpp-end' => empty($wpp_end) ? '' : $wpp_end,
392 'title-start' => empty($header_start) ? '' : $header_start,
393 'title-end' => empty($header_end) ? '' : $header_end,
394 'post-html' => empty($post_html) ? '<li>{thumb} {title} <span class="wpp-meta post-stats">{stats}</span></li>' : $post_html
395 ]
396 ];
397
398 // Post / Page / CTP filter
399 $ids = array_filter(explode(",", $shortcode_ops['pid']), 'is_numeric');
400 // Got no valid IDs, clear
401 if ( empty($ids) ) {
402 $shortcode_ops['pid'] = '';
403 }
404
405 // Category filter
406 $ids = array_filter(explode(",", $shortcode_ops['cat']), 'is_numeric');
407 // Got no valid IDs, clear
408 if ( empty($ids) ) {
409 $shortcode_ops['cat'] = '';
410 }
411
412 // Author filter
413 $ids = array_filter(explode( ",", $shortcode_ops['author']), 'is_numeric');
414 // Got no valid IDs, clear
415 if ( empty($ids) ) {
416 $shortcode_ops['author'] = '';
417 }
418
419 $shortcode_content = '';
420
421 // is there a title defined by user?
422 if (
423 ! empty($header)
424 && ! empty($header_start)
425 && ! empty($header_end)
426 ) {
427 $shortcode_content .= htmlspecialchars_decode($header_start, ENT_QUOTES) . $header . htmlspecialchars_decode($header_end, ENT_QUOTES);
428 }
429
430 $cached = false;
431
432 // Return cached results
433 if ( $this->config['tools']['cache']['active'] ) {
434
435 $key = md5(json_encode($shortcode_ops));
436 $popular_posts = \WordPressPopularPosts\Cache::get($key);
437
438 if ( false === $popular_posts ) {
439 $popular_posts = new Query($shortcode_ops);
440
441 $time_value = $this->config['tools']['cache']['interval']['value']; // eg. 5
442 $time_unit = $this->config['tools']['cache']['interval']['time']; // eg. 'minute'
443
444 // No popular posts found, check again in 1 minute
445 if ( ! $popular_posts->get_posts() ) {
446 $time_value = 1;
447 $time_unit = 'minute';
448 }
449
450 \WordPressPopularPosts\Cache::set(
451 $key,
452 $popular_posts,
453 $time_value,
454 $time_unit
455 );
456 }
457
458 $cached = true;
459
460 } // Get popular posts
461 else {
462 $popular_posts = new Query($shortcode_ops);
463 }
464
465 $this->output->set_data($popular_posts->get_posts());
466 $this->output->set_public_options($shortcode_ops);
467 $this->output->build_output();
468
469 $shortcode_content .= $this->output->get_output();
470
471 return $shortcode_content;
472 }
473
474 }
475