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