From 09cb2a201844905362533ada8339ccc194d0dda2 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 17 Dec 2020 13:34:39 +0000 Subject: [PATCH] jetpack-post-views --- .../jetpack-post-views/jetpack-post-views.php | 1054 +++++++++++++++++ .../plugins/jetpack-post-views/readme.txt | 151 +++ .../plugins/jetpack-post-views/uninstall.php | 42 + 3 files changed, 1247 insertions(+) create mode 100644 wp-content/plugins/jetpack-post-views/jetpack-post-views.php create mode 100644 wp-content/plugins/jetpack-post-views/readme.txt create mode 100644 wp-content/plugins/jetpack-post-views/uninstall.php diff --git a/wp-content/plugins/jetpack-post-views/jetpack-post-views.php b/wp-content/plugins/jetpack-post-views/jetpack-post-views.php new file mode 100644 index 000000000..bfe957b44 --- /dev/null +++ b/wp-content/plugins/jetpack-post-views/jetpack-post-views.php @@ -0,0 +1,1054 @@ +NOTE: If the plugin does not work, visit the Settings page to enter a WordPress API Key. + * Author: Steven Lambert + * Version: 1.1.0 + * Author URI: http://sklambert.com + * License: GPL2+ + */ + +/* Copyright 2013 Steven Lambert (email : steven@sklambert.com) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License, version 2, as + published by the Free Software Foundation. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// Define plugin version +if (!defined('JETPACK_POST_VIEWS_VERSION_KEY')) + define('JETPACK_POST_VIEWS_VERSION_KEY', 'jetpack-post-views_version'); + +if (!defined('JETPACK_POST_VIEWS_VERSION_NUM')) + define('JETPACK_POST_VIEWS_VERSION_NUM', '1.1.0'); + +add_option(JETPACK_POST_VIEWS_VERSION_KEY, JETPACK_POST_VIEWS_VERSION_NUM); + +/** + * Jetpack Post Views + * + * Queries the Jetpack API and adds a custom post_meta 'jetpack-post-views' that holds the total views of a + * post as listed on Jetpack. Adds a widget to display the top posts for a site. + */ +class Jetpack_Post_Views extends WP_Widget { + + // Private variables + var $version = '1.1.0'; + var $apiUrl = 'http://stats.wordpress.com/csv.php'; + var $apiArgs = array( + 'table' => 'postviews', + 'days' => -1, + 'limit' => -1, + 'summarize' => 1, + 'format' => 'json' + ); + var $interval = array( + 'Unlimited' => -1, + 'Day' => 1, + 'Week' => 7, + 'Month' => 30, + 'Year' => 365 + ); + + // Update test data + var $updateMessages = array(); + var $DEBUG = false; + + /* CONSTRUCTOR */ + function __construct() { + + // Admin hooks + add_action( 'init', array( &$this, 'load_language_files' ) ); + add_action( 'admin_init', array( &$this, 'register_setting' ) ); + add_action( 'admin_menu', array( &$this, 'register_settings_page' ) ); + add_action( 'manage_posts_custom_column', array( &$this, 'add_post_views_column_content' ), 10, 2); + add_filter( 'plugin_action_links', array( &$this, 'settings_link' ), 10, 2 ); + add_filter( 'manage_posts_columns', array( &$this, 'add_post_views_column' ) ); + add_filter( 'manage_edit-post_sortable_columns', array( &$this, 'post_views_column_sort') ); + add_filter( 'request', array( &$this, 'post_views_column_orderby' ) ); + + // Scheduled hooks + add_action( 'jetpack_post_views_scheduled_update', array( &$this, 'get_post_views' ) ); + + // Post hooks + add_action( 'publish_post', array( &$this, 'add_jetpack_meta' ) ); + + // Query the database for the blog_id + global $wpdb; + $options_table = $wpdb->base_prefix."options"; + $stats_options = $wpdb->get_var( "SELECT option_value + FROM $options_table + WHERE option_name = 'stats_options'" ); + $stats = unserialize($stats_options); + + // Set blog_id + if ( $stats ) { + $this->blog_id = $stats['blog_id']; + } + else { // Jetpack stats unavailable + + // Try another possibility to get the blog_id + $jetpack_options = $wpdb->get_var( "SELECT option_value + FROM $options_table + WHERE option_name = 'jetpack_options'" ); + $jetpack = unserialize($jetpack_options); + + if ( $jetpack ) { + $this->blog_id = $jetpack['id']; + } + else { // Jetpack stats really unavailable + $this->blog_id = -1; + } + } + + // Get the api key if it already exists + $api_key = get_option( 'jetpack_post_views_wp_api_key' ) != "" ? get_option( 'jetpack_post_views_wp_api_key' ) : ""; + + // Default settings + $this->defaultsettings = (array) apply_filters( 'jetpack_post_views_defaultsettings', array( + 'version' => get_option(JETPACK_POST_VIEWS_VERSION_KEY), + 'api_key' => $api_key, + 'blog_id' => $this->blog_id, + 'blog_uri' => home_url( '/' ), + 'changed' => 0, + 'connect_blog_id' => 0, + 'connect_blog_uri' => 0, + 'display_total_views' => "", + 'use_stats_get_csv' => "on", + 'use_blog_uri' => "on" + ) ); + + // Create the settings array by merging the user's settings and the defaults + $usersettings = (array) get_option('jetpack_post_views_settings'); + $this->settings = wp_parse_args( $usersettings, $this->defaultsettings ); + + // Controls and options + $widget_ops = array( + 'classname' => 'jetpack-post-views', + 'description' => __( 'Your site\'s most popular posts using Jetpack stats', 'jetpack-post-views') + ); + $control_ops = array( + 'id_base' => 'jetpack-post-views-widget' + ); + + // Set widget information + $this->WP_Widget( 'jetpack-post-views-widget', __( 'Jetpack Post Views Widget', 'jetpack-post-views'), $widget_ops, $control_ops ); + } + + /* ADD LANGUGE FILES */ + function load_language_files() { + load_plugin_textdomain('jetpack-post-views', false, basename( dirname( __FILE__ ) ) . '/languages' ); + } + + /* REGISTER SETTINGS PAGE */ + function register_settings_page() { + add_options_page( __( 'Jetpack Post Views Settings', 'jetpack-post-views' ), __( 'Jetpack Post Views', 'jetpack-post-views' ), 'manage_options', 'jetpack_post_views', array( &$this, 'settings_page' ) ); + } + + /* REGISTER PLUGIN SETTINGS */ + function register_setting() { + register_setting( 'jetpack_post_views_settings', 'jetpack_post_views_settings', array( &$this, 'validate_settings' ) ); + } + + + /* ADD JETPACK POST META ON POST PUBLISH */ + function add_jetpack_meta() { + global $post; + add_post_meta( $post->ID, 'jetpack-post-views', 0, true ); + } + + /* ADD POST VIEWS TO POST ADMIN PAGE */ + function add_post_views_column( $defaults ) { + if ( $this->settings['display_total_views'] ) { + $defaults['post_views'] = __( 'Total Views', 'jetpack-post-views' ); + } + return $defaults; + } + + /* SHOW THE TOTAL NUMBER OF VIEWS FOR A POST */ + function add_post_views_column_content( $column_name, $post_ID ) { + if ($column_name == 'post_views') { + $views = get_post_meta( $post_ID, "jetpack-post-views", true ); + + if ( $views ) { + echo number_format_i18n( $views ).__( ' views', 'jetpack-post-views' ); + } + else { + echo '0 views'; + } + } + } + + /* ALLOW SORTING OF POST VIEW COLUMN */ + function post_views_column_sort( $columns ) { + $columns['post_views'] = 'post_views'; + return $columns; + } + + /* SORT POST VIEW COLUMN BY VIEWS */ + function post_views_column_orderby( $vars ) { + if ( isset( $vars['orderby'] ) && 'post_views' == $vars['orderby'] ) { + $vars = array_merge( $vars, array( + 'meta_key' => 'jetpack-post-views', + 'orderby' => 'meta_value_num' + ) ); + } + return $vars; + } + + /* ADD A "SETTINGS" LINK TO PLUGINS PAGE */ + function settings_link( $links, $file ) { + static $this_plugin; + + if( empty($this_plugin) ) + $this_plugin = plugin_basename(__FILE__); + + if ( $file == $this_plugin ) + $links[] = '' . __( 'Settings', 'jetpack-post-views' ) . ''; + + return $links; + } + + /* VALIDATE SETTING PAGE SETTINGS */ + function validate_settings( $settings ) { + if ( !empty($_POST['jetpack-post-views-defaults']) ) { + $settings = $this->defaultsettings; + $_REQUEST['_wp_http_referer'] = add_query_arg( 'defaults', 'true', $_REQUEST['_wp_http_referer'] ); + } else { + // Hidden fields + $settings['connect_blog_uri'] = strip_tags( $settings['connect_blog_uri'] ); + $settings['connect_blog_id'] = strip_tags( $settings['connect_blog_id'] ); + + // Settings + $settings['api_key'] = ( !empty( $settings['api_key'] ) ) ? strip_tags( $settings['api_key'] ) : ""; + $settings['blog_uri'] = ( !empty( $settings['blog_uri'] ) ) ? strip_tags( $settings['blog_uri'] ) : home_url( '/' ); + $settings['display_total_views'] = ( !empty( $settings['display_total_views'] ) ) ? strip_tags( $settings['display_total_views'] ) : ""; + $settings['use_stats_get_csv'] = ( !empty( $settings['use_stats_get_csv'] ) ) ? strip_tags( $settings['use_stats_get_csv'] ) : ""; + $settings['use_blog_uri'] = ( !empty( $settings['use_blog_uri'] ) ) ? strip_tags( $settings['use_blog_uri'] ) : ""; + + // Flag settings change + if ( $settings['api_key'] != $this->settings['api_key'] || $settings['blog_uri'] != $this->settings['blog_uri'] ) { + $settings['changed'] = 1; + } + } + + return $settings; + } + + /* SETTINGS PAGE */ + function settings_page() { ?> + + + +
+ + +

