PluginProbe ʕ •ᴥ•ʔ
WP Popular Posts / 3.3.2
WP Popular Posts v3.3.2
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 / wordpress-popular-posts.php
wordpress-popular-posts Last commit date
js 10 years ago lang 10 years ago style 10 years ago views 10 years ago index.php 10 years ago no_thumb.jpg 10 years ago readme.txt 10 years ago uninstall.php 10 years ago wordpress-popular-posts.php 10 years ago
wordpress-popular-posts.php
3331 lines
1 <?php
2 /*
3 Plugin Name: WordPress Popular Posts
4 Plugin URI: http://wordpress.org/extend/plugins/wordpress-popular-posts
5 Description: WordPress Popular Posts is a highly customizable widget that displays the most popular posts on your blog
6 Version: 3.3.2
7 Author: Hector Cabrera
8 Author URI: http://cabrerahector.com
9 Author Email: hcabrerab@gmail.com
10 Text Domain: wordpress-popular-posts
11 Domain Path: /lang/
12 Network: false
13 License: GPLv2 or later
14 License URI: http://www.gnu.org/licenses/gpl-2.0.html
15
16 Copyright 2008-2015 Hector Cabrera (hcabrerab@gmail.com)
17
18 This program is free software; you can redistribute it and/or modify
19 it under the terms of the GNU General Public License, version 2, as
20 published by the Free Software Foundation.
21
22 This program is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 GNU General Public License for more details.
26
27 You should have received a copy of the GNU General Public License
28 along with this program; if not, write to the Free Software
29 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 */
31
32 if ( !defined('ABSPATH') )
33 exit('Please do not load this file directly.');
34
35 /**
36 * WordPress Popular Posts class.
37 */
38 if ( !class_exists('WordpressPopularPosts') ) {
39
40 /**
41 * Register plugin's activation / deactivation functions
42 * @since 1.3
43 */
44 register_activation_hook( __FILE__, array( 'WordpressPopularPosts', 'activate' ) );
45 register_deactivation_hook( __FILE__, array( 'WordpressPopularPosts', 'deactivate' ) );
46
47 /**
48 * Add function to widgets_init that'll load WPP.
49 * @since 2.0
50 */
51 function load_wpp() {
52 register_widget( 'WordpressPopularPosts' );
53 }
54 add_action( 'widgets_init', 'load_wpp' );
55
56 class WordpressPopularPosts extends WP_Widget {
57
58 /**
59 * Plugin version, used for cache-busting of style and script file references.
60 *
61 * @since 1.3.0
62 * @var string
63 */
64 private $version = '3.3.2';
65
66 /**
67 * Plugin identifier.
68 *
69 * @since 3.0.0
70 * @var string
71 */
72 private $plugin_slug = 'wordpress-popular-posts';
73
74 /**
75 * Instance of this class.
76 *
77 * @since 3.0.0
78 * @var object
79 */
80 protected static $instance = NULL;
81
82 /**
83 * Slug of the plugin screen.
84 *
85 * @since 3.0.0
86 * @var string
87 */
88 protected $plugin_screen_hook_suffix = NULL;
89
90 /**
91 * Flag for singular pages.
92 *
93 * @since 3.1.2
94 * @var int
95 */
96 private $current_post_id = 0;
97
98 /**
99 * Plugin directory.
100 *
101 * @since 1.4.6
102 * @var string
103 */
104 private $plugin_dir = '';
105
106 /**
107 * Plugin uploads directory.
108 *
109 * @since 3.0.4
110 * @var array
111 */
112 private $uploads_dir = array();
113
114 /**
115 * Default thumbnail.
116 *
117 * @since 2.2.0
118 * @var string
119 */
120 private $default_thumbnail = '';
121
122 /**
123 * Default thumbnail sizes
124 *
125 * @since 3.2.2
126 * @var array
127 */
128 private $default_thumbnail_sizes = array();
129
130 /**
131 * Flag to verify if thumbnails can be created or not.
132 *
133 * @since 1.4.6
134 * @var bool
135 */
136 private $thumbnailing = false;
137
138 /**
139 * Flag to verify if qTrans is present.
140 *
141 * @since 1.4.6
142 * @var bool
143 */
144 private $qTrans = false;
145
146 /**
147 * Default charset.
148 *
149 * @since 2.1.4
150 * @var string
151 */
152 private $charset = "UTF-8";
153
154 /**
155 * Plugin defaults.
156 *
157 * @since 2.3.3
158 * @var array
159 */
160 protected $defaults = array(
161 'title' => '',
162 'limit' => 10,
163 'range' => 'daily',
164 'freshness' => false,
165 'order_by' => 'views',
166 'post_type' => 'post,page',
167 'pid' => '',
168 'author' => '',
169 'cat' => '',
170 'shorten_title' => array(
171 'active' => false,
172 'length' => 25,
173 'words' => false
174 ),
175 'post-excerpt' => array(
176 'active' => false,
177 'length' => 55,
178 'keep_format' => false,
179 'words' => false
180 ),
181 'thumbnail' => array(
182 'active' => false,
183 'build' => 'manual',
184 'width' => 15,
185 'height' => 15,
186 'crop' => true
187 ),
188 'rating' => false,
189 'stats_tag' => array(
190 'comment_count' => false,
191 'views' => true,
192 'author' => false,
193 'date' => array(
194 'active' => false,
195 'format' => 'F j, Y'
196 ),
197 'category' => false
198 ),
199 'markup' => array(
200 'custom_html' => false,
201 'wpp-start' => '&lt;ul class="wpp-list"&gt;',
202 'wpp-end' => '&lt;/ul&gt;',
203 'post-html' => '&lt;li&gt;{thumb} {title} {stats}&lt;/li&gt;',
204 'post-start' => '&lt;li&gt;',
205 'post-end' => '&lt;/li&gt;',
206 'title-start' => '&lt;h2&gt;',
207 'title-end' => '&lt;/h2&gt;'
208 )
209 );
210
211 /**
212 * Admin page user settings defaults.
213 *
214 * @since 2.3.3
215 * @var array
216 */
217 protected $default_user_settings = array(
218 'stats' => array(
219 'order_by' => 'views',
220 'limit' => 10,
221 'post_type' => 'post,page',
222 'freshness' => false
223 ),
224 'tools' => array(
225 'ajax' => false,
226 'css' => true,
227 'link' => array(
228 'target' => '_self'
229 ),
230 'thumbnail' => array(
231 'source' => 'featured',
232 'field' => '',
233 'resize' => false,
234 'default' => '',
235 'responsive' => false
236 ),
237 'log' => array(
238 'level' => 1,
239 'limit' => 0,
240 'expires_after' => 180
241 ),
242 'cache' => array(
243 'active' => false,
244 'interval' => array(
245 'time' => 'hour',
246 'value' => 1
247 )
248 ),
249 'sampling' => array(
250 'active' => false,
251 'rate' => 100
252 )
253 )
254 );
255
256 /**
257 * Admin page user settings.
258 *
259 * @since 2.3.3
260 * @var array
261 */
262 private $user_settings = array();
263
264 /**
265 * Bots list.
266 *
267 * @since 3.0.0
268 * @var array
269 */
270 protected $botlist = array( 'bot', 'crawl', 'curl', 'facebookexternalhit', 'geturl', 'google', 'java', 'msn', 'perl', 'slurp', 'spider', 'sqworm', 'search', 'wget' );
271
272 /*--------------------------------------------------*/
273 /* Constructor
274 /*--------------------------------------------------*/
275
276 /**
277 * Initialize the widget by setting localization, filters, and administration functions.
278 *
279 * @since 1.0.0
280 */
281 public function __construct() {
282
283 // Load plugin text domain
284 add_action( 'init', array( $this, 'widget_textdomain' ) );
285
286 // Upgrade check
287 add_action( 'init', array( $this, 'upgrade_check' ) );
288
289 // Check location on template redirect
290 add_action( 'template_redirect', array( $this, 'is_single' ) );
291
292 // Hook fired when a new blog is activated on WP Multisite
293 add_action( 'wpmu_new_blog', array( $this, 'activate_new_site' ) );
294
295 // Notices check
296 add_action( 'admin_notices', array( $this, 'check_admin_notices' ) );
297
298 // Create the widget
299 parent::__construct(
300 'wpp',
301 'WordPress Popular Posts',
302 array(
303 'classname' => 'popular-posts',
304 'description' => __( 'The most Popular Posts on your blog.', $this->plugin_slug )
305 )
306 );
307
308 // Get user options
309 $this->user_settings = get_site_option('wpp_settings_config');
310 if ( !$this->user_settings ) {
311 add_site_option('wpp_settings_config', $this->default_user_settings);
312 $this->user_settings = $this->default_user_settings;
313 } else {
314 $this->user_settings = $this->__merge_array_r( $this->default_user_settings, $this->user_settings );
315 }
316
317 // Allow WP themers / coders to override data sampling status (active/inactive)
318 $this->user_settings['tools']['sampling']['active'] = apply_filters( 'wpp_data_sampling', $this->user_settings['tools']['sampling']['active'] );
319
320 // Add the options page and menu item.
321 add_action( 'admin_menu', array( $this, 'add_plugin_admin_menu' ) );
322
323 // Register admin styles and scripts
324 add_action( 'admin_print_styles', array( $this, 'register_admin_styles' ) );
325 add_action( 'admin_enqueue_scripts', array( $this, 'register_admin_scripts' ) );
326 add_action( 'admin_init', array( $this, 'thickbox_setup' ) );
327
328 // Register site styles and scripts
329 if ( $this->user_settings['tools']['css'] )
330 add_action( 'wp_enqueue_scripts', array( $this, 'register_widget_styles' ) );
331 add_action( 'wp_enqueue_scripts', array( $this, 'register_widget_scripts' ) );
332
333 // Add plugin settings link
334 add_filter( 'plugin_action_links', array( $this, 'add_plugin_settings_link' ), 10, 2 );
335
336 // Set plugin directory
337 $this->plugin_dir = plugin_dir_url(__FILE__);
338
339 // Get blog charset
340 $this->charset = get_bloginfo('charset');
341
342 // Add ajax table truncation to wp_ajax_ hook
343 add_action('wp_ajax_wpp_clear_data', array( $this, 'clear_data' ));
344
345 // Add thumbnail cache truncation to wp_ajax_ hook
346 add_action('wp_ajax_wpp_clear_thumbnail', array( $this, 'clear_thumbnails' ));
347
348 // Add ajax hook for widget
349 add_action('wp_ajax_wpp_get_popular', array( $this, 'get_popular') );
350 add_action('wp_ajax_nopriv_wpp_get_popular', array( $this, 'get_popular') );
351
352 // Check if images can be created
353 if ( extension_loaded('ImageMagick') || (extension_loaded('GD') && function_exists('gd_info')) ) {
354 // Enable thumbnail feature
355 $this->thumbnailing = true;
356 // Get available thumbnail size(s)
357 $this->default_thumbnail_sizes = $this->__get_image_sizes();
358 }
359
360 // Set default thumbnail
361 $this->default_thumbnail = $this->plugin_dir . "no_thumb.jpg";
362 $this->default_user_settings['tools']['thumbnail']['default'] = $this->default_thumbnail;
363
364 if ( !empty($this->user_settings['tools']['thumbnail']['default']) )
365 $this->default_thumbnail = $this->user_settings['tools']['thumbnail']['default'];
366 else
367 $this->user_settings['tools']['thumbnail']['default'] = $this->default_thumbnail;
368
369 // Set uploads folder
370 $wp_upload_dir = wp_upload_dir();
371 $this->uploads_dir['basedir'] = $wp_upload_dir['basedir'] . "/" . $this->plugin_slug;
372 $this->uploads_dir['baseurl'] = $wp_upload_dir['baseurl'] . "/" . $this->plugin_slug;
373
374 if ( !is_dir($this->uploads_dir['basedir']) ) {
375 if ( !wp_mkdir_p($this->uploads_dir['basedir']) ) {
376 $this->uploads_dir['basedir'] = $wp_upload_dir['basedir'];
377 $this->uploads_dir['baseurl'] = $wp_upload_dir['baseurl'];
378 }
379 }
380
381 // qTrans plugin support
382 if ( function_exists('qtrans_useCurrentLanguageIfNotFoundUseDefaultLanguage') )
383 $this->qTrans = true;
384
385 // Remove post/page prefetching!
386 remove_action( 'wp_head', 'adjacent_posts_rel_link_wp_head' );
387 // Add the update hooks only if the logging conditions are met
388 if ( (0 == $this->user_settings['tools']['log']['level'] && !is_user_logged_in()) || (1 == $this->user_settings['tools']['log']['level']) || (2 == $this->user_settings['tools']['log']['level'] && is_user_logged_in()) ) {
389
390 add_action( 'wp_head', array(&$this, 'print_ajax') );
391
392 // Register views from everyone and/or connected users
393 if ( 0 != $this->user_settings['tools']['log']['level'] )
394 add_action( 'wp_ajax_update_views_ajax', array($this, 'update_views_ajax') );
395 // Register views from everyone and/or visitors only
396 if ( 2 != $this->user_settings['tools']['log']['level'] )
397 add_action( 'wp_ajax_nopriv_update_views_ajax', array($this, 'update_views_ajax') );
398
399 }
400
401 // Add shortcode
402 add_shortcode('wpp', array(&$this, 'shortcode'));
403
404 // Purge post data from DB on deletion
405 add_action( 'admin_init', array($this, 'purge_post_init') );
406
407 // Enable data purging at midnight
408 if ( 1 == $this->user_settings['tools']['log']['limit'] ) {
409
410 add_action( 'wpp_cache_event', array($this, 'purge_data') );
411 if ( !wp_next_scheduled('wpp_cache_event') ) {
412 $tomorrow = time() + 86400;
413 $midnight = mktime(0, 0, 0,
414 date("m", $tomorrow),
415 date("d", $tomorrow),
416 date("Y", $tomorrow));
417 wp_schedule_event( $midnight, 'daily', 'wpp_cache_event' );
418 }
419
420 } else {
421 // Remove the scheduled event if exists
422 if ( $timestamp = wp_next_scheduled('wpp_cache_event') ) {
423 wp_unschedule_event( $timestamp, 'wpp_cache_event' );
424 }
425
426 }
427
428 } // end constructor
429
430 /*--------------------------------------------------*/
431 /* Widget API Functions
432 /*--------------------------------------------------*/
433
434 /**
435 * Outputs the content of the widget.
436 *
437 * @since 1.0.0
438 * @param array args The array of form elements
439 * @param array instance The current instance of the widget
440 */
441 public function widget( $args, $instance ) {
442
443 $this->__debug($args);
444
445 /**
446 * @var String $name
447 * @var String $id
448 * @var String $description
449 * @var String $class
450 * @var String $before_widget
451 * @var String $after_widget
452 * @var String $before_title
453 * @var String $after_title
454 * @var String $widget_id
455 * @var String $widget_name
456 */
457 extract( $args, EXTR_SKIP );
458
459 $markup = ( $instance['markup']['custom_html'] || has_filter('wpp_custom_html') || has_filter('wpp_post') )
460 ? 'custom'
461 : 'regular';
462
463 echo "\n". "<!-- WordPress Popular Posts Plugin v{$this->version} [W] [{$instance['range']}] [{$instance['order_by']}] [{$markup}]" . ( !empty($instance['pid']) ? " [PID]" : "" ) . ( !empty($instance['cat']) ? " [CAT]" : "" ) . ( !empty($instance['author']) ? " [UID]" : "" ) . " -->" . "\n";
464
465 echo $before_widget . "\n";
466
467 // has user set a title?
468 if ( '' != $instance['title'] ) {
469
470 $title = apply_filters( 'widget_title', $instance['title'] );
471
472 if ($instance['markup']['custom_html'] && $instance['markup']['title-start'] != "" && $instance['markup']['title-end'] != "" ) {
473 echo htmlspecialchars_decode($instance['markup']['title-start'], ENT_QUOTES) . $title . htmlspecialchars_decode($instance['markup']['title-end'], ENT_QUOTES);
474 } else {
475 echo $before_title . $title . $after_title;
476 }
477 }
478
479 if ( $this->user_settings['tools']['ajax'] ) {
480 if ( empty($before_widget) || !preg_match('/id="[^"]*"/', $before_widget) ) {
481 ?>
482 <p><?php _e('Error: cannot ajaxify WordPress Popular Posts on this theme. It\'s missing the <em>id</em> attribute on before_widget (see <a href="http://codex.wordpress.org/Function_Reference/register_sidebar" target="_blank" rel="nofollow">register_sidebar</a> for more).', $this->plugin_slug ); ?></p>
483 <?php
484 } else {
485 ?>
486 <script type="text/javascript">//<![CDATA[
487 // jQuery is available, so proceed
488 if ( window.jQuery ) {
489
490 jQuery(document).ready(function($){
491 $.get('<?php echo admin_url('admin-ajax.php'); ?>', {
492 action: 'wpp_get_popular',
493 id: '<?php echo $this->number; ?>'
494 }, function(data){
495 $('#<?php echo $widget_id; ?>').append(data);
496 });
497 });
498
499 } else { // jQuery is not defined
500 if ( window.console && window.console.log )
501 window.console.log('WordPress Popular Posts: jQuery is not defined!');
502 }
503 //]]></script>
504 <?php
505 }
506 } else {
507 echo $this->__get_popular_posts( $instance );
508 }
509
510 echo $after_widget . "\n";
511 echo "<!-- End WordPress Popular Posts Plugin v{$this->version} -->"."\n";
512
513 } // end widget
514
515 /**
516 * Processes the widget's options to be saved.
517 *
518 * @since 1.0.0
519 * @param array new_instance The previous instance of values before the update.
520 * @param array old_instance The new instance of values to be generated via the update.
521 * @return array instance Updated instance.
522 */
523 public function update( $new_instance, $old_instance ) {
524
525 $instance = $old_instance;
526
527 $instance['title'] = htmlspecialchars( stripslashes_deep(strip_tags( $new_instance['title'] )), ENT_QUOTES );
528 $instance['limit'] = ( $this->__is_numeric($new_instance['limit']) && $new_instance['limit'] > 0 )
529 ? $new_instance['limit']
530 : 10;
531 $instance['range'] = $new_instance['range'];
532 $instance['order_by'] = $new_instance['order_by'];
533
534 // FILTERS
535 // user did not define the custom post type name, so we fall back to default
536 $instance['post_type'] = ( '' == $new_instance['post_type'] )
537 ? 'post,page'
538 : $new_instance['post_type'];
539
540 $instance['freshness'] = isset( $new_instance['freshness'] );
541
542 $instance['pid'] = implode(",", array_filter(explode(",", preg_replace( '|[^0-9,]|', '', $new_instance['pid'] ))));
543 $instance['cat'] = implode(",", array_filter(explode(",", preg_replace( '|[^0-9,-]|', '', $new_instance['cat'] ))));
544 $instance['author'] = implode(",", array_filter(explode(",", preg_replace( '|[^0-9,]|', '', $new_instance['uid'] ))));
545
546 $instance['shorten_title']['words'] = $new_instance['shorten_title-words'];
547 $instance['shorten_title']['active'] = isset( $new_instance['shorten_title-active'] );
548 $instance['shorten_title']['length'] = ( $this->__is_numeric($new_instance['shorten_title-length']) && $new_instance['shorten_title-length'] > 0 )
549 ? $new_instance['shorten_title-length']
550 : 25;
551
552 $instance['post-excerpt']['keep_format'] = isset( $new_instance['post-excerpt-format'] );
553 $instance['post-excerpt']['words'] = $new_instance['post-excerpt-words'];
554 $instance['post-excerpt']['active'] = isset( $new_instance['post-excerpt-active'] );
555 $instance['post-excerpt']['length'] = ( $this->__is_numeric($new_instance['post-excerpt-length']) && $new_instance['post-excerpt-length'] > 0 )
556 ? $new_instance['post-excerpt-length']
557 : 55;
558
559 $instance['thumbnail']['active'] = false;
560 $instance['thumbnail']['width'] = 15;
561 $instance['thumbnail']['height'] = 15;
562
563 // can create thumbnails
564 if ( $this->thumbnailing ) {
565
566 $instance['thumbnail']['active'] = isset( $new_instance['thumbnail-active'] );
567 $instance['thumbnail']['build'] = $new_instance['thumbnail-size-source'];
568
569 // Use predefined thumbnail sizes
570 if ( 'predefined' == $new_instance['thumbnail-size-source'] ) {
571 $size = $this->default_thumbnail_sizes[ $new_instance['thumbnail-size'] ];
572 $instance['thumbnail']['width'] = $size['width'];
573 $instance['thumbnail']['height'] = $size['height'];
574 $instance['thumbnail']['crop'] = $size['crop'];
575 } // Set thumbnail size manually
576 else {
577 if ($this->__is_numeric($new_instance['thumbnail-width']) && $this->__is_numeric($new_instance['thumbnail-height'])) {
578 $instance['thumbnail']['width'] = $new_instance['thumbnail-width'];
579 $instance['thumbnail']['height'] = $new_instance['thumbnail-height'];
580 $instance['thumbnail']['crop'] = true;
581 }
582 }
583
584 }
585
586 $instance['rating'] = isset( $new_instance['rating'] );
587 $instance['stats_tag']['comment_count'] = isset( $new_instance['comment_count'] );
588 $instance['stats_tag']['views'] = isset( $new_instance['views'] );
589 $instance['stats_tag']['author'] = isset( $new_instance['author'] );
590 $instance['stats_tag']['date']['active'] = isset( $new_instance['date'] );
591 $instance['stats_tag']['date']['format'] = empty($new_instance['date_format'])
592 ? 'F j, Y'
593 : $new_instance['date_format'];
594
595 $instance['stats_tag']['category'] = isset( $new_instance['category'] );
596 $instance['markup']['custom_html'] = isset( $new_instance['custom_html'] );
597 $instance['markup']['wpp-start'] = empty($new_instance['wpp-start'])
598 ? htmlspecialchars( '<ul class="wpp-list">', ENT_QUOTES )
599 : htmlspecialchars( $new_instance['wpp-start'], ENT_QUOTES );
600
601 $instance['markup']['wpp-end'] = empty($new_instance['wpp-end'])
602 ? htmlspecialchars( '</ul>', ENT_QUOTES )
603 : htmlspecialchars( $new_instance['wpp-end'], ENT_QUOTES );
604
605 $instance['markup']['post-html'] = empty($new_instance['post-html'])
606 ? htmlspecialchars( '<li>{thumb} {title} {stats}</li>', ENT_QUOTES )
607 : htmlspecialchars( $new_instance['post-html'], ENT_QUOTES );
608
609 $instance['markup']['title-start'] = empty($new_instance['title-start'])
610 ? ''
611 : htmlspecialchars( $new_instance['title-start'], ENT_QUOTES );
612
613 $instance['markup']['title-end'] = empty($new_instance['title-end'])
614 ? '' :
615 htmlspecialchars( $new_instance['title-end'], ENT_QUOTES );
616
617 return $instance;
618
619 } // end widget
620
621 /**
622 * Generates the administration form for the widget.
623 *
624 * @since 1.0.0
625 * @param array instance The array of keys and values for the widget.
626 */
627 public function form( $instance ) {
628
629 // parse instance values
630 $instance = $this->__merge_array_r(
631 $this->defaults,
632 $instance
633 );
634
635 // Display the admin form
636 include( plugin_dir_path(__FILE__) . '/views/form.php' );
637
638 } // end form
639
640 /*--------------------------------------------------*/
641 /* Public methods
642 /*--------------------------------------------------*/
643
644 /**
645 * Loads the Widget's text domain for localization and translation.
646 *
647 * @since 1.0.0
648 */
649 public function widget_textdomain() {
650
651 $domain = $this->plugin_slug;
652 $locale = apply_filters( 'plugin_locale', get_locale(), $domain );
653
654 load_textdomain( $domain, WP_LANG_DIR . '/' . $domain . '/' . $domain . '-' . $locale . '.mo' );
655 load_plugin_textdomain( $domain, FALSE, dirname( plugin_basename( __FILE__ ) ) . '/lang/' );
656
657 } // end widget_textdomain
658
659 /**
660 * Registers and enqueues admin-specific styles.
661 *
662 * @since 1.0.0
663 */
664 public function register_admin_styles() {
665
666 if ( ! isset( $this->plugin_screen_hook_suffix ) ) {
667 return;
668 }
669
670 $screen = get_current_screen();
671 if ( $screen->id == $this->plugin_screen_hook_suffix ) {
672 wp_enqueue_style( $this->plugin_slug .'-admin-styles', plugins_url( 'style/admin.css', __FILE__ ), array(), $this->version );
673 }
674
675 } // end register_admin_styles
676
677 /**
678 * Registers and enqueues admin-specific JavaScript.
679 *
680 * @since 2.3.4
681 */
682 public function register_admin_scripts() {
683
684 if ( ! isset( $this->plugin_screen_hook_suffix ) ) {
685 return;
686 }
687
688 $screen = get_current_screen();
689 if ( $screen->id == $this->plugin_screen_hook_suffix ) {
690 wp_enqueue_script( 'thickbox' );
691 wp_enqueue_style( 'thickbox' );
692 wp_enqueue_script( 'media-upload' );
693 wp_enqueue_script( $this->plugin_slug .'-admin-script', plugins_url( 'js/admin.js', __FILE__ ), array('jquery'), $this->version, true );
694 }
695
696 } // end register_admin_scripts
697
698 /**
699 * Hooks into getttext to change upload button text when uploader is called by WPP.
700 *
701 * @since 2.3.4
702 */
703 function thickbox_setup() {
704
705 global $pagenow;
706 if ( 'media-upload.php' == $pagenow || 'async-upload.php' == $pagenow ) {
707 add_filter( 'gettext', array( $this, 'replace_thickbox_text' ), 1, 3 );
708 }
709
710 } // end thickbox_setup
711
712 /**
713 * Replaces upload button text when uploader is called by WPP.
714 *
715 * @since 2.3.4
716 * @param string translated_text
717 * @param string text
718 * @param string domain
719 * @return string
720 */
721 function replace_thickbox_text($translated_text, $text, $domain) {
722
723 if ('Insert into Post' == $text) {
724 $referer = strpos( wp_get_referer(), 'wpp_admin' );
725 if ( $referer != '' ) {
726 return __('Upload', $this->plugin_slug );
727 }
728 }
729
730 return $translated_text;
731
732 } // end replace_thickbox_text
733
734 /**
735 * Registers and enqueues widget-specific styles.
736 *
737 * @since 1.0.0
738 */
739 public function register_widget_styles() {
740
741 $theme_file = get_stylesheet_directory() . '/wpp.css';
742 $plugin_file = plugin_dir_path(__FILE__) . 'style/wpp.css';
743
744 if ( @file_exists($theme_file) ) { // user stored a custom wpp.css on theme's directory, so use it
745 wp_enqueue_style( $this->plugin_slug, get_stylesheet_directory_uri() . "/wpp.css", array(), $this->version );
746 } elseif ( @file_exists($plugin_file) ) { // no custom wpp.css, use plugin's instead
747 wp_enqueue_style( $this->plugin_slug, plugins_url( 'style/wpp.css', __FILE__ ), array(), $this->version );
748 }
749
750 } // end register_widget_styles
751
752 /**
753 * Registers and enqueues widget-specific scripts.
754 */
755 public function register_widget_scripts() {
756 // We need jQuery in the front-end only when ajaxifying the widget
757 if ( $this->user_settings['tools']['ajax'] )
758 wp_enqueue_script( 'jquery' );
759 } // end register_widget_scripts
760
761 /**
762 * Register the administration menu for this plugin into the WordPress Dashboard menu.
763 *
764 * @since 1.0.0
765 */
766 public function add_plugin_admin_menu() {
767
768 $this->plugin_screen_hook_suffix = add_options_page(
769 'WordPress Popular Posts',
770 'WordPress Popular Posts',
771 'manage_options',
772 $this->plugin_slug,
773 array( $this, 'display_plugin_admin_page' )
774 );
775
776 }
777
778 /**
779 * Render the settings page for this plugin.
780 *
781 * @since 1.0.0
782 */
783 public function display_plugin_admin_page() {
784 include_once( 'views/admin.php' );
785 }
786
787 /**
788 * Registers Settings link on plugin description.
789 *
790 * @since 2.3.3
791 * @param array links
792 * @param string file
793 * @return array
794 */
795 public function add_plugin_settings_link( $links, $file ){
796
797 $this_plugin = plugin_basename(__FILE__);
798
799 if ( is_plugin_active($this_plugin) && $file == $this_plugin ) {
800 $links[] = '<a href="' . admin_url( 'options-general.php?page=wordpress-popular-posts' ) . '">Settings</a>';
801 }
802
803 return $links;
804
805 } // end add_plugin_settings_link
806
807 /*--------------------------------------------------*/
808 /* Install / activation / deactivation methods
809 /*--------------------------------------------------*/
810
811 /**
812 * Return an instance of this class.
813 *
814 * @since 3.0.0
815 * @return object A single instance of this class.
816 */
817 public static function get_instance() {
818
819 // If the single instance hasn't been set, set it now.
820 if ( NULL == self::$instance ) {
821 self::$instance = new self;
822 }
823
824 return self::$instance;
825
826 } // end get_instance
827
828 /**
829 * Fired when the plugin is activated.
830 *
831 * @since 1.0.0
832 * @global object wpdb
833 * @param bool network_wide True if WPMU superadmin uses "Network Activate" action, false if WPMU is disabled or plugin is activated on an individual blog.
834 */
835 public static function activate( $network_wide ) {
836
837 global $wpdb;
838
839 if ( function_exists( 'is_multisite' ) && is_multisite() ) {
840
841 // run activation for each blog in the network
842 if ( $network_wide ) {
843
844 $original_blog_id = get_current_blog_id();
845 $blogs_ids = $wpdb->get_col( "SELECT blog_id FROM {$wpdb->blogs}" );
846
847 foreach( $blogs_ids as $blog_id ) {
848 switch_to_blog( $blog_id );
849 self::__activate();
850 }
851
852 // switch back to current blog
853 switch_to_blog( $original_blog_id );
854
855 return;
856
857 }
858
859 }
860
861 self::__activate();
862
863 } // end activate
864
865 /**
866 * Fired when a new blog is activated on WP Multisite.
867 *
868 * @since 3.0.0
869 * @param int blog_id New blog ID
870 */
871 public function activate_new_site( $blog_id ){
872
873 if ( 1 !== did_action( 'wpmu_new_blog' ) )
874 return;
875
876 // run activation for the new blog
877 switch_to_blog( $blog_id );
878 self::__activate();
879
880 // switch back to current blog
881 restore_current_blog();
882
883 } // end activate_new_site
884
885 /**
886 * On plugin activation, checks that the WPP database tables are present.
887 *
888 * @since 2.4.0
889 * @global object wpdb
890 */
891 private static function __activate() {
892
893 global $wpdb;
894
895 // set table name
896 $prefix = $wpdb->prefix . "popularposts";
897
898 // fresh setup
899 if ( $prefix != $wpdb->get_var("SHOW TABLES LIKE '{$prefix}data'") ) {
900 self::__do_db_tables( $prefix );
901 }
902
903 } // end __activate
904
905 /**
906 * Fired when the plugin is deactivated.
907 *
908 * @since 1.0.0
909 * @global object wpbd
910 * @param bool network_wide True if WPMU superadmin uses "Network Activate" action, false if WPMU is disabled or plugin is activated on an individual blog
911 */
912 public static function deactivate( $network_wide ) {
913
914 global $wpdb;
915
916 if ( function_exists( 'is_multisite' ) && is_multisite() ) {
917
918 // Run deactivation for each blog in the network
919 if ( $network_wide ) {
920
921 $original_blog_id = get_current_blog_id();
922 $blogs_ids = $wpdb->get_col( "SELECT blog_id FROM {$wpdb->blogs}" );
923
924 foreach( $blogs_ids as $blog_id ) {
925 switch_to_blog( $blog_id );
926 self::__deactivate();
927 }
928
929 // Switch back to current blog
930 switch_to_blog( $original_blog_id );
931
932 return;
933
934 }
935
936 }
937
938 self::__deactivate();
939
940 } // end deactivate
941
942 /**
943 * On plugin deactivation, disables the shortcode and removes the scheduled task.
944 *
945 * @since 2.4.0
946 */
947 private static function __deactivate() {
948
949 remove_shortcode('wpp');
950 wp_clear_scheduled_hook('wpp_cache_event');
951
952 } // end __deactivate
953
954 /**
955 * Checks if an upgrade procedure is required.
956 *
957 * @since 2.4.0
958 */
959 public function upgrade_check(){
960
961 // Get WPP version
962 $wpp_ver = get_site_option('wpp_ver');
963
964 if ( !$wpp_ver ) {
965 add_site_option('wpp_ver', $this->version);
966 } elseif ( version_compare($wpp_ver, $this->version, '<') ) {
967 $this->__upgrade();
968 }
969
970 } // end upgrade_check
971
972 /**
973 * On plugin upgrade, performs a number of actions: update WPP database tables structures (if needed),
974 * run the setup wizard (if needed), and some other checks.
975 *
976 * @since 2.4.0
977 * @global object wpdb
978 */
979 private function __upgrade() {
980
981 global $wpdb;
982
983 // set table name
984 $prefix = $wpdb->prefix . "popularposts";
985
986 // validate the structure of the tables and create missing tables
987 self::__do_db_tables( $prefix );
988
989 // If summary is empty, import data from popularpostsdatacache
990 if ( !$wpdb->get_var("SELECT COUNT(*) FROM {$prefix}summary") ) {
991
992 // popularpostsdatacache table is still there
993 if ( $wpdb->get_var("SHOW TABLES LIKE '{$prefix}datacache'") ) {
994
995 $sql = "
996 INSERT INTO {$prefix}summary (postid, pageviews, view_date, last_viewed)
997 SELECT id, pageviews, day_no_time, day
998 FROM {$prefix}datacache
999 GROUP BY day_no_time, id
1000 ORDER BY day_no_time DESC";
1001
1002 $result = $wpdb->query( $sql );
1003
1004 }
1005
1006 }
1007
1008 // Deletes old caching tables, if found
1009 $wpdb->query( "DROP TABLE IF EXISTS {$prefix}datacache, {$prefix}datacache_backup;" );
1010
1011 // Check storage engine
1012 $storage_engine_data = $wpdb->get_var("SELECT `ENGINE` FROM `information_schema`.`TABLES` WHERE `TABLE_SCHEMA`='{$wpdb->dbname}' AND `TABLE_NAME`='{$prefix}data';");
1013
1014 if ( 'MyISAM' == $storage_engine_data ) {
1015 $wpdb->query("ALTER TABLE {$prefix}data ENGINE=INNODB;");
1016 }
1017
1018 $storage_engine_summary = $wpdb->get_var("SELECT `ENGINE` FROM `information_schema`.`TABLES` WHERE `TABLE_SCHEMA`='{$wpdb->dbname}' AND `TABLE_NAME`='{$prefix}summary';");
1019
1020 if ( 'MyISAM' == $storage_engine_summary ) {
1021 $wpdb->query("ALTER TABLE {$prefix}summary ENGINE=INNODB;");
1022 }
1023
1024 // Update WPP version
1025 update_site_option('wpp_ver', $this->version);
1026
1027 } // end __upgrade
1028
1029 /**
1030 * Creates/updates the WPP database tables.
1031 *
1032 * @since 2.4.0
1033 * @global object wpdb
1034 */
1035 private static function __do_db_tables( $prefix ) {
1036
1037 global $wpdb;
1038
1039 $sql = "";
1040 $charset_collate = "";
1041
1042 if ( !empty($wpdb->charset) )
1043 $charset_collate = "DEFAULT CHARACTER SET {$wpdb->charset} ";
1044
1045 if ( !empty($wpdb->collate) )
1046 $charset_collate .= "COLLATE {$wpdb->collate}";
1047
1048 $sql = "
1049 CREATE TABLE {$prefix}data (
1050 postid bigint(20) NOT NULL,
1051 day datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
1052 last_viewed datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
1053 pageviews bigint(20) DEFAULT 1,
1054 PRIMARY KEY (postid)
1055 ) {$charset_collate} ENGINE=INNODB;
1056 CREATE TABLE {$prefix}summary (
1057 ID bigint(20) NOT NULL AUTO_INCREMENT,
1058 postid bigint(20) NOT NULL,
1059 pageviews bigint(20) NOT NULL DEFAULT 1,
1060 view_date date NOT NULL DEFAULT '0000-00-00',
1061 last_viewed datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
1062 PRIMARY KEY (ID),
1063 UNIQUE KEY ID_date (postid,view_date),
1064 KEY postid (postid),
1065 KEY view_date (view_date),
1066 KEY last_viewed (last_viewed)
1067 ) {$charset_collate} ENGINE=INNODB;";
1068
1069 require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
1070 dbDelta($sql);
1071
1072 } // end __do_db_tables
1073
1074 /**
1075 * Checks if the technical requirements are met.
1076 *
1077 * @since 2.4.0
1078 * @link http://wordpress.stackexchange.com/questions/25910/uninstall-activate-deactivate-a-plugin-typical-features-how-to/25979#25979
1079 * @global string $wp_version
1080 * @return array
1081 */
1082 private function __check_requirements() {
1083
1084 global $wp_version;
1085
1086 $php_min_version = '5.2';
1087 $wp_min_version = '3.8';
1088 $php_current_version = phpversion();
1089 $errors = array();
1090
1091 if ( version_compare( $php_min_version, $php_current_version, '>' ) ) {
1092 $errors[] = sprintf(
1093 __( 'Your PHP installation is too old. WordPress Popular Posts requires at least PHP version %1$s to function correctly. Please contact your hosting provider and ask them to upgrade PHP to %1$s or higher.', $this->plugin_slug ),
1094 $php_min_version
1095 );
1096 }
1097
1098 if ( version_compare( $wp_min_version, $wp_version, '>' ) ) {
1099 $errors[] = sprintf(
1100 __( 'Your WordPress version is too old. WordPress Popular Posts requires at least WordPress version %1$s to function correctly. Please update your blog via Dashboard &gt; Update.', $this->plugin_slug ),
1101 $wp_min_version
1102 );
1103 }
1104
1105 return $errors;
1106
1107 } // end __check_requirements
1108
1109 /**
1110 * Outputs error messages to wp-admin.
1111 *
1112 * @since 2.4.0
1113 */
1114 public function check_admin_notices() {
1115
1116 $errors = $this->__check_requirements();
1117
1118 if ( empty($errors) )
1119 return;
1120
1121 if ( isset($_GET['activate']) )
1122 unset($_GET['activate']);
1123
1124 printf(
1125 __('<div class="error"><p>%1$s</p><p><i>%2$s</i> has been <strong>deactivated</strong>.</p></div>', $this->plugin_slug),
1126 join( '</p><p>', $errors ),
1127 'WordPress Popular Posts'
1128 );
1129
1130 deactivate_plugins( plugin_basename( __FILE__ ) );
1131
1132 } // end check_admin_notices
1133
1134
1135 /*--------------------------------------------------*/
1136 /* Plugin methods / functions
1137 /*--------------------------------------------------*/
1138
1139 /**
1140 * Purges post from data/summary tables.
1141 *
1142 * @since 3.3.0
1143 */
1144 public function purge_post_init() {
1145
1146 if ( current_user_can( 'delete_posts' ) )
1147 add_action( 'delete_post', array( $this, 'purge_post' ), 10 );
1148
1149 } // end purge_post_init
1150
1151 /**
1152 * Purges post from data/summary tables.
1153 *
1154 * @since 3.3.0
1155 * @global object $wpdb
1156 * @return bool
1157 */
1158 public function purge_post( $pID ) {
1159
1160 global $wpdb;
1161
1162 if ( $wpdb->get_var( $wpdb->prepare( "SELECT postid FROM {$wpdb->prefix}popularpostsdata WHERE postid = %d", $pID ) ) ) {
1163 // Delete from data table
1164 $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}popularpostsdata WHERE postid = %d;", $pID ) );
1165 // Delete from summary table
1166 $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->prefix}popularpostssummary WHERE postid = %d;", $pID ) );
1167 }
1168
1169 return true;
1170
1171 } // end purge_post
1172
1173 /**
1174 * Purges old post data from summary table.
1175 *
1176 * @since 2.0.0
1177 * @global object $wpdb
1178 */
1179 public function purge_data() {
1180
1181 global $wpdb;
1182
1183 $wpdb->query( "DELETE FROM {$wpdb->prefix}popularpostssummary WHERE view_date < DATE_SUB('{$this->__curdate()}', INTERVAL {$this->user_settings['tools']['log']['expires_after']} DAY);" );
1184
1185 } // end purge_data
1186
1187 /**
1188 * Truncates data and cache on demand.
1189 *
1190 * @since 2.0.0
1191 * @global object wpdb
1192 */
1193 public function clear_data() {
1194
1195 $token = $_POST['token'];
1196 $clear = isset($_POST['clear']) ? $_POST['clear'] : '';
1197 $key = get_site_option("wpp_rand");
1198
1199 if (current_user_can('manage_options') && ($token === $key) && !empty($clear)) {
1200 global $wpdb;
1201
1202 // set table name
1203 $prefix = $wpdb->prefix . "popularposts";
1204
1205 if ($clear == 'cache') {
1206 if ( $wpdb->get_var("SHOW TABLES LIKE '{$prefix}summary'") ) {
1207 $wpdb->query("TRUNCATE TABLE {$prefix}summary;");
1208 $this->__flush_transients();
1209 _e('Success! The cache table has been cleared!', $this->plugin_slug);
1210 } else {
1211 _e('Error: cache table does not exist.', $this->plugin_slug);
1212 }
1213 } else if ($clear == 'all') {
1214 if ( $wpdb->get_var("SHOW TABLES LIKE '{$prefix}data'") && $wpdb->get_var("SHOW TABLES LIKE '{$prefix}summary'") ) {
1215 $wpdb->query("TRUNCATE TABLE {$prefix}data;");
1216 $wpdb->query("TRUNCATE TABLE {$prefix}summary;");
1217 $this->__flush_transients();
1218 _e('Success! All data have been cleared!', $this->plugin_slug);
1219 } else {
1220 _e('Error: one or both data tables are missing.', $this->plugin_slug);
1221 }
1222 } else {
1223 _e('Invalid action.', $this->plugin_slug);
1224 }
1225 } else {
1226 _e('Sorry, you do not have enough permissions to do this. Please contact the site administrator for support.', $this->plugin_slug);
1227 }
1228
1229 die();
1230
1231 } // end clear_data
1232
1233 /**
1234 * Truncates thumbnails cache on demand.
1235 *
1236 * @since 2.0.0
1237 * @global object wpdb
1238 */
1239 public function clear_thumbnails() {
1240
1241 $token = $_POST['token'];
1242 $key = get_site_option("wpp_rand");
1243
1244 if ( current_user_can('manage_options') && ($token === $key) ) {
1245 $wp_upload_dir = wp_upload_dir();
1246
1247 if ( is_dir( $wp_upload_dir['basedir'] . "/" . $this->plugin_slug ) ) {
1248 $files = glob( $wp_upload_dir['basedir'] . "/" . $this->plugin_slug . "/*" ); // get all file names
1249
1250 if ( is_array($files) && !empty($files) ) {
1251 foreach($files as $file){ // iterate files
1252 if ( is_file($file) )
1253 @unlink($file); // delete file
1254 }
1255
1256 _e('Success! All files have been deleted!', $this->plugin_slug);
1257 } else {
1258 _e('The thumbnail cache is already empty!', $this->plugin_slug);
1259 }
1260 } else {
1261 _e('Invalid action.', $this->plugin_slug);
1262 }
1263 } else {
1264 _e('Sorry, you do not have enough permissions to do this. Please contact the site administrator for support.', $this->plugin_slug);
1265 }
1266
1267 die();
1268
1269 } // end clear_data
1270
1271 /**
1272 * Updates views count on page load via AJAX.
1273 *
1274 * @since 2.0.0
1275 */
1276 public function update_views_ajax(){
1277
1278 if ( !wp_verify_nonce($_POST['token'], 'wpp-token') || !$this->__is_numeric($_POST['wpp_id']) )
1279 die("WPP: Oops, invalid request!");
1280
1281 $nonce = $_POST['token'];
1282 $post_ID = $_POST['wpp_id'];
1283
1284 $exec_time = 0;
1285
1286 $start = $this->__microtime_float();
1287 $result = $this->__update_views($post_ID);
1288 $end = $this->__microtime_float();
1289
1290 $exec_time += round($end - $start, 6);
1291
1292 if ( $result ) {
1293 die( "WPP: OK. Execution time: " . $exec_time . " seconds" );
1294 }
1295
1296 die( "WPP: Oops, could not update the views count!" );
1297
1298 } // end update_views_ajax
1299
1300 /**
1301 * Outputs script to update views via AJAX.
1302 *
1303 * @since 2.0.0
1304 * @global object post
1305 */
1306 public function print_ajax(){
1307
1308 if ( 0 != $this->current_post_id ) {
1309 ?>
1310 <!-- WordPress Popular Posts v<?php echo $this->version; ?> -->
1311 <script type="text/javascript">//<![CDATA[
1312
1313 var sampling_active = <?php echo ( $this->user_settings['tools']['sampling']['active'] ) ? 1 : 0; ?>;
1314 var sampling_rate = <?php echo intval( $this->user_settings['tools']['sampling']['rate'] ); ?>;
1315 var do_request = false;
1316
1317 if ( !sampling_active ) {
1318 do_request = true;
1319 } else {
1320 var num = Math.floor(Math.random() * sampling_rate) + 1;
1321 do_request = ( 1 === num );
1322 }
1323
1324 if ( do_request ) {
1325
1326 // Create XMLHttpRequest object and set variables
1327 var xhr = ( window.XMLHttpRequest )
1328 ? new XMLHttpRequest()
1329 : new ActiveXObject( "Microsoft.XMLHTTP" ),
1330 url = '<?php echo admin_url('admin-ajax.php', is_ssl() ? 'https' : 'http'); ?>',
1331 params = 'action=update_views_ajax&token=<?php echo wp_create_nonce('wpp-token') ?>&wpp_id=<?php echo $this->current_post_id; ?>';
1332 // Set request method and target URL
1333 xhr.open( "POST", url, true );
1334 // Set request header
1335 xhr.setRequestHeader( "Content-type", "application/x-www-form-urlencoded" );
1336 // Hook into onreadystatechange
1337 xhr.onreadystatechange = function() {
1338 if ( 4 === xhr.readyState && 200 === xhr.status ) {
1339 if ( window.console && window.console.log ) {
1340 window.console.log( xhr.responseText );
1341 }
1342 }
1343 };
1344 // Send request
1345 xhr.send( params );
1346
1347 }
1348
1349 //]]></script>
1350 <!-- End WordPress Popular Posts v<?php echo $this->version; ?> -->
1351 <?php
1352 }
1353
1354 } // end print_ajax
1355
1356 /**
1357 * Deletes cached (transient) data.
1358 *
1359 * @since 3.0.0
1360 */
1361 private function __flush_transients() {
1362
1363 $wpp_transients = get_site_option('wpp_transients');
1364
1365 if ( $wpp_transients && is_array($wpp_transients) && !empty($wpp_transients) ) {
1366 for ($t=0; $t < count($wpp_transients); $t++)
1367 delete_transient( $wpp_transients[$t] );
1368
1369 update_site_option('wpp_transients', array());
1370 }
1371
1372 } // end __flush_transients
1373
1374 /**
1375 * Updates views count.
1376 *
1377 * @since 1.4.0
1378 * @global object $wpdb
1379 * @param int Post ID
1380 * @return bool|int FALSE if query failed, TRUE on success
1381 */
1382 private function __update_views($id) {
1383
1384 /*
1385 TODO:
1386 For WordPress Multisite, we must define the DIEONDBERROR constant for database errors to display like so:
1387 <?php define( 'DIEONDBERROR', true ); ?>
1388 */
1389
1390 global $wpdb;
1391 $table = $wpdb->prefix . "popularposts";
1392 $wpdb->show_errors();
1393
1394 // WPML support, get original post/page ID
1395 if ( defined('ICL_LANGUAGE_CODE') && function_exists('icl_object_id') ) {
1396 global $sitepress;
1397 if ( isset( $sitepress )) { // avoids a fatal error with Polylang
1398 $id = icl_object_id( $id, get_post_type( $id ), true, $sitepress->get_default_language() );
1399 }
1400 else if ( function_exists( 'pll_default_language' ) ) { // adds Polylang support
1401 $id = icl_object_id( $id, get_post_type( $id ), true, pll_default_language() );
1402 }
1403 }
1404
1405 $now = $this->__now();
1406 $curdate = $this->__curdate();
1407 $views = ( $this->user_settings['tools']['sampling']['active'] )
1408 ? $this->user_settings['tools']['sampling']['rate']
1409 : 1;
1410
1411 // Allow WP themers / coders perform an action
1412 // before updating views count
1413 if ( has_action( 'wpp_pre_update_views' ) )
1414 do_action( 'wpp_pre_update_views', $id, $views );
1415
1416 // Update all-time table
1417 $result1 = $wpdb->query( $wpdb->prepare(
1418 "INSERT INTO {$table}data
1419 (postid, day, last_viewed, pageviews) VALUES (%d, %s, %s, %d)
1420 ON DUPLICATE KEY UPDATE pageviews = pageviews + %4\$d, last_viewed = '%3\$s';",
1421 $id,
1422 $now,
1423 $now,
1424 $views
1425 ));
1426
1427 // Update range (summary) table
1428 $result2 = $wpdb->query( $wpdb->prepare(
1429 "INSERT INTO {$table}summary
1430 (postid, pageviews, view_date, last_viewed) VALUES (%d, %d, %s, %s)
1431 ON DUPLICATE KEY UPDATE pageviews = pageviews + %2\$d, last_viewed = '%4\$s';",
1432 $id,
1433 $views,
1434 $curdate,
1435 $now
1436 ));
1437
1438 if ( !$result1 || !$result2 )
1439 return false;
1440
1441 // Allow WP themers / coders perform an action
1442 // after updating views count
1443 if ( has_action( 'wpp_post_update_views' ) )
1444 do_action( 'wpp_post_update_views', $id );
1445
1446 return true;
1447
1448 } // end __update_views
1449
1450 /**
1451 * Queries the database and returns the posts (if any met the criteria set by the user).
1452 *
1453 * @since 1.4.0
1454 * @global object $wpdb
1455 * @param array Widget instance
1456 * @return null|array Array of posts, or null if nothing was found
1457 */
1458 protected function _query_posts($instance) {
1459
1460 global $wpdb;
1461
1462 // parse instance values
1463 $instance = $this->__merge_array_r(
1464 $this->defaults,
1465 $instance
1466 );
1467
1468 $prefix = $wpdb->prefix . "popularposts";
1469 $fields = "p.ID AS 'id', p.post_title AS 'title', p.post_date AS 'date', p.post_author AS 'uid'";
1470 $from = "";
1471 $where = "WHERE 1 = 1";
1472 $orderby = "";
1473 $groupby = "";
1474 $limit = "LIMIT {$instance['limit']}";
1475
1476 $post_types = "";
1477 $pids = "";
1478 $cats = "";
1479 $authors = "";
1480 $content = "";
1481
1482 $now = $this->__now();
1483
1484 // post filters
1485 // * freshness - get posts published within the selected time range only
1486 if ( $instance['freshness'] ) {
1487 switch( $instance['range'] ){
1488 case "daily":
1489 $where .= " AND p.post_date > DATE_SUB('{$now}', INTERVAL 1 DAY) ";
1490 break;
1491
1492 case "weekly":
1493 $where .= " AND p.post_date > DATE_SUB('{$now}', INTERVAL 1 WEEK) ";
1494 break;
1495
1496 case "monthly":
1497 $where .= " AND p.post_date > DATE_SUB('{$now}', INTERVAL 1 MONTH) ";
1498 break;
1499
1500 default:
1501 $where .= "";
1502 break;
1503 }
1504 }
1505
1506 // * post types - based on code seen at https://github.com/williamsba/WordPress-Popular-Posts-with-Custom-Post-Type-Support
1507 $types = explode(",", $instance['post_type']);
1508 $sql_post_types = "";
1509 $join_cats = true;
1510
1511 // if we're getting just pages, why join the categories table?
1512 if ( 'page' == strtolower($instance['post_type']) ) {
1513
1514 $join_cats = false;
1515 $where .= " AND p.post_type = '{$instance['post_type']}'";
1516
1517 }
1518 // we're listing other custom type(s)
1519 else {
1520
1521 if ( count($types) > 1 ) {
1522
1523 foreach ( $types as $post_type ) {
1524 $post_type = trim($post_type); // required in case user places whitespace between commas
1525 $sql_post_types .= "'{$post_type}',";
1526 }
1527
1528 $sql_post_types = rtrim( $sql_post_types, ",");
1529 $where .= " AND p.post_type IN({$sql_post_types})";
1530
1531 } else {
1532 $where .= " AND p.post_type = '{$instance['post_type']}'";
1533 }
1534
1535 }
1536
1537 // * posts exclusion
1538 if ( !empty($instance['pid']) ) {
1539
1540 $ath = explode(",", $instance['pid']);
1541
1542 $where .= ( count($ath) > 1 )
1543 ? " AND p.ID NOT IN({$instance['pid']})"
1544 : " AND p.ID <> '{$instance['pid']}'";
1545
1546 }
1547
1548 // * categories
1549 if ( !empty($instance['cat']) && $join_cats ) {
1550
1551 $cat_ids = explode(",", $instance['cat']);
1552 $in = array();
1553 $out = array();
1554
1555 for ($i=0; $i < count($cat_ids); $i++) {
1556 if ($cat_ids[$i] >= 0)
1557 $in[] = $cat_ids[$i];
1558 else
1559 $out[] = $cat_ids[$i];
1560 }
1561
1562 $in_cats = implode(",", $in);
1563 $out_cats = implode(",", $out);
1564 $out_cats = preg_replace( '|[^0-9,]|', '', $out_cats );
1565
1566 if ($in_cats != "" && $out_cats == "") { // get posts from from given cats only
1567 $where .= " AND p.ID IN (
1568 SELECT object_id
1569 FROM {$wpdb->term_relationships} AS r
1570 JOIN {$wpdb->term_taxonomy} AS x ON x.term_taxonomy_id = r.term_taxonomy_id
1571 WHERE x.taxonomy = 'category' AND x.term_id IN({$in_cats})
1572 )";
1573 } else if ($in_cats == "" && $out_cats != "") { // exclude posts from given cats only
1574 $where .= " AND p.ID NOT IN (
1575 SELECT object_id
1576 FROM {$wpdb->term_relationships} AS r
1577 JOIN {$wpdb->term_taxonomy} AS x ON x.term_taxonomy_id = r.term_taxonomy_id
1578 WHERE x.taxonomy = 'category' AND x.term_id IN({$out_cats})
1579 )";
1580 } else { // mixed
1581 $where .= " AND p.ID IN (
1582 SELECT object_id
1583 FROM {$wpdb->term_relationships} AS r
1584 JOIN {$wpdb->term_taxonomy} AS x ON x.term_taxonomy_id = r.term_taxonomy_id
1585 WHERE x.taxonomy = 'category' AND x.term_id IN({$in_cats}) AND x.term_id NOT IN({$out_cats})
1586 ) ";
1587 }
1588
1589 }
1590
1591 // * authors
1592 if ( !empty($instance['author']) ) {
1593
1594 $ath = explode(",", $instance['author']);
1595
1596 $where .= ( count($ath) > 1 )
1597 ? " AND p.post_author IN({$instance['author']})"
1598 : " AND p.post_author = '{$instance['author']}'";
1599
1600 }
1601
1602 // All-time range
1603 if ( "all" == $instance['range'] ) {
1604
1605 $fields .= ", p.comment_count AS 'comment_count'";
1606
1607 // order by comments
1608 if ( "comments" == $instance['order_by'] ) {
1609
1610 $from = "{$wpdb->posts} p";
1611 $where .= " AND p.comment_count > 0 ";
1612 $orderby = " ORDER BY p.comment_count DESC";
1613
1614 // get views, too
1615 if ( $instance['stats_tag']['views'] ) {
1616
1617 $fields .= ", IFNULL(v.pageviews, 0) AS 'pageviews'";
1618 $from .= " LEFT JOIN {$prefix}data v ON p.ID = v.postid";
1619
1620 }
1621
1622 }
1623 // order by (avg) views
1624 else {
1625
1626 $from = "{$prefix}data v LEFT JOIN {$wpdb->posts} p ON v.postid = p.ID";
1627
1628 // order by views
1629 if ( "views" == $instance['order_by'] ) {
1630
1631 $fields .= ", v.pageviews AS 'pageviews'";
1632 $orderby = "ORDER BY pageviews DESC";
1633
1634 }
1635 // order by avg views
1636 elseif ( "avg" == $instance['order_by'] ) {
1637
1638 $fields .= ", ( v.pageviews/(IF ( DATEDIFF('{$now}', MIN(v.day)) > 0, DATEDIFF('{$now}', MIN(v.day)), 1) ) ) AS 'avg_views'";
1639 $groupby = "GROUP BY v.postid";
1640 $orderby = "ORDER BY avg_views DESC";
1641
1642 }
1643
1644 }
1645
1646 } else { // CUSTOM RANGE
1647
1648 $interval = "";
1649
1650 switch( $instance['range'] ){
1651 case "daily":
1652 $interval = "1 DAY";
1653 break;
1654
1655 case "weekly":
1656 $interval = "1 WEEK";
1657 break;
1658
1659 case "monthly":
1660 $interval = "1 MONTH";
1661 break;
1662
1663 default:
1664 $interval = "1 DAY";
1665 break;
1666 }
1667
1668 // order by comments
1669 if ( "comments" == $instance['order_by'] ) {
1670
1671 $fields .= ", COUNT(c.comment_post_ID) AS 'comment_count'";
1672 $from = "{$wpdb->comments} c LEFT JOIN {$wpdb->posts} p ON c.comment_post_ID = p.ID";
1673 $where .= " AND c.comment_date_gmt > DATE_SUB('{$now}', INTERVAL {$interval}) AND c.comment_approved = 1 ";
1674 $groupby = "GROUP BY c.comment_post_ID";
1675 $orderby = "ORDER BY comment_count DESC";
1676
1677 if ( $instance['stats_tag']['views'] ) { // get views, too
1678
1679 $fields .= ", IFNULL(v.pageviews, 0) AS 'pageviews'";
1680 $from .= " LEFT JOIN (SELECT postid, SUM(pageviews) AS pageviews FROM {$prefix}summary WHERE last_viewed > DATE_SUB('{$now}', INTERVAL {$interval}) GROUP BY postid) v ON p.ID = v.postid";
1681
1682 }
1683
1684 }
1685 // ordered by views / avg
1686 else {
1687
1688 $from = "{$prefix}summary v LEFT JOIN {$wpdb->posts} p ON v.postid = p.ID";
1689 $where .= " AND v.last_viewed > DATE_SUB('{$now}', INTERVAL {$interval}) ";
1690 $groupby = "GROUP BY v.postid";
1691
1692 // ordered by views
1693 if ( "views" == $instance['order_by'] ) {
1694
1695 $fields .= ", SUM(v.pageviews) AS 'pageviews'";
1696 $orderby = "ORDER BY pageviews DESC";
1697
1698 }
1699 // ordered by avg views
1700 elseif ( "avg" == $instance['order_by'] ) {
1701
1702 $fields .= ", ( SUM(v.pageviews)/(IF ( DATEDIFF('{$now}', DATE_SUB('{$now}', INTERVAL {$interval})) > 0, DATEDIFF('{$now}', DATE_SUB('{$now}', INTERVAL {$interval})), 1) ) ) AS 'avg_views' ";
1703 $orderby = "ORDER BY avg_views DESC";
1704
1705 }
1706
1707 // get comments, too
1708 if ( $instance['stats_tag']['comment_count'] ) {
1709
1710 $fields .= ", IFNULL(c.comment_count, 0) AS 'comment_count'";
1711 $from .= " LEFT JOIN (SELECT comment_post_ID, COUNT(comment_post_ID) AS 'comment_count' FROM {$wpdb->comments} WHERE comment_date_gmt > DATE_SUB('{$now}', INTERVAL {$interval}) AND comment_approved = 1 GROUP BY comment_post_ID) c ON p.ID = c.comment_post_ID";
1712
1713 }
1714
1715 }
1716
1717 }
1718
1719 // List only published, non password-protected posts
1720 $where .= " AND p.post_password = '' AND p.post_status = 'publish'";
1721
1722 // Build query
1723 $query = "SELECT {$fields} FROM {$from} {$where} {$groupby} {$orderby} {$limit};";
1724
1725 $this->__debug( $query );
1726
1727 $result = $wpdb->get_results($query);
1728
1729 return apply_filters( 'wpp_query_posts', $result, $instance );
1730
1731 } // end query_posts
1732
1733 /**
1734 * Returns the formatted list of posts.
1735 *
1736 * @since 3.0.0
1737 * @param array instance The current instance of the widget / shortcode parameters
1738 * @return string HTML list of popular posts
1739 */
1740 private function __get_popular_posts( $instance ) {
1741
1742 // Parse instance values
1743 $instance = $this->__merge_array_r(
1744 $this->defaults,
1745 $instance
1746 );
1747
1748 // Pass the widget ID, might come in handy
1749 if ( isset($this->id) )
1750 $instance['widget_id'] = $this->id;
1751
1752 $content = "";
1753
1754 // Fetch posts
1755 if ( !defined('WPP_ADMIN') && $this->user_settings['tools']['cache']['active'] ) {
1756 $transient_name = md5(json_encode($instance));
1757 $mostpopular = ( function_exists( 'is_multisite' ) && is_multisite() )
1758 ? get_site_transient( $transient_name )
1759 : get_transient( $transient_name );
1760
1761 $content = "\n" . "<!-- cached -->" . "\n";
1762
1763 // It wasn't there, so regenerate the data and save the transient
1764 if ( false === $mostpopular ) {
1765 $mostpopular = $this->_query_posts( $instance );
1766
1767 switch($this->user_settings['tools']['cache']['interval']['time']){
1768 case 'minute':
1769 $time = 60;
1770 break;
1771
1772 case 'hour':
1773 $time = 60 * 60;
1774 break;
1775
1776 case 'day':
1777 $time = 60 * 60 * 24;
1778 break;
1779
1780 case 'week':
1781 $time = 60 * 60 * 24 * 7;
1782 break;
1783
1784 case 'month':
1785 $time = 60 * 60 * 24 * 30;
1786 break;
1787
1788 case 'year':
1789 $time = 60 * 60 * 24 * 365;
1790 break;
1791 }
1792
1793 $expiration = $time * $this->user_settings['tools']['cache']['interval']['value'];
1794
1795 if ( function_exists( 'is_multisite' ) && is_multisite() )
1796 set_site_transient( $transient_name, $mostpopular, $expiration );
1797 else
1798 set_transient( $transient_name, $mostpopular, $expiration );
1799
1800 $wpp_transients = get_site_option('wpp_transients');
1801
1802 if ( !$wpp_transients ) {
1803 $wpp_transients = array( $transient_name );
1804 add_site_option('wpp_transients', $wpp_transients);
1805 } else {
1806 if ( !in_array($transient_name, $wpp_transients) ) {
1807 $wpp_transients[] = $transient_name;
1808 update_site_option('wpp_transients', $wpp_transients);
1809 }
1810 }
1811 }
1812 } else {
1813 $mostpopular = $this->_query_posts( $instance );
1814 }
1815
1816 // No posts to show
1817 if ( !is_array($mostpopular) || empty($mostpopular) ) {
1818 return apply_filters( 'wpp_no_data', "<p class=\"wpp-no-data\">" . __('Sorry. No data so far.', $this->plugin_slug) . "</p>" );
1819 }
1820
1821 // Allow WP themers / coders access to raw data
1822 // so they can build their own output
1823 if ( has_filter( 'wpp_custom_html' ) && !defined('WPP_ADMIN') ) {
1824 return apply_filters( 'wpp_custom_html', $mostpopular, $instance );
1825 }
1826
1827 // HTML wrapper
1828 if ($instance['markup']['custom_html']) {
1829 $content .= "\n" . htmlspecialchars_decode($instance['markup']['wpp-start'], ENT_QUOTES) ."\n";
1830 } else {
1831 $content .= "\n" . "<ul class=\"wpp-list\">" . "\n";
1832 }
1833
1834 // Loop through posts
1835 foreach($mostpopular as $p) {
1836 $content .= $this->__render_popular_post( $p, $instance );
1837 }
1838
1839 // END HTML wrapper
1840 if ($instance['markup']['custom_html']) {
1841 $content .= "\n". htmlspecialchars_decode($instance['markup']['wpp-end'], ENT_QUOTES) ."\n";
1842 } else {
1843 $content .= "\n". "</ul>". "\n";
1844 }
1845
1846 return $content;
1847
1848 } // end __get_popular_posts
1849
1850 /**
1851 * Returns the formatted post.
1852 *
1853 * @since 3.0.0
1854 * @param object p
1855 * @param array instance The current instance of the widget / shortcode parameters
1856 * @return string
1857 */
1858 private function __render_popular_post($p, $instance) {
1859
1860 // WPML support, based on Serhat Evren's suggestion - see http://wordpress.org/support/topic/wpml-trick#post-5452607
1861 if ( defined('ICL_LANGUAGE_CODE') && function_exists('icl_object_id') ) {
1862 $current_id = icl_object_id( $p->id, get_post_type( $p->id ), true, ICL_LANGUAGE_CODE );
1863 $permalink = get_permalink( $current_id );
1864 } // Get original permalink
1865 else {
1866 $permalink = get_permalink($p->id);
1867 }
1868
1869 $title = $this->_get_title($p, $instance);
1870 $title_sub = $this->_get_title_sub($p, $instance);
1871
1872 $author = $this->_get_author($p, $instance);
1873 $post_cat = $this->_get_post_cat($p, $instance);
1874
1875 $thumb = $this->_get_thumb($p, $instance);
1876 $excerpt = $this->_get_excerpt($p, $instance);
1877
1878 $pageviews = $this->_get_pageviews($p, $instance);
1879 $comments = $this->_get_comments($p, $instance);
1880 $rating = $this->_get_rating($p, $instance);
1881 $date = $this->_get_date($p, $instance);
1882
1883 $_stats = join(' | ', $this->_get_stats($p, $instance));
1884
1885 // PUTTING IT ALL TOGETHER
1886 // build custom layout
1887 if ($instance['markup']['custom_html']) {
1888
1889 $data = array(
1890 'title' => '<a href="'.$permalink.'" title="'. esc_attr($title) .'" class="wpp-post-title" target="' . $this->user_settings['tools']['link']['target'] . '">'.$title_sub.'</a>',
1891 'summary' => $excerpt,
1892 'stats' => $_stats,
1893 'img' => ( !empty($thumb) ) ? '<a href="'.$permalink.'" title="'. esc_attr($title) .'" target="' . $this->user_settings['tools']['link']['target'] . '">' . $thumb . '</a>' : '',
1894 'img_no_link' => $thumb,
1895 'id' => $p->id,
1896 'url' => $permalink,
1897 'text_title' => esc_attr($title),
1898 'category' => $post_cat,
1899 'author' => '<a href="' . get_author_posts_url($p->uid) . '">' . $author . '</a>',
1900 'views' => ($instance['order_by'] == "views" || $instance['order_by'] == "comments") ? number_format_i18n( $pageviews ) : number_format_i18n( $pageviews, 2 ),
1901 'comments' => number_format_i18n( $comments ),
1902 'date' => $date
1903 );
1904
1905 $content = $this->__format_content( htmlspecialchars_decode($instance['markup']['post-html'], ENT_QUOTES ), $data, $instance['rating'] ). "\n";
1906
1907 }
1908 // build regular layout
1909 else {
1910 $thumb = ( !empty($thumb) )
1911 ? '<a ' . ( ( $this->current_post_id == $p->id ) ? '' : 'href="' . $permalink . '"' ) . ' title="' . esc_attr($title) . '" target="' . $this->user_settings['tools']['link']['target'] . '">' . $thumb . '</a> '
1912 : '';
1913
1914 $_stats = ( !empty($_stats) )
1915 ? ' <span class="post-stats">' . $_stats . '</span> '
1916 : '';
1917
1918 $content =
1919 '<li' . ( ( $this->current_post_id == $p->id ) ? ' class="current"' : '' ) . '>'
1920 . $thumb
1921 . '<a ' . ( ( $this->current_post_id == $p->id ) ? '' : 'href="' . $permalink . '"' ) . ' title="' . esc_attr($title) . '" class="wpp-post-title" target="' . $this->user_settings['tools']['link']['target'] . '">' . $title_sub . '</a> '
1922 . $excerpt . $_stats
1923 . $rating
1924 . "</li>\n";
1925 }
1926
1927 return apply_filters('wpp_post', $content, $p, $instance);
1928
1929 } // end __render_popular_post
1930
1931 /**
1932 * Cache.
1933 *
1934 * @since 3.0.0
1935 * @param string $func function name
1936 * @param mixed $default
1937 * @return mixed
1938 */
1939 private function &__cache($func, $default = null) {
1940
1941 static $cache;
1942
1943 if ( !isset($cache) ) {
1944 $cache = array();
1945 }
1946
1947 if ( !isset($cache[$func]) ) {
1948 $cache[$func] = $default;
1949 }
1950
1951 return $cache[$func];
1952
1953 } // end __cache
1954
1955 /**
1956 * Gets post title.
1957 *
1958 * @since 3.0.0
1959 * @param object p
1960 * @param array instance The current instance of the widget / shortcode parameters
1961 * @return string
1962 */
1963 protected function _get_title($p, $instance) {
1964
1965 $cache = &$this->__cache(__FUNCTION__, array());
1966
1967 if ( isset($cache[$p->id]) ) {
1968 return $cache[$p->id];
1969 }
1970
1971 // WPML support, based on Serhat Evren's suggestion - see http://wordpress.org/support/topic/wpml-trick#post-5452607
1972 if ( defined('ICL_LANGUAGE_CODE') && function_exists('icl_object_id') ) {
1973 $current_id = icl_object_id( $p->id, get_post_type( $p->id ), true, ICL_LANGUAGE_CODE );
1974 $title = get_the_title( $current_id );
1975 } // Check for qTranslate
1976 else if ( $this->qTrans && function_exists('qtrans_useCurrentLanguageIfNotFoundUseDefaultLanguage') ) {
1977 $title = qtrans_useCurrentLanguageIfNotFoundUseDefaultLanguage( $p->title );
1978 } // Use ol' plain title
1979 else {
1980 $title = $p->title;
1981 }
1982
1983 // Strip HTML tags
1984 $title = strip_tags($title);
1985
1986 return $cache[$p->id] = apply_filters('the_title', $title, $p->id);
1987
1988 } // end _get_title
1989
1990 /**
1991 * Gets substring of post title.
1992 *
1993 * @since 3.0.0
1994 * @param object p
1995 * @param array instance The current instance of the widget / shortcode parameters
1996 * @return string
1997 */
1998 protected function _get_title_sub($p, $instance) {
1999
2000 $cache = &$this->__cache(__FUNCTION__, array());
2001
2002 if ( isset($cache[$p->id]) ) {
2003 return $cache[$p->id];
2004 }
2005
2006 // TITLE
2007 $title_sub = $this->_get_title($p, $instance);
2008
2009 // truncate title
2010 if ($instance['shorten_title']['active']) {
2011 // by words
2012 if (isset($instance['shorten_title']['words']) && $instance['shorten_title']['words']) {
2013
2014 $words = explode(" ", $title_sub, $instance['shorten_title']['length'] + 1);
2015 if (count($words) > $instance['shorten_title']['length']) {
2016 array_pop($words);
2017 $title_sub = implode(" ", $words) . "...";
2018 }
2019
2020 }
2021 elseif (strlen($title_sub) > $instance['shorten_title']['length']) {
2022 $title_sub = mb_substr($title_sub, 0, $instance['shorten_title']['length'], $this->charset) . "...";
2023 }
2024 }
2025
2026 return $cache[$p->id] = $title_sub;
2027
2028 } // end _get_title_sub
2029
2030 /**
2031 * Gets post's excerpt.
2032 *
2033 * @since 3.0.0
2034 * @param object p
2035 * @param array instance The current instance of the widget / shortcode parameters
2036 * @return string
2037 */
2038 protected function _get_excerpt($p, $instance) {
2039
2040 $excerpt = '';
2041
2042 // EXCERPT
2043 if ($instance['post-excerpt']['active']) {
2044
2045 $excerpt = trim($this->_get_summary($p->id, $instance));
2046
2047 if (!empty($excerpt) && !$instance['markup']['custom_html']) {
2048 $excerpt = '<span class="wpp-excerpt">' . $excerpt . '</span>';
2049 }
2050
2051 }
2052
2053 return $excerpt;
2054
2055 } // end _get_excerpt
2056
2057 /**
2058 * Gets post's thumbnail.
2059 *
2060 * @since 3.0.0
2061 * @param object p
2062 * @param array instance The current instance of the widget / shortcode parameters
2063 * @return string
2064 */
2065 protected function _get_thumb($p, $instance) {
2066
2067 if ( !$instance['thumbnail']['active'] || !$this->thumbnailing ) {
2068 return '';
2069 }
2070
2071 $tbWidth = $instance['thumbnail']['width'];
2072 $tbHeight = $instance['thumbnail']['height'];
2073 $crop = $instance['thumbnail']['crop'];
2074 $title = $this->_get_title($p, $instance);
2075
2076 $thumb = '';
2077
2078 // get image from custom field
2079 if ($this->user_settings['tools']['thumbnail']['source'] == "custom_field") {
2080 $path = get_post_meta($p->id, $this->user_settings['tools']['thumbnail']['field'], true);
2081
2082 if ($path != '') {
2083 // user has requested to resize cf image
2084 if ( $this->user_settings['tools']['thumbnail']['resize'] ) {
2085 $thumb .= $this->__get_img($p, null, $path, array($tbWidth, $tbHeight), $crop, $this->user_settings['tools']['thumbnail']['source'], $title);
2086 }
2087 // use original size
2088 else {
2089 $thumb .= $this->_render_image($path, array($tbWidth, $tbHeight), 'wpp-thumbnail wpp_cf', $title);
2090 }
2091 }
2092 else {
2093 $thumb .= $this->_render_image($this->default_thumbnail, array($tbWidth, $tbHeight), 'wpp-thumbnail wpp_cf_def', $title);
2094 }
2095 }
2096 // get image from post / Featured Image
2097 else {
2098
2099 // User wants to use the Featured Image using the 'stock' sizes, get stock thumbnails
2100 if ( 'predefined' == $instance['thumbnail']['build'] && 'featured' == $this->user_settings['tools']['thumbnail']['source'] ) {
2101
2102 // The has_post_thumbnail() functions requires theme's 'post-thumbnails' support, otherwise an error will be thrown
2103 if ( current_theme_supports( 'post-thumbnails' ) ) {
2104
2105 // Featured image found, retrieve it
2106 if ( has_post_thumbnail($p->id) ) {
2107 $size = null;
2108
2109 foreach ( $this->default_thumbnail_sizes as $name => $attr ) :
2110 if ( $attr['width'] == $tbWidth && $attr['height'] == $tbHeight && $attr['crop'] == $crop ) {
2111 $size = $name;
2112 break;
2113 }
2114 endforeach;
2115
2116 // Couldn't find a matching size (this should like never happen, but...) let's use width & height instead
2117 if ( null == $size ) {
2118 $size = array( $tbWidth, $tbHeight );
2119 }
2120
2121 if ( $this->user_settings['tools']['thumbnail']['responsive'] )
2122 $thumb .= preg_replace( '/(width|height)=["\']\d*["\']\s?/', "", get_the_post_thumbnail($p->id, $size, array( 'class' => 'wpp-thumbnail wpp_featured_stock' )) );
2123 else
2124 $thumb .= get_the_post_thumbnail( $p->id, $size, array( 'class' => 'wpp-thumbnail wpp_featured_stock' ) );
2125 }
2126 // No featured image found
2127 else {
2128 $thumb .= $this->_render_image($this->default_thumbnail, array($tbWidth, $tbHeight), 'wpp-thumbnail wpp_featured_def', $title);
2129 }
2130
2131 } // Current theme does not support 'post-thumbnails' feature
2132 else {
2133 $thumb .= $this->_render_image($this->default_thumbnail, array($tbWidth, $tbHeight), 'wpp-thumbnail wpp_featured_def', $title, 'No post-thumbnail support?');
2134 }
2135
2136 }
2137 // Get/generate custom thumbnail
2138 else {
2139 $thumb .= $this->__get_img($p, $p->id, null, array($tbWidth, $tbHeight), $crop, $this->user_settings['tools']['thumbnail']['source'], $title);
2140 }
2141
2142 }
2143
2144 return $thumb;
2145
2146 } // end _get_thumb
2147
2148 /**
2149 * Gets post's views.
2150 *
2151 * @since 3.0.0
2152 * @param object p
2153 * @param array instance The current instance of the widget / shortcode parameters
2154 * @return int|float
2155 */
2156 protected function _get_pageviews($p, $instance) {
2157
2158 $pageviews = 0;
2159
2160 if (
2161 $instance['order_by'] == "views"
2162 || $instance['order_by'] == "avg"
2163 || $instance['stats_tag']['views']
2164 ) {
2165 $pageviews = ($instance['order_by'] == "views" || $instance['order_by'] == "comments")
2166 ? $p->pageviews
2167 : $p->avg_views;
2168 }
2169
2170 return $pageviews;
2171
2172 } // end _get_pageviews
2173
2174 /**
2175 * Gets post's comment count.
2176 *
2177 * @since 3.0.0
2178 * @param object p
2179 * @param array instance The current instance of the widget / shortcode parameters
2180 * @return int
2181 */
2182 protected function _get_comments($p, $instance) {
2183
2184 $comments = ($instance['order_by'] == "comments" || $instance['stats_tag']['comment_count'])
2185 ? $p->comment_count
2186 : 0;
2187
2188 return $comments;
2189
2190 } // end _get_comments
2191
2192 /**
2193 * Gets post's rating.
2194 *
2195 * @since 3.0.0
2196 * @param object p
2197 * @param array instance The current instance of the widget / shortcode parameters
2198 * @return string
2199 */
2200 protected function _get_rating($p, $instance) {
2201
2202 $cache = &$this->__cache(__FUNCTION__, array());
2203
2204 if ( isset($cache[$p->id]) ) {
2205 return $cache[$p->id];
2206 }
2207
2208 $rating = '';
2209
2210 // RATING
2211 if (function_exists('the_ratings') && $instance['rating']) {
2212 $rating = '<span class="wpp-rating">' . the_ratings('span', $p->id, false) . '</span>';
2213 }
2214
2215 return $cache[$p->id] = $rating;
2216 } // end _get_rating
2217
2218 /**
2219 * Gets post's author.
2220 *
2221 * @since 3.0.0
2222 * @param object p
2223 * @param array instance The current instance of the widget / shortcode parameters
2224 * @return string
2225 */
2226 protected function _get_author($p, $instance) {
2227
2228 $cache = &$this->__cache(__FUNCTION__, array());
2229
2230 if ( isset($cache[$p->id]) ) {
2231 return $cache[$p->id];
2232 }
2233
2234 $author = ($instance['stats_tag']['author'])
2235 ? get_the_author_meta('display_name', $p->uid)
2236 : "";
2237
2238 return $cache[$p->id] = $author;
2239
2240 } // end _get_author
2241
2242 /**
2243 * Gets post's date.
2244 *
2245 * @since 3.0.0
2246 * @param object p
2247 * @param array instance The current instance of the widget / shortcode parameters
2248 * @return string
2249 */
2250 protected function _get_date($p, $instance) {
2251
2252 $cache = &$this->__cache(__FUNCTION__, array());
2253
2254 if ( isset($cache[$p->id]) ) {
2255 return $cache[$p->id];
2256 }
2257
2258 $date = date_i18n($instance['stats_tag']['date']['format'], strtotime($p->date));
2259 return $cache[$p->id] = $date;
2260
2261 } // end _get_date
2262
2263 /**
2264 * Gets post's category.
2265 *
2266 * @since 3.0.0
2267 * @param object p
2268 * @param array instance The current instance of the widget / shortcode parameters
2269 * @return string
2270 */
2271 protected function _get_post_cat($p, $instance) {
2272
2273 $post_cat = '';
2274
2275 if ($instance['stats_tag']['category']) {
2276
2277 $cache = &$this->__cache(__FUNCTION__, array());
2278
2279 if ( isset($cache[$p->id]) ) {
2280 return $cache[$p->id];
2281 }
2282
2283 // Try and get parent category
2284 $cats = get_the_category($p->id);
2285
2286 foreach( $cats as $cat ) {
2287 if( $cat->category_parent == 0) {
2288 $post_cat = $cat;
2289 }
2290 }
2291
2292 // Default to first category avaliable
2293 if ( $post_cat == "" && isset($cats[0]) && isset($cats[0]->slug) ) {
2294 $post_cat = $cats[0];
2295 }
2296
2297 // Build category tag
2298 if ( "" != $post_cat ) {
2299
2300 $category_id = $post_cat->term_id;
2301 $category_name = $post_cat->cat_name;
2302
2303 // WPML support, based on Serhat Evren's suggestion - see http://wordpress.org/support/topic/wpml-trick#post-5452607
2304 if ( defined('ICL_LANGUAGE_CODE') && function_exists('icl_object_id') ) {
2305 $category_id = icl_object_id( $category_id, 'category', true, ICL_LANGUAGE_CODE );
2306 $category_name = get_the_category_by_ID( $category_id );
2307 }
2308
2309 $post_cat = '<a href="' . get_category_link( $category_id ) . '" class="cat-id-' . $category_id . '">' . $category_name . '</a>';
2310
2311 }
2312
2313 return $cache[$p->id] = $post_cat;
2314
2315 }
2316
2317 return $post_cat;
2318
2319 } // end _get_post_cat
2320
2321 /**
2322 * Gets statistics data.
2323 *
2324 * @since 3.0.0
2325 * @param object p
2326 * @param array instance The current instance of the widget / shortcode parameters
2327 * @return array
2328 */
2329 protected function _get_stats($p, $instance) {
2330
2331 $cache = &$this->__cache(__FUNCTION__ . md5(json_encode($instance)), array());
2332
2333 if ( isset($cache[$p->id]) ) {
2334 return $cache[$p->id];
2335 }
2336
2337 $stats = array();
2338
2339 // STATS
2340 // comments
2341 if ($instance['stats_tag']['comment_count']) {
2342 $comments = $this->_get_comments($p, $instance);
2343
2344 $comments_text = sprintf(
2345 _n('1 comment', '%s comments', $comments, $this->plugin_slug),
2346 number_format_i18n( $comments )
2347 );
2348
2349 }
2350
2351 // views
2352 if ($instance['stats_tag']['views']) {
2353 $pageviews = $this->_get_pageviews($p, $instance);
2354
2355 if ($instance['order_by'] == 'avg') {
2356 $views_text = sprintf(
2357 _n('1 view per day', '%s views per day', $pageviews, $this->plugin_slug),
2358 number_format_i18n( $pageviews, 2 )
2359 );
2360 }
2361 else {
2362 $views_text = sprintf(
2363 _n('1 view', '%s views', $pageviews, $this->plugin_slug),
2364 number_format_i18n( $pageviews )
2365 );
2366 }
2367
2368 }
2369
2370 if ( "comments" == $instance['order_by'] ) {
2371 if ($instance['stats_tag']['comment_count'])
2372 $stats[] = '<span class="wpp-comments">' . $comments_text . '</span>'; // First comments count
2373 if ($instance['stats_tag']['views'])
2374 $stats[] = '<span class="wpp-views">' . $views_text . "</span>"; // ... then views
2375 } else {
2376 if ($instance['stats_tag']['views'])
2377 $stats[] = '<span class="wpp-views">' . $views_text . "</span>"; // First views count
2378 if ($instance['stats_tag']['comment_count'])
2379 $stats[] = '<span class="wpp-comments">' . $comments_text . '</span>'; // ... then comments
2380 }
2381
2382 // author
2383 if ($instance['stats_tag']['author']) {
2384 $author = $this->_get_author($p, $instance);
2385 $display_name = '<a href="' . get_author_posts_url($p->uid) . '">' . $author . '</a>';
2386 $stats[] = '<span class="wpp-author">' . sprintf(__('by %s', $this->plugin_slug), $display_name).'</span>';
2387 }
2388
2389 // date
2390 if ($instance['stats_tag']['date']['active']) {
2391 $date = $this->_get_date($p, $instance);
2392 $stats[] = '<span class="wpp-date">' . sprintf(__('posted on %s', $this->plugin_slug), $date) . '</span>';
2393 }
2394
2395 // category
2396 if ($instance['stats_tag']['category']) {
2397 $post_cat = $this->_get_post_cat($p, $instance);
2398
2399 if ($post_cat != '') {
2400 $stats[] = '<span class="wpp-category">' . sprintf(__('under %s', $this->plugin_slug), $post_cat) . '</span>';
2401 }
2402 }
2403
2404 return $cache[$p->id] = $stats;
2405
2406 } // end _get_stats
2407
2408 /**
2409 * Retrieves / creates the post thumbnail.
2410 *
2411 * @since 2.3.3
2412 * @param int id Post ID
2413 * @param string url Image URL
2414 * @param array dim Thumbnail width & height
2415 * @param string source Image source
2416 * @return string
2417 */
2418 private function __get_img($p, $id = null, $url = null, $dim = array(80, 80), $crop = true, $source = "featured", $title) {
2419
2420 if ( (!$id || empty($id) || !$this->__is_numeric($id)) && (!$url || empty($url)) ) {
2421 return $this->_render_image($this->default_thumbnail, $dim, 'wpp-thumbnail wpp_def_noID', $title);
2422 }
2423
2424 // Get image by post ID (parent)
2425 if ( $id ) {
2426 $file_path = $this->__get_image_file_paths($id, $source);
2427
2428 // No images found, return default thumbnail
2429 if ( !$file_path ) {
2430 return $this->_render_image($this->default_thumbnail, $dim, 'wpp-thumbnail wpp_def_noPath wpp_' . $source, $title);
2431 }
2432 }
2433 // Get image from URL
2434 else {
2435 // sanitize URL, just in case
2436 $image_url = esc_url( $url );
2437 // remove querystring
2438 preg_match('/[^\?]+\.(jpg|JPG|jpe|JPE|jpeg|JPEG|gif|GIF|png|PNG)/', $image_url, $matches);
2439 $image_url = $matches[0];
2440
2441 $attachment_id = $this->__get_attachment_id($image_url);
2442
2443 // Image is hosted locally
2444 if ( $attachment_id ) {
2445 $file_path = get_attached_file($attachment_id);
2446 }
2447 // Image is hosted outside WordPress
2448 else {
2449 $external_image = $this->__fetch_external_image($p->id, $image_url);
2450
2451 if ( !$external_image ) {
2452 return $this->_render_image($this->default_thumbnail, $dim, 'wpp-thumbnail wpp_def_noPath wpp_no_external', $title);
2453 }
2454
2455 $file_path = $external_image;
2456 }
2457 }
2458
2459 $file_info = pathinfo($file_path);
2460
2461 // there is a thumbnail already
2462 if ( file_exists(trailingslashit($this->uploads_dir['basedir']) . $p->id . '-' . $source . '-' . $dim[0] . 'x' . $dim[1] . '.' . $file_info['extension']) ) {
2463 return $this->_render_image( trailingslashit($this->uploads_dir['baseurl']) . $p->id . '-' . $source . '-' . $dim[0] . 'x' . $dim[1] . '.' . $file_info['extension'], $dim, 'wpp-thumbnail wpp_cached_thumb wpp_' . $source, $title );
2464 }
2465
2466 return $this->__image_resize($p, $file_path, $dim, $crop, $source);
2467
2468 } // end __get_img
2469
2470 /**
2471 * Resizes image.
2472 *
2473 * @since 3.0.0
2474 * @param object p Post object
2475 * @param string path Image path
2476 * @param array dimension Image's width and height
2477 * @param string source Image source
2478 * @return string
2479 */
2480 private function __image_resize($p, $path, $dimension, $crop, $source) {
2481
2482 $image = wp_get_image_editor($path);
2483
2484 // valid image, create thumbnail
2485 if ( !is_wp_error($image) ) {
2486 $file_info = pathinfo($path);
2487
2488 $image->resize($dimension[0], $dimension[1], $crop);
2489 $new_img = $image->save( trailingslashit($this->uploads_dir['basedir']) . $p->id . '-' . $source . '-' . $dimension[0] . 'x' . $dimension[1] . '.' . $file_info['extension'] );
2490
2491 if ( is_wp_error($new_img) ) {
2492 return $this->_render_image($this->default_thumbnail, $dimension, 'wpp-thumbnail wpp_imgeditor_error wpp_' . $source, '', $new_img->get_error_message());
2493 }
2494
2495 return $this->_render_image( trailingslashit($this->uploads_dir['baseurl']) . $new_img['file'], $dimension, 'wpp-thumbnail wpp_imgeditor_thumb wpp_' . $source, '');
2496 }
2497
2498 // ELSE
2499 // image file path is invalid
2500 return $this->_render_image($this->default_thumbnail, $dimension, 'wpp-thumbnail wpp_imgeditor_error wpp_' . $source, '', $image->get_error_message());
2501
2502 } // end __image_resize
2503
2504 /**
2505 * Get image absolute path / URL.
2506 *
2507 * @since 3.0.0
2508 * @param int id Post ID
2509 * @param string source Image source
2510 * @return array
2511 */
2512 private function __get_image_file_paths($id, $source) {
2513
2514 $file_path = '';
2515
2516 // get thumbnail path from the Featured Image
2517 if ($source == "featured") {
2518
2519 // thumb attachment ID
2520 $thumbnail_id = get_post_thumbnail_id($id);
2521
2522 if ($thumbnail_id) {
2523 // image path
2524 return get_attached_file($thumbnail_id);
2525 }
2526
2527 }
2528 // get thumbnail path from post content
2529 elseif ($source == "first_image") {
2530
2531 /** @var wpdb $wpdb */
2532 global $wpdb;
2533
2534 if ( $content = $wpdb->get_var( "SELECT post_content FROM {$wpdb->posts} WHERE ID = {$id};" ) ) {
2535
2536 // at least one image has been found
2537 if ( preg_match( '/<img[^>]+>/i', $content, $img ) ) {
2538
2539 // get img src attribute from the first image found
2540 preg_match( '/(src)="([^"]*)"/i', $img[0], $src_attr );
2541
2542 if ( isset($src_attr[2]) && !empty($src_attr[2]) ) {
2543
2544 // image from Media Library
2545 if ( $attachment_id = $this->__get_attachment_id( $src_attr[2] ) ) {
2546
2547 $file_path = get_attached_file($attachment_id);
2548
2549 // There's a file path, so return it
2550 if ( !empty($file_path) ) {
2551 return $file_path;
2552 }
2553
2554 } // external image?
2555 else {
2556 return $this->__fetch_external_image($id, $src_attr[2]);
2557 }
2558
2559 }
2560
2561 }
2562
2563 }
2564
2565 }
2566
2567 return false;
2568
2569 } // end __get_image_file_paths
2570
2571 /**
2572 * Render image tag.
2573 *
2574 * @since 3.0.0
2575 * @param string src Image URL
2576 * @param array dimension Image's width and height
2577 * @param string class CSS class
2578 * @param string title Image's title/alt attribute
2579 * @param string error Error, if the image could not be created
2580 * @return string
2581 */
2582 protected function _render_image($src, $dimension, $class, $title = "", $error = null) {
2583
2584 $msg = '';
2585
2586 if ($error) {
2587 $msg = '<!-- ' . $error . ' --> ';
2588 }
2589
2590 if ( is_ssl() ) {
2591 $src = str_ireplace( "http://", "https://", $src );
2592 }
2593
2594 return apply_filters( 'wpp_render_image', $msg .
2595 '<img src="' . $src . '" ' . ( false == $this->user_settings['tools']['thumbnail']['responsive'] ? 'width=' . $dimension[0] . ' height=' . $dimension[1] : '' ) . ' title="' . esc_attr($title) . '" alt="' . esc_attr($title) . '" class="' . $class . '" />' );
2596
2597 } // _render_image
2598
2599 /**
2600 * Get the Attachment ID for a given image URL.
2601 *
2602 * @since 3.0.0
2603 * @author Frankie Jarrett
2604 * @link http://frankiejarrett.com/get-an-attachment-id-by-url-in-wordpress/
2605 * @param string url
2606 * @return bool|int
2607 */
2608 private function __get_attachment_id($url) {
2609
2610 // Split the $url into two parts with the wp-content directory as the separator.
2611 $parse_url = explode( parse_url( WP_CONTENT_URL, PHP_URL_PATH ), $url );
2612
2613 // Get the host of the current site and the host of the $url, ignoring www.
2614 $this_host = str_ireplace( 'www.', '', parse_url( home_url(), PHP_URL_HOST ) );
2615 $file_host = str_ireplace( 'www.', '', parse_url( $url, PHP_URL_HOST ) );
2616
2617 // Return nothing if there aren't any $url parts or if the current host and $url host do not match.
2618 if ( ! isset( $parse_url[1] ) || empty( $parse_url[1] ) || ( $this_host != $file_host ) ) {
2619 return false;
2620 }
2621
2622 // Now we're going to quickly search the DB for any attachment GUID with a partial path match.
2623 // Example: /uploads/2013/05/test-image.jpg
2624 global $wpdb;
2625
2626 if ( !$attachment = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM {$wpdb->prefix}posts WHERE guid RLIKE %s;", $parse_url[1] ) ) ) {
2627 // Maybe it's a resized image, so try to get the full one
2628 $parse_url[1] = preg_replace( '/-[0-9]{1,4}x[0-9]{1,4}\.(jpg|jpeg|png|gif|bmp)$/i', '.$1', $parse_url[1] );
2629 $attachment = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM {$wpdb->prefix}posts WHERE guid RLIKE %s;", $parse_url[1] ) );
2630 }
2631
2632 // Returns null if no attachment is found.
2633 return isset($attachment[0]) ? $attachment[0] : NULL;
2634
2635 } // __get_attachment_id
2636
2637 /**
2638 * Fetchs external images.
2639 *
2640 * @since 2.3.3
2641 * @param string url
2642 * @return bool|int
2643 */
2644 private function __fetch_external_image($id, $url){
2645
2646 $full_image_path = trailingslashit( $this->uploads_dir['basedir'] ) . "{$id}_". sanitize_file_name( rawurldecode(wp_basename( $url )) );
2647
2648 // if the file exists already, return URL and path
2649 if ( file_exists($full_image_path) )
2650 return $full_image_path;
2651
2652 $accepted_status_codes = array( 200, 301, 302 );
2653 $response = wp_remote_head( $url, array( 'timeout' => 5, 'sslverify' => false ) );
2654
2655 if ( !is_wp_error($response) && in_array(wp_remote_retrieve_response_code($response), $accepted_status_codes) ) {
2656
2657 require_once( ABSPATH . 'wp-admin/includes/file.php' );
2658 $url = str_replace( 'https://', 'http://', $url );
2659 $tmp = download_url( $url );
2660
2661 if ( !is_wp_error( $tmp ) ) {
2662
2663 if ( function_exists('exif_imagetype') ) {
2664 $image_type = exif_imagetype( $tmp );
2665 } else {
2666 $image_type = getimagesize( $tmp );
2667 $image_type = ( isset($image_type[2]) ) ? $image_type[2] : NULL;
2668 }
2669
2670 if ( in_array($image_type, array(IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG)) ) {
2671
2672 // move file to Uploads
2673 if ( @rename($tmp, $full_image_path) ) {
2674 // borrowed from WP - set correct file permissions
2675 $stat = stat( dirname( $full_image_path ));
2676 $perms = $stat['mode'] & 0000644;
2677 @chmod( $full_image_path, $perms );
2678
2679 return $full_image_path;
2680 }
2681
2682 }
2683
2684 // remove temp file
2685 @unlink( $tmp );
2686
2687 }
2688
2689 }
2690
2691 return false;
2692
2693 } // end __fetch_external_image
2694
2695 /**
2696 * Builds post's excerpt
2697 *
2698 * @since 1.4.6
2699 * @global object wpdb
2700 * @param int post ID
2701 * @param array widget instance
2702 * @return string
2703 */
2704 protected function _get_summary($id, $instance){
2705
2706 if ( !$this->__is_numeric($id) )
2707 return false;
2708
2709 global $wpdb;
2710
2711 $excerpt = "";
2712
2713 // WPML support, get excerpt for current language
2714 if ( defined('ICL_LANGUAGE_CODE') && function_exists('icl_object_id') ) {
2715 $current_id = icl_object_id( $id, get_post_type( $id ), true, ICL_LANGUAGE_CODE );
2716
2717 $the_post = get_post( $current_id );
2718 $excerpt = ( empty($the_post->post_excerpt) )
2719 ? $the_post->post_content
2720 : $the_post->post_excerpt;
2721 } // Use ol' plain excerpt
2722 else {
2723 $the_post = get_post( $id );
2724 $excerpt = ( empty($the_post->post_excerpt) )
2725 ? $the_post->post_content
2726 : $the_post->post_excerpt;
2727
2728 // RRR added call to the_content filters, allows qTranslate to hook in.
2729 if ( $this->qTrans )
2730 $excerpt = qtrans_useCurrentLanguageIfNotFoundUseDefaultLanguage( $excerpt );
2731 }
2732
2733 // remove caption tags
2734 $excerpt = preg_replace( "/\[caption.*\[\/caption\]/", "", $excerpt );
2735
2736 // remove Flash objects
2737 $excerpt = preg_replace( "/<object[0-9 a-z_?*=\":\-\/\.#\,\\n\\r\\t]+/smi", "", $excerpt );
2738
2739 // remove Iframes
2740 $excerpt = preg_replace( "/<iframe.*?\/iframe>/i", "", $excerpt);
2741
2742 // remove WP shortcodes
2743 $excerpt = strip_shortcodes( $excerpt );
2744
2745 // remove HTML tags if requested
2746 if ( $instance['post-excerpt']['keep_format'] ) {
2747 $excerpt = strip_tags($excerpt, '<a><b><i><em><strong>');
2748 } else {
2749 $excerpt = strip_tags($excerpt);
2750 // remove URLs, too
2751 $excerpt = preg_replace( '_^(?:(?:https?|ftp)://)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\x{00a1}-\x{ffff}0-9]+-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.(?:[a-z\x{00a1}-\x{ffff}0-9]+-?)*[a-z\x{00a1}-\x{ffff}0-9]+)*(?:\.(?:[a-z\x{00a1}-\x{ffff}]{2,})))(?::\d{2,5})?(?:/[^\s]*)?$_iuS', '', $excerpt );
2752 }
2753
2754 // Fix RSS CDATA tags
2755 $excerpt = str_replace( ']]>', ']]&gt;', $excerpt );
2756
2757 // do we still have something to display?
2758 if ( !empty($excerpt) ) {
2759
2760 // truncate excerpt
2761 if ( isset($instance['post-excerpt']['words']) && $instance['post-excerpt']['words'] ) { // by words
2762
2763 $words = explode(" ", $excerpt, $instance['post-excerpt']['length'] + 1);
2764
2765 if ( count($words) > $instance['post-excerpt']['length'] ) {
2766 array_pop($words);
2767 $excerpt = implode(" ", $words) . "...";
2768 }
2769
2770 } else { // by characters
2771
2772 if ( strlen($excerpt) > $instance['post-excerpt']['length'] ) {
2773 $excerpt = mb_substr( $excerpt, 0, $instance['post-excerpt']['length'], $this->charset ) . "...";
2774 }
2775
2776 }
2777
2778 }
2779
2780 // Balance tags, if needed
2781 if ( $instance['post-excerpt']['keep_format'] ) {
2782 $excerpt = force_balance_tags($excerpt);
2783 }
2784
2785 return $excerpt;
2786
2787 } // _get_summary
2788
2789 /**
2790 * WPP shortcode handler
2791 * Since 2.0.0
2792 */
2793 public function shortcode($atts = null, $content = null) {
2794 /**
2795 * @var String $header
2796 * @var Int $limit
2797 * @var String $range
2798 * @var Bool $freshness
2799 * @var String $order_by
2800 * @var String $post_type
2801 * @var String $pid
2802 * @var String $cat
2803 * @var String $author
2804 * @var Int $title_length
2805 * @var Int $title_by_words
2806 * @var Int $excerpt_length
2807 * @var Int $excerpt_format
2808 * @var Int $excerpt_by_words
2809 * @var Int $thumbnail_width
2810 * @var Int $thumbnail_height
2811 * @var Bool $rating
2812 * @var Bool $stats_comments
2813 * @var Bool $stats_views
2814 * @var Bool $stats_author
2815 * @var Bool $stats_date
2816 * @var String $stats_date_format
2817 * @var Bool $stats_category
2818 * @var String $wpp_start
2819 * @var String $wpp_end
2820 * @var String $header_start
2821 * @var String $header_end
2822 * @var String $post_html
2823 * @var Bool $php
2824 */
2825 extract( shortcode_atts( array(
2826 'header' => '',
2827 'limit' => 10,
2828 'range' => 'daily',
2829 'freshness' => false,
2830 'order_by' => 'views',
2831 'post_type' => 'post,page',
2832 'pid' => '',
2833 'cat' => '',
2834 'author' => '',
2835 'title_length' => 0,
2836 'title_by_words' => 0,
2837 'excerpt_length' => 0,
2838 'excerpt_format' => 0,
2839 'excerpt_by_words' => 0,
2840 'thumbnail_width' => 0,
2841 'thumbnail_height' => 0,
2842 'rating' => false,
2843 'stats_comments' => false,
2844 'stats_views' => true,
2845 'stats_author' => false,
2846 'stats_date' => false,
2847 'stats_date_format' => 'F j, Y',
2848 'stats_category' => false,
2849 'wpp_start' => '<ul class="wpp-list">',
2850 'wpp_end' => '</ul>',
2851 'header_start' => '<h2>',
2852 'header_end' => '</h2>',
2853 'post_html' => '',
2854 'php' => false
2855 ),$atts));
2856
2857 // possible values for "Time Range" and "Order by"
2858 $range_values = array("yesterday", "daily", "weekly", "monthly", "all");
2859 $order_by_values = array("comments", "views", "avg");
2860
2861 $shortcode_ops = array(
2862 'title' => strip_tags($header),
2863 'limit' => (!empty($limit) && $this->__is_numeric($limit) && $limit > 0) ? $limit : 10,
2864 'range' => (in_array($range, $range_values)) ? $range : 'daily',
2865 'freshness' => empty($freshness) ? false : $freshness,
2866 'order_by' => (in_array($order_by, $order_by_values)) ? $order_by : 'views',
2867 'post_type' => empty($post_type) ? 'post,page' : $post_type,
2868 'pid' => preg_replace('|[^0-9,]|', '', $pid),
2869 'cat' => preg_replace('|[^0-9,-]|', '', $cat),
2870 'author' => preg_replace('|[^0-9,]|', '', $author),
2871 'shorten_title' => array(
2872 'active' => (!empty($title_length) && $this->__is_numeric($title_length) && $title_length > 0),
2873 'length' => (!empty($title_length) && $this->__is_numeric($title_length)) ? $title_length : 0,
2874 'words' => (!empty($title_by_words) && $this->__is_numeric($title_by_words) && $title_by_words > 0),
2875 ),
2876 'post-excerpt' => array(
2877 'active' => (!empty($excerpt_length) && $this->__is_numeric($excerpt_length) && ($excerpt_length > 0)),
2878 'length' => (!empty($excerpt_length) && $this->__is_numeric($excerpt_length)) ? $excerpt_length : 0,
2879 'keep_format' => (!empty($excerpt_format) && $this->__is_numeric($excerpt_format) && ($excerpt_format > 0)),
2880 'words' => (!empty($excerpt_by_words) && $this->__is_numeric($excerpt_by_words) && $excerpt_by_words > 0),
2881 ),
2882 'thumbnail' => array(
2883 'active' => (!empty($thumbnail_width) && $this->__is_numeric($thumbnail_width) && $thumbnail_width > 0),
2884 'width' => (!empty($thumbnail_width) && $this->__is_numeric($thumbnail_width) && $thumbnail_width > 0) ? $thumbnail_width : 0,
2885 'height' => (!empty($thumbnail_height) && $this->__is_numeric($thumbnail_height) && $thumbnail_height > 0) ? $thumbnail_height : 0,
2886 ),
2887 'rating' => empty($rating) ? false : $rating,
2888 'stats_tag' => array(
2889 'comment_count' => empty($stats_comments) ? false : $stats_comments,
2890 'views' => empty($stats_views) ? false : $stats_views,
2891 'author' => empty($stats_author) ? false : $stats_author,
2892 'date' => array(
2893 'active' => empty($stats_date) ? false : $stats_date,
2894 'format' => empty($stats_date_format) ? 'F j, Y' : $stats_date_format
2895 ),
2896 'category' => empty($stats_category) ? false : $stats_category,
2897 ),
2898 'markup' => array(
2899 'custom_html' => true,
2900 'wpp-start' => empty($wpp_start) ? '<ul class="wpp-list">' : $wpp_start,
2901 'wpp-end' => empty($wpp_end) ? '</ul>' : $wpp_end,
2902 'title-start' => empty($header_start) ? '' : $header_start,
2903 'title-end' => empty($header_end) ? '' : $header_end,
2904 'post-html' => empty($post_html) ? '<li>{thumb} {title} {stats}</li>' : $post_html
2905 )
2906 );
2907
2908 $shortcode_content = "\n". "<!-- WordPress Popular Posts Plugin v". $this->version ." [" . ( $php ? "PHP" : "SC" ) . "] [".$shortcode_ops['range']."] [".$shortcode_ops['order_by']."] [custom]" . ( !empty($shortcode_ops['pid']) ? " [PID]" : "" ) . ( !empty($shortcode_ops['cat']) ? " [CAT]" : "" ) . ( !empty($shortcode_ops['author']) ? " [UID]" : "" ) . " -->"."\n";
2909
2910 // is there a title defined by user?
2911 if (!empty($header) && !empty($header_start) && !empty($header_end)) {
2912 $shortcode_content .= htmlspecialchars_decode($header_start, ENT_QUOTES) . apply_filters('widget_title', $header) . htmlspecialchars_decode($header_end, ENT_QUOTES);
2913 }
2914
2915 // print popular posts list
2916 $shortcode_content .= $this->__get_popular_posts($shortcode_ops);
2917 $shortcode_content .= "\n". "<!-- End WordPress Popular Posts Plugin v". $this->version ." -->"."\n";
2918
2919 return $shortcode_content;
2920
2921 } // end shortcode
2922
2923 /**
2924 * Parses content tags
2925 *
2926 * @since 1.4.6
2927 * @param string HTML string with content tags
2928 * @param array Post data
2929 * @param bool Used to display post rating (if functionality is available)
2930 * @return string
2931 */
2932 private function __format_content($string, $data = array(), $rating) {
2933
2934 if (empty($string) || (empty($data) || !is_array($data)))
2935 return false;
2936
2937 $params = array();
2938 $pattern = '/\{(excerpt|summary|stats|title|image|thumb|thumb_img|rating|score|url|text_title|author|category|views|comments|date)\}/i';
2939 preg_match_all($pattern, $string, $matches);
2940
2941 array_map('strtolower', $matches[0]);
2942
2943 if ( in_array("{title}", $matches[0]) ) {
2944 $string = str_replace( "{title}", $data['title'], $string );
2945 }
2946
2947 if ( in_array("{stats}", $matches[0]) ) {
2948 $string = str_replace( "{stats}", $data['stats'], $string );
2949 }
2950
2951 if ( in_array("{excerpt}", $matches[0]) || in_array("{summary}", $matches[0]) ) {
2952 $string = str_replace( array("{excerpt}", "{summary}"), $data['summary'], $string );
2953 }
2954
2955 if ( in_array("{image}", $matches[0]) || in_array("{thumb}", $matches[0]) ) {
2956 $string = str_replace( array("{image}", "{thumb}"), $data['img'], $string );
2957 }
2958
2959 if ( in_array("{thumb_img}", $matches[0]) ) {
2960 $string = str_replace( "{thumb_img}", $data['img_no_link'], $string );
2961 }
2962
2963 // WP-PostRatings check
2964 if ( $rating ) {
2965 if ( function_exists('the_ratings_results') && in_array("{rating}", $matches[0]) ) {
2966 $string = str_replace( "{rating}", the_ratings_results($data['id']), $string );
2967 }
2968
2969 if ( function_exists('expand_ratings_template') && in_array("{score}", $matches[0]) ) {
2970 $string = str_replace( "{score}", expand_ratings_template('%RATINGS_SCORE%', $data['id']), $string);
2971 // removing the redundant plus sign
2972 $string = str_replace('+', '', $string);
2973 }
2974 }
2975
2976 if ( in_array("{url}", $matches[0]) ) {
2977 $string = str_replace( "{url}", $data['url'], $string );
2978 }
2979
2980 if ( in_array("{text_title}", $matches[0]) ) {
2981 $string = str_replace( "{text_title}", $data['text_title'], $string );
2982 }
2983
2984 if ( in_array("{author}", $matches[0]) ) {
2985 $string = str_replace( "{author}", $data['author'], $string );
2986 }
2987
2988 if ( in_array("{category}", $matches[0]) ) {
2989 $string = str_replace( "{category}", $data['category'], $string );
2990 }
2991
2992 if ( in_array("{views}", $matches[0]) ) {
2993 $string = str_replace( "{views}", $data['views'], $string );
2994 }
2995
2996 if ( in_array("{comments}", $matches[0]) ) {
2997 $string = str_replace( "{comments}", $data['comments'], $string );
2998 }
2999
3000 if ( in_array("{date}", $matches[0]) ) {
3001 $string = str_replace( "{date}", $data['date'], $string );
3002 }
3003
3004 return $string;
3005
3006 } // end __format_content
3007
3008 /**
3009 * Returns HTML list via AJAX
3010 *
3011 * @since 2.3.3
3012 * @return string
3013 */
3014 public function get_popular( ) {
3015
3016 if ( $this->__is_numeric($_GET['id']) && ($_GET['id'] != '') ) {
3017 $id = $_GET['id'];
3018 } else {
3019 die("Invalid ID");
3020 }
3021
3022 $widget_instances = $this->get_settings();
3023
3024 if ( isset($widget_instances[$id]) ) {
3025
3026 echo $this->__get_popular_posts( $widget_instances[$id] );
3027
3028 } else {
3029
3030 echo "Invalid Widget ID";
3031 }
3032
3033 exit();
3034
3035 } // end get_popular
3036
3037 /*--------------------------------------------------*/
3038 /* Helper functions
3039 /*--------------------------------------------------*/
3040
3041 /**
3042 * Gets list of available thumbnails sizes
3043 *
3044 * @since 3.2.0
3045 * @link http://codex.wordpress.org/Function_Reference/get_intermediate_image_sizes
3046 * @param string $size
3047 * @return array|bool
3048 */
3049 private function __get_image_sizes( $size = '' ) {
3050
3051 global $_wp_additional_image_sizes;
3052
3053 $sizes = array();
3054 $get_intermediate_image_sizes = get_intermediate_image_sizes();
3055
3056 // Create the full array with sizes and crop info
3057 foreach( $get_intermediate_image_sizes as $_size ) {
3058
3059 if ( in_array( $_size, array( 'thumbnail', 'medium', 'large' ) ) ) {
3060
3061 $sizes[ $_size ]['width'] = get_option( $_size . '_size_w' );
3062 $sizes[ $_size ]['height'] = get_option( $_size . '_size_h' );
3063 $sizes[ $_size ]['crop'] = (bool) get_option( $_size . '_crop' );
3064
3065 } elseif ( isset( $_wp_additional_image_sizes[ $_size ] ) ) {
3066
3067 $sizes[ $_size ] = array(
3068 'width' => $_wp_additional_image_sizes[ $_size ]['width'],
3069 'height' => $_wp_additional_image_sizes[ $_size ]['height'],
3070 'crop' => $_wp_additional_image_sizes[ $_size ]['crop']
3071 );
3072
3073 }
3074
3075 }
3076
3077 // Get only 1 size if found
3078 if ( $size ) {
3079
3080 if( isset( $sizes[ $size ] ) ) {
3081 return $sizes[ $size ];
3082 } else {
3083 return false;
3084 }
3085
3086 }
3087
3088 return $sizes;
3089 }
3090
3091 /**
3092 * Gets post/page ID if current page is singular
3093 *
3094 * @since 3.1.2
3095 */
3096 public function is_single() {
3097 if ( (is_single() || is_page()) && !is_front_page() && !is_preview() && !is_trackback() && !is_feed() && !is_robots() ) {
3098 global $post;
3099 $this->current_post_id = ( is_object($post) ) ? $post->ID : 0;
3100 } else {
3101 $this->current_post_id = 0;
3102 }
3103 } // end is_single
3104
3105 /**
3106 * Checks for valid number
3107 *
3108 * @since 2.1.6
3109 * @param int number
3110 * @return bool
3111 */
3112 private function __is_numeric($number){
3113 return !empty($number) && is_numeric($number) && (intval($number) == floatval($number));
3114 }
3115
3116 /**
3117 * Returns server datetime
3118 *
3119 * @since 2.1.6
3120 * @return string
3121 */
3122 private function __curdate() {
3123 return gmdate( 'Y-m-d', ( time() + ( get_site_option( 'gmt_offset' ) * 3600 ) ));
3124 } // end __curdate
3125
3126 /**
3127 * Returns mysql datetime
3128 *
3129 * @since 2.1.6
3130 * @return string
3131 */
3132 private function __now() {
3133 return current_time('mysql');
3134 } // end __now
3135
3136 /**
3137 * Returns time
3138 *
3139 * @since 2.3.0
3140 * @return string
3141 */
3142 private function __microtime_float() {
3143
3144 list( $msec, $sec ) = explode( ' ', microtime() );
3145
3146 $microtime = (float) $msec + (float) $sec;
3147 return $microtime;
3148
3149 } // end __microtime_float
3150
3151 /**
3152 * Merges two associative arrays recursively
3153 *
3154 * @since 2.3.4
3155 * @link http://www.php.net/manual/en/function.array-merge-recursive.php#92195
3156 * @param array array1
3157 * @param array array2
3158 * @return array
3159 */
3160 private function __merge_array_r( array &$array1, array &$array2 ) {
3161
3162 $merged = $array1;
3163
3164 foreach ( $array2 as $key => &$value ) {
3165
3166 if ( is_array( $value ) && isset ( $merged[$key] ) && is_array( $merged[$key] ) ) {
3167 $merged[$key] = $this->__merge_array_r( $merged[$key], $value );
3168 } else {
3169 $merged[$key] = $value;
3170 }
3171 }
3172
3173 return $merged;
3174
3175 } // end __merge_array_r
3176
3177 /**
3178 * Checks if visitor is human or bot.
3179 *
3180 * @since 3.0.0
3181 * @return bool FALSE if human, TRUE if bot
3182 */
3183 private function __is_bot() {
3184
3185 if ( !isset($_SERVER['HTTP_USER_AGENT']) || empty($_SERVER['HTTP_USER_AGENT']) )
3186 return true; // No UA? Bot (probably)
3187
3188 $user_agent = strtolower($_SERVER['HTTP_USER_AGENT']);
3189
3190 foreach ( $this->botlist as $bot ) {
3191 if ( false !== strpos($user_agent, $bot) ) {
3192 return true; // Bot
3193 }
3194 }
3195
3196 return false; // Human, I guess...
3197
3198 } // end __is_bot
3199
3200 /**
3201 * Debug function.
3202 *
3203 * @since 3.0.0
3204 * @param mixed $v variable to display with var_dump()
3205 * @param mixed $v,... unlimited optional number of variables to display with var_dump()
3206 */
3207 private function __debug($v) {
3208
3209 if ( !defined('WPP_DEBUG') || !WPP_DEBUG )
3210 return;
3211
3212 foreach (func_get_args() as $arg) {
3213
3214 print "<pre>";
3215 var_dump($arg);
3216 print "</pre>";
3217
3218 }
3219
3220 } // end __debug
3221
3222 } // end class
3223
3224 }
3225
3226 /**
3227 * WordPress Popular Posts template tags for use in themes.
3228 */
3229
3230 /**
3231 * Template tag - gets views count.
3232 *
3233 * @since 2.0.3
3234 * @global object wpdb
3235 * @param int id
3236 * @param string range
3237 * @param bool number_format
3238 * @return string
3239 */
3240 function wpp_get_views($id = NULL, $range = NULL, $number_format = true) {
3241
3242 // have we got an id?
3243 if ( empty($id) || is_null($id) || !is_numeric($id) ) {
3244 return "-1";
3245 } else {
3246 global $wpdb;
3247
3248 $table_name = $wpdb->prefix . "popularposts";
3249
3250 if ( !$range || 'all' == $range ) {
3251 $query = "SELECT pageviews FROM {$table_name}data WHERE postid = '{$id}'";
3252 } else {
3253 $interval = "";
3254
3255 switch( $range ){
3256 case "yesterday":
3257 $interval = "1 DAY";
3258 break;
3259
3260 case "daily":
3261 $interval = "1 DAY";
3262 break;
3263
3264 case "weekly":
3265 $interval = "1 WEEK";
3266 break;
3267
3268 case "monthly":
3269 $interval = "1 MONTH";
3270 break;
3271
3272 default:
3273 $interval = "1 DAY";
3274 break;
3275 }
3276
3277 $now = current_time('mysql');
3278
3279 $query = "SELECT SUM(pageviews) FROM {$table_name}summary WHERE postid = '{$id}' AND last_viewed > DATE_SUB('{$now}', INTERVAL {$interval}) LIMIT 1;";
3280 }
3281
3282 $result = $wpdb->get_var($query);
3283
3284 if ( !$result ) {
3285 return "0";
3286 }
3287
3288 return ($number_format) ? number_format_i18n( intval($result) ) : $result;
3289 }
3290
3291 }
3292
3293 /**
3294 * Template tag - gets popular posts.
3295 *
3296 * @since 2.0.3
3297 * @param mixed args
3298 */
3299 function wpp_get_mostpopular($args = NULL) {
3300
3301 $shortcode = '[wpp';
3302
3303 if ( is_null( $args ) ) {
3304 $shortcode .= ']';
3305 } else {
3306 if( is_array( $args ) ){
3307 $atts = '';
3308 foreach( $args as $key => $arg ){
3309 $atts .= ' ' . $key . '="' . htmlspecialchars($arg, ENT_QUOTES, $encoding = ini_get("default_charset"), false) . '"';
3310 }
3311 } else {
3312 $atts = trim( str_replace( "&", " ", $args ) );
3313 }
3314
3315 $shortcode .= ' ' . $atts . ' php=true]';
3316 }
3317
3318 echo do_shortcode( $shortcode );
3319
3320 }
3321
3322 /**
3323 * Template tag - gets popular posts. Deprecated in 2.0.3, use wpp_get_mostpopular instead.
3324 *
3325 * @since 1.0
3326 * @param mixed args
3327 */
3328 function get_mostpopular($args = NULL) {
3329 trigger_error( 'The get_mostpopular() template tag has been deprecated since 2.0.3. Please use wpp_get_mostpopular() instead.', E_USER_WARNING );
3330 }
3331