+ +
+ + + + + + + + + + + + + + + + +
+
+
+
+ +

+ +

stats_get_csv().', 'jetpack-post-views' ); ?>

+ + + + + + + + + + +
" />
+ +

+ +

Stats updated using the first connection available in the order that they are listed.', 'jetpack-post-views' ); ?>

+ + settings['changed'] ) { + $args = $this->apiArgs; + $args['limit'] = 1; + $args['api_key'] = $this->settings['api_key']; + + // Test the URI connection by testing for results from the api + $args['blog_uri'] = $this->settings['blog_uri']; + + $url = add_query_arg( $args, $this->apiUrl ); + $json = wp_remote_get( $url ); + $data = ( is_array( $json ) && !empty( $json['body'] ) ? json_decode( $json['body'], true ) : array()); + + $this->settings['connect_blog_uri'] = ( !empty( $data[0]['postviews'] ) ? 1 : 0 ); + + // Test the Blog ID connection by testing for results from the api + unset( $args['blog_uri'] ); + $args['blog_id'] = $this->settings['blog_id']; + + $url = add_query_arg( $args, $this->apiUrl ); + $json = wp_remote_get( $url ); + $data = ( is_array( $json ) && !empty( $json['body'] ) ? json_decode( $json['body'], true ) : array()); + + $this->settings['connect_blog_id'] = ( !empty( $data[0]['postviews'] ) ? 1 : 0 ); + + $this->get_post_views(); + } + ?> + + + + +
+
+ + + + + + + + + + + + +
stats_get_csv() exists', 'jetpack-post-views' ); ?> +
">
+
+
">
+
+
">
+
+ +

+ ' . "\n"; + } + ?> +

+ +

+

+

+

+ + + +

+ + DEBUG) { + echo "

Plugin options

";
+                    foreach ($this->settings as $key => $value) {
+                        echo "[$key]: $value\n";
+                    }
+                    echo "
"; + + if (function_exists('stats_get_csv')) { + echo "
stats_get_csv function exists
"; + } + else { + echo "
stats_get_csv function does not exist
"; + } + + $this->get_post_views(); + ksort($this->updateMessages); + + echo "

Update Messages by Post ID

";
+                    foreach ($this->updateMessages as $key => $value) {
+                        if ( gettype($value) == "array") {
+                            echo "[$key]: ";
+                            print_r($value);
+                        }
+                        else {
+                            echo "[$key]: $value\n";
+                        }
+                    }
+                    echo "
"; + } + ?> + +
+ +
+ + + + + + false ), 'names' ); + $all_post_types['post'] = 'post'; + + // Filter which post types are displayed + $post_types = array(); + foreach ( $all_post_types as $key => $value ) { + if ( $instance['type_'.$key] ) { + array_push($post_types, $key); + } + } + // Filter results by category + $cat_list = array(); + foreach ( $categories as $key => $value ) { + if ( $instance['category_'.$value->slug] ) { + array_push($cat_list, $value->cat_ID); + } + } + $category = implode(',', $cat_list); + + // Get all posts + $meta_key = 'jetpack-post-views'; + if ( $instance['days'] != $this->interval['Unlimited'] ) { + $key = array_search( $instance['days'], $this->interval ); + $meta_key .= '-'.$key; + } + $args = array( + 'numberposts' => $instance['num_posts'], + 'orderby' => 'meta_value_num', + 'order' => 'DESC', + 'exclude' => $instance['exclude_posts'], + 'meta_key' => $meta_key, + 'post_type' => $post_types, + 'category' => $category + ); + $posts = get_posts( $args ); + + // Print top posts in order + $results = ""; + + echo $results; + + echo $after_widget; + } + + /* UPDATE WIDGET OPTIONS */ + function update( $new_instance, $old_instance ) { + $instance = $old_instance; + + // Check nonce + check_admin_referer('jetpack-post-views-widget-form-submission'); + + $instance['title'] = strip_tags( $new_instance['title'] ); + $instance['show_views'] = strip_tags( $new_instance['show_views'] ); + $instance['days'] = strip_tags( $new_instance['days'] ); + $instance['exclude_custom_types'] = strip_tags( $new_instance['exclude_custom_types'] ); + $instance['exclude_posts'] = strip_tags( $new_instance['exclude_posts'] ); + $instance['display_type'] = strip_tags( $new_instance['display_type'] ); + $instance['display_post_types'] = strip_tags( $new_instance['display_post_types'] ); + + // Get all post types + $post_types = get_post_types( array( '_builtin' => false ), 'names' ); + $post_types['post'] = 'post'; + foreach ( $post_types as $key => $value ) { + if ( $value != 'safecss' ) { + $instance['type_'.$key] = strip_tags( $new_instance['type_'.$key] ); + } + } + + // Get all categories + $categories = get_categories(); + foreach ( $categories as $key => $value ) { + $instance['category_'.$value->slug] = strip_tags( $new_instance['category_'.$value->slug] ); + } + + // Set default number of posts to display if invalid option + $num_posts = intval( strip_tags( $new_instance['num_posts'] ) ); + $instance['num_posts'] = ($num_posts > 0 ? $num_posts : 5); + + return $instance; + } + + /* DISPLAY WIDGET OPTIONS */ + function form( $instance ) { + + // Default widget settings + $defaults = array( + 'title' => __( 'Most Popular Posts', 'jetpack-post-views' ), + 'error' => '', + 'num_posts' => 5, + 'days' => '-1', + 'show_views' => false, + 'display_type' => 'title', + 'exclude_posts' => '', + 'display_post_types' => '' + ); + + // Get all post types + $post_types = get_post_types( array( '_builtin' => false ), 'names' ); + $post_types['post'] = 'post'; + foreach ( $post_types as $key => $value ) { + if ( $value != 'safecss' ) { // I have no idea what this is but it's not a valid post type + $defaults['type_'.$key] = 'on'; + } + } + + // Get all categories + $categories = get_categories(); + foreach ( $categories as $key => $value ) { + $defaults['category_'.$value->slug] = 'on'; + } + + $instance = wp_parse_args( (array) $instance, $defaults ); + + // Set nonce + if ( function_exists('wp_nonce_field') ) { + wp_nonce_field( 'jetpack-post-views-widget-form-submission' ); + echo "\n\n"; + } + + ?> + + + +
+

Display

+ +

+ + +

+ +

+ + +

+ +

+ + +

+ +

+ id="get_field_id( 'show_views' ); ?>" name="get_field_name( 'show_views' ); ?>" /> + +

+ +

+ + +

+
+ +
+

Filter

+ +

+ + +

+ +

+ +
+ $value ) { + if ( $value != 'safecss' ) { + ?> + id="get_field_id( 'type_'.$key ); ?>" name="get_field_name( 'type_'.$key ); ?>" /> + +
+ + +

+ +

+ +
+ $value ) { + ?> + slug], 'on' ); ?> id="get_field_id( 'category_'.$value->slug ); ?>" name="get_field_name( 'category_'.$value->slug ); ?>" /> + +
+ + +

+
+ + settings['use_stats_get_csv'] ) { + + // Get post views for each interval: Unlimited, Day, Week, Month, Year + foreach ($this->interval as $key => $value) { + $args = array( + 'days' => $value, + 'limit' => $random, + 'summarize' => 1 + ); + $post_stats[$key] = stats_get_csv( 'postviews', $args ); + } + + $this->updateMessages[-2] = "Stats being updated using the stats_get_csv function"; + } + // Get the stats using the blog_uri or blog_id + else { + $args = $this->apiArgs; + $args['api_key'] = $this->settings['api_key']; + $args['limit'] = $random; + + // Get the stats using the blog_uri + if ( $this->settings['connect_blog_uri'] && $this->settings['use_blog_uri'] ) { + $args['blog_uri'] = $this->settings['blog_uri']; + $this->updateMessages[-2] = "Stats being updated using blog_uri"; + } + // Get the stats using the blog_id + else if ( $this->settings['connect_blog_id'] ) { + $args['blog_id'] = $this->settings['blog_id']; + $this->updateMessages[-2] = "Stats being updated using blog_id"; + } + else { + return; + } + + // Get post views for each interval: Unlimited, Day, Week, Month, Year + foreach ($this->interval as $key => $value) { + $args['days'] = $value; + $url = add_query_arg( $args, $this->apiUrl ); + $json = wp_remote_get( $url ); + $data = json_decode( $json['body'], true ); + $post_stats[$key] = $data[0]['postviews']; + } + } + + $this->updateMessages[-1] = $post_stats; + global $post; + + // Create an array indexed by interval and then post_id + foreach ( $post_stats as $key => $value ) { + $postdata[$key] = array(); + foreach ( $value as $postinfo ) { + $postdata[$key][$postinfo['post_id']] = strip_tags( $postinfo['views'] ); + } + } + + // Get all posts and update them + $post_types = get_post_types( array( '_builtin' => false ), 'names' ); + $post_types['post'] = 'post'; + + $args = array( + 'numberposts' => -1, + 'post_type' => $post_types, + 'post_status' => 'publish' + ); + $allposts = get_posts( $args ); + foreach( $allposts as $post) { + $message = "'".get_the_title( $post->ID )."' updated with stats:"; + + // Cannot save the interval data as an array in a meta key because WP cannot sort post queries by an array. + // Have to store each interval data in it's own meta key. + // http://wordpress.stackexchange.com/questions/99149/wp-query-meta-query-by-array-key + foreach ( $this->interval as $key => $value ) { + + // Ensure that the $post-ID exists as a key in the array before trying to update post information. + // This prevents the user from pulling data from another website and trying to add it to their own + // posts. + if ( array_key_exists( $post->ID, $postdata[$key] ) ) { + $newViews = intval( $postdata[$key][ $post->ID ] ); + + // Unlimited meta key different as to not break sites that used this previously + if ( $key == 'Unlimited' ) { + $oldViews = get_post_meta( $post->ID, 'jetpack-post-views', true ); + + // Only update posts with new stats. Prevents posts from being updated with '0' views when the API service is down. + if ( $newViews < $oldViews ) { + $newViews = $oldViews; + } + + update_post_meta( $post->ID, 'jetpack-post-views', $newViews ); + } + else { + // Always update non-unlimited intervals since they can fluctuate + update_post_meta( $post->ID, 'jetpack-post-views-'.$key, $newViews ); + } + + $message .= " $key($newViews)"; + } + else { + $message .= " $key(not updated)"; + } + } + + $this->updateMessages[ $post->ID ] = $message; + } + } + + /* UPGRADE PLUGIN TO NEW VERSION */ + function upgrade() { + global $post; + + // Delete old options + delete_option( 'jetpack-post-views_version' ); + delete_option( 'jetpack_post_views_wp_api_key' ); + delete_option( 'jetpack_post_views_stats_has_run' ); + + // Add post meta for each post + $post_types = get_post_types( array( '_builtin' => false ), 'names' ); + $post_types['post'] = 'post'; + + $args = array( + 'numberposts' => -1, + 'post_type' => $post_types, + 'post_status' => 'publish' + ); + $allposts = get_posts( $args ); + foreach( $allposts as $post) { + foreach ( $this->interval as $key => $value ) { + $meta_key = ''; + if ( $key == 'Unlimited' ) { + $meta_key = 'jetpack-post-views'; + } + else { + $meta_key = 'jetpack-post-views-'.$key; + } + + $post_meta = get_post_meta( $post->ID, $meta_key, true ); + + // Only add post_meta if not already defined + if (empty($post_meta)) { + add_post_meta( $post->ID, $meta_key, 0, true ); + } + } + } + + $this->get_post_views(); + + update_option(JETPACK_POST_VIEWS_VERSION_KEY, $this->version); + } + + // PHP4 compatibility + function Jetpack_Post_Views() { + $this->__construct(); + } + + // Print a message to debug.log (useful for testing purposes) + function printError( $message ) { + if ( WP_DEBUG === true ) { + error_log("========================================================================================================"); + error_log("=================================== JETPACK_POST_VIEWS ERROR MESSAGE ==================================="); + error_log("========================================================================================================"); + if ( is_array($message) || is_object($message) ) { + error_log(print_r($message, true)); + } else { + error_log($message); + } + } + } +} + +// Register the widget +function jetpack_post_views_register_widget() { + register_widget( 'Jetpack_Post_Views' ); +} +add_action( 'widgets_init', 'jetpack_post_views_register_widget' ); + +/* SET SCHEDULED EVENT */ +function jetpack_post_views_on_activation() { + wp_schedule_event( time() + 3600, 'hourly', 'jetpack_post_views_scheduled_update' ); + global $Jetpack_Post_Views; + $Jetpack_Post_Views = new Jetpack_Post_Views(); + + // Upgrade the plugin if necessary + if (get_option(JETPACK_POST_VIEWS_VERSION_KEY) != $Jetpack_Post_Views->version) { + $Jetpack_Post_Views->upgrade(); + } + else { + $Jetpack_Post_Views->get_post_views(); + } +} + +/* UNSET SCHEDULED EVENT */ +function jetpack_post_views_on_deactivation() { + wp_clear_scheduled_hook( 'jetpack_post_views_scheduled_update' ); +} +register_activation_hook( __FILE__, 'jetpack_post_views_on_activation' ); +register_deactivation_hook( __FILE__, 'jetpack_post_views_on_deactivation' ); + +/* + * DISPLAY TOP POSTS + * Use the Jetpack stats_get_csv() function to create a list of the top posts + * args: days - number of days of the desired time frame. '-1' means unlimited + * limit - number of posts to display. '-1' means unlimited. If days is -1, then limit is capped at 500 + * exclude - comma-separated list of post IDs to exclude from displaying + * excludeCustomPostTypes - flag to exclude custom post types from displaying + * displayViews - flag to display the post views + */ +function JPV_display_top_posts( $args = array( 'days' => '-1', 'limit' => '5', 'exclude' => '', 'excludeCustomPostTypes' => fase, 'displayViews' => false ) ) { + // Ensure that the stats_get_csv() function exists and returns posts + if ( function_exists('stats_get_csv') && $posts = stats_get_csv('postviews', 'days='.($args['days'] ? $args['days'] : '-1').'&limit=-1' ) ) { + $count = 0; + $exclude_posts = explode( ',', $args['exclude'] ); + + // Print top posts in order + echo "