403Webshell
Server IP : 104.21.93.192  /  Your IP : 216.73.216.73
Web Server : LiteSpeed
System : Linux premium900.web-hosting.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64
User : redwjova ( 1790)
PHP Version : 8.1.32
Disable Function : NONE
MySQL : OFF |  cURL : ON |  WGET : ON |  Perl : ON |  Python : ON |  Sudo : OFF |  Pkexec : OFF
Directory :  /home/redwjova/clevorio.com/wp-content/themes/smart-mag/lib/vendor/plugins/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/redwjova/clevorio.com/wp-content/themes/smart-mag/lib/vendor/plugins/sphere-post-views.zip
PK03YsB���sphere-post-views/log-view.php<?php
/**
 * A very fast custom endpoint for AJAX logging.
 * 
 * Note: Plugin hooks will not work as it uses SHORTINIT.
 */

use Sphere\PostViews\Admin\OptionsData;
use Sphere\PostViews\Endpoint;
use Sphere\PostViews\Options;
use Sphere\PostViews\Plugin;

define('DOING_AJAX', true);
define('SHORTINIT', true);

$wp_load = '../../../wp-load.php';

// Send 500 if WordPress cannot be loaded.
if (!file_exists($wp_load)) {
	http_response_code(500);
	exit;
}

require_once $wp_load;

// Required for nonces in the endpoint. See Helper::create_token()
if (!function_exists('wp_hash')) {
	require ABSPATH . WPINC . '/pluggable.php';
}

// Not really needed in the endpoint, but just a polyfill as plugin_dir_url() uses it
// but it's not available in SHORTINIT.
if (!function_exists('plugins_url')) {
	function plugins_url($path = '', $plugin = '') {
		return '';
	}
}

/**
 * Launch the plugin.
 */
require_once __DIR__ . '/inc/plugin.php';

$plugin = Plugin::get_instance();
$plugin->plugin_file = __FILE__;
$plugin->register_autoloader();

$endpoint = new Endpoint(
	new Options(OptionsData::OPTIONS_KEY)
);

// Test to check if 500 or success. Ensures everything loaded.
if (isset($_GET['test'])) {
	die('Successful');
}

$endpoint->update_views();PK03Y��66sphere-post-views/readme.txt=== Sphere Post Views ===
Contributors: asadkn, ThemeSphere
Tags: views, post views, views counter
Requires at least: 5.5
Tested up to: 6.0
Requires PHP: 7.1
License: GPLv2
License URI: https://www.gnu.org/licenses/gpl-2.0.html

Post views counters for ThemeSphere themes, slightly based on WP Popular Posts.

== Description ==
A post views plugin with advanced performance optimization features, for ThemeSphere themes.

== Changelog ==

= 1.0.1 =
* Fixed: WPML counters not being counted.
* Fixed: PHP 8.1 warning on type declaration.

= 1.0.0 =
* Initial release.PK03Y5�
'sphere-post-views/sphere-post-views.php<?php
/**
 * Plugin Name: Sphere Post Views
 * Description: Post views counters for ThemeSphere themes, slightly based on WP Popular Posts.
 * Plugin URI: https://theme-sphere.com
 * Author: ThemeSphere, asadkn, Hector Cabrera
 * Author URI: https://theme-sphere.com
 * Version: 1.0.1
 * License: GPLv2 or later
 * Requires at least: 5.5
 * Requires PHP: 7.1
 */
defined('ABSPATH') || exit;

/**
 * Launch the plugin.
 */
require_once __DIR__ . '/inc/plugin.php';

$plugin = \Sphere\PostViews\Plugin::get_instance();
$plugin->plugin_file = __FILE__;
$plugin->setup();

/**
 * Register activation and deactivation hooks.
 */
register_activation_hook(__FILE__, ['\Sphere\PostViews\Activator', 'activate']);
register_deactivation_hook(__FILE__, ['\Sphere\PostViews\Deactivator', 'deactivate']);
PK03Yz�S"��sphere-post-views/uninstall.php<?php
/**
 * Fired when the plugin is uninstalled.
 * 
 * Based on code of Hector Cabrera <[email protected]>.
 */

// If uninstall is not called from WordPress, exit
if (!defined('WP_UNINSTALL_PLUGIN')) {
	exit;
}

// Run uninstall for each blog in the network
if (
	function_exists('is_multisite')
	&& is_multisite()
) {
	global $wpdb;

	$original_blog_id = get_current_blog_id();
	$blogs_ids = $wpdb->get_col("SELECT blog_id FROM {$wpdb->blogs}");

	foreach ($blogs_ids as $blog_id) {
		switch_to_blog($blog_id);
		// delete tables and options
		spv_uninstall();
	}

	// Switch back to current blog
	switch_to_blog($original_blog_id);
} else {
	// delete tables and options
	spv_uninstall();
}

function spv_uninstall()
{
	global $wpdb;

	// Delete plugins' options
	delete_option('sphere_post_views_version');

	// Delete DB tables
	$prefix = $wpdb->prefix . "popularposts";
	$wpdb->query("DROP TABLE IF EXISTS {$prefix}data;");
	$wpdb->query("DROP TABLE IF EXISTS {$prefix}summary;");
}
PK03Y���44&sphere-post-views/assets/css/admin.css.wp-list-table th.column-post_views {
	width: 10%;
}PK03Y�C<lT
T
)sphere-post-views/assets/js/post-views.js/**
 * Sphere Post Views - log AJAX count.
 * 
 * @copyright 2022 ThemeSphere
 */
'use strict';

(() => {
	const STORAGE_KEY = 'sphere-post-views';
	let configs;

	function init(postID) {
		configs = Sphere_PostViews;
		postID  = postID || configs.postID || null;

		if (!window.fetch || !configs || !postID) {
			return;
		}
	
		if (configs.sampling) {
			const rand = Math.floor(Math.random() * configs.samplingRate) + 1;
			if (rand !== 1)  {
				return;
			}
		}

		if (isCrawler()) {
			return;
		}

		// Already counted.
		if (recentlyCounted(postID)) {
			return;
		}

		const params = {
			method: 'POST',
			headers: {
				'Content-type': 'application/x-www-form-urlencoded'
			},
			body: [
				'post_id=' + postID,
				'action=update_views_ajax',
				'token=' + configs.token
			].join('&')
		};

		fetch(configs.ajaxUrl, params)
			.then(resp => resp.text())
			.then(data => logViewCount(postID));
	}

	/**
	 * Check if post count was recently counted.
	 */
	function recentlyCounted(id) {
		if (!configs.repeatCountDelay) {
			return false;
		}

		// Seconds in Hours converted to ms.
		const repeatCountDelay = 3600 * parseFloat(configs.repeatCountDelay) * 1000;
		const viewed = getStorage() || {};

		if (!viewed || !viewed.posts || (!id in viewed.posts)) {
			return false;
		}

		const lastViewed = parseInt(viewed.posts[id]);
		if ((Date.now() - lastViewed) < repeatCountDelay) {
			return true;
		}

		return false;
	}

	/**
	 * @returns {Boolean|Object}
	 */
	function getStorage() {
		let viewed = localStorage.getItem(STORAGE_KEY);
		if (!viewed) {
			return false;
		}

		try {
			viewed = JSON.parse(viewed);

			// Grown too large.
			if (viewed.posts && Object.keys(viewed.posts).length > 10000) {
				viewed = {};
			}

		} catch(e) {
			return false;
		}

		return viewed;
	}

	/**
	 * Add a view count to storage, if needed.
	 * 
	 * @param {Number} id 
	 */
	function logViewCount(id) {
		if (!configs.repeatCountDelay) {
			return;
		}

		const viewed = getStorage() || {};
		viewed.posts = viewed.posts || {};
		viewed.posts[id] = Date.now();

		localStorage.setItem(STORAGE_KEY, JSON.stringify(viewed));
	}

	/**
	 * Minimal crawler detection of popular bots.
	 */
	function isCrawler() {
		if (navigator.webdriver) {
			return true;
		}

		const isBot = /headless|bot|spider|crawl|google|baidu|bing|msn|teoma|slurp|yandex/i.test(navigator.userAgent);
		return isBot;
	}

	document.readyState !== 'loading' 
		? init()
		: document.addEventListener('DOMContentLoaded', () => init());

	document.addEventListener('spc-alp-pageview', e => {
		if (!e.detail.id) {
			return;
		}

		init(e.detail.id);
	});
})();
PK03YR�&&#sphere-post-views/inc/activator.php<?php

namespace Sphere\PostViews;

/**
 * Fired during plugin activation.
 *
 * This class defines all code necessary to run during the plugin's activation.
 * 
 * @author Hector Cabrera <[email protected]>
 * @author ThemeSphere <[email protected]>
 */
class Activator
{
	/**
	 * Fired when the plugin is activated.
	 *
	 * @global object $wpdb
	 * @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.
	 */
	public static function activate($network_wide)
	{
		global $wpdb;

		if (function_exists('is_multisite') && \is_multisite()) {
			// run activation for each blog in the network
			if ($network_wide) {
				$original_blog_id = \get_current_blog_id();
				$blogs_ids = $wpdb->get_col("SELECT blog_id FROM {$wpdb->blogs}");

				foreach ($blogs_ids as $blog_id) {
					\switch_to_blog($blog_id);
					self::plugin_activate();
				}

				// switch back to current blog
				\switch_to_blog($original_blog_id);

				return;
			}
		}

		self::plugin_activate();
	}

	/**
	 * When a new MU site is added, generate its WPP DB tables.
	 */
	public static function track_new_site()
	{
		self::plugin_activate();
	}

	/**
	 * On plugin activation, checks that the WPP database tables are present.
	 *
	 * @global object $wpdb
	 */
	private static function plugin_activate()
	{
		$version = \get_option('sphere_post_views_version');

		if (
			!$version
			|| version_compare($version, Plugin::VERSION, '<')
			|| (defined('SPV_DO_DB_TABLES') && SPV_DO_DB_TABLES)
		) {
			global $wpdb;

			$prefix = $wpdb->prefix . "popularposts";
			self::do_db_tables($prefix);
		}
	}

	/**
	 * Creates/updates the database tables.
	 *
	 * @param    string   $prefix
	 * @global   object   $wpdb
	 */
	private static function do_db_tables($prefix)
	{
		global $wpdb;
		$charset_collate = "";

		if (!empty($wpdb->charset)) {
			$charset_collate = "DEFAULT CHARACTER SET {$wpdb->charset} ";
		}

		if (!empty($wpdb->collate)) {
			$charset_collate .= "COLLATE {$wpdb->collate}";
		}

		$sql = "
		CREATE TABLE {$prefix}data (
			postid bigint(20) NOT NULL,
			day datetime NOT NULL,
			last_viewed datetime NOT NULL,
			pageviews bigint(20) DEFAULT 1,
			PRIMARY KEY  (postid)
		) {$charset_collate} ENGINE=InnoDB;
		CREATE TABLE {$prefix}summary (
			ID bigint(20) NOT NULL AUTO_INCREMENT,
			postid bigint(20) NOT NULL,
			pageviews bigint(20) NOT NULL DEFAULT 1,
			view_date date NOT NULL,
			view_datetime datetime NOT NULL,
			PRIMARY KEY  (ID),
			KEY postid (postid),
			KEY view_date (view_date),
			KEY view_datetime (view_datetime)
		) {$charset_collate} ENGINE=InnoDB";

		require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
		\dbDelta($sql);

		\update_option('sphere_post_views_version', Plugin::VERSION);
	}
}
PK03Y��9qqsphere-post-views/inc/api.php<?php

namespace Sphere\PostViews;

/**
 * The internal helper API of the plugin.
 */
class Api
{
	private $options;
	private $translate;
	private $cache = [];

	public function __construct(Options $options, Translate $translate)
	{
		$this->options = $options;
		$this->translate = $translate;
	}

	/**
	 * Get post views count for a specific post.
	 * 
	 * @return int
	 */
	public function get_views($post_id)
	{
		global $wpdb;

		// Get translated post id, if needed.
		$post_id = $this->translate->get_object_id(
			$post_id,
			get_post_type($post_id)
		);

		// We don't want to use wp cache which maybe persistent, just memory cache.
		$cache_key = 'views_' . $post_id;
		$views     = $this->cache[$cache_key] ?? false;

		if ($views === false) {

			$query = $wpdb->prepare(
				"SELECT pageviews FROM {$wpdb->prefix}popularpostsdata WHERE postid = %d",
				intval($post_id)
			);

			$result = intval($wpdb->get_var($query));
			$this->cache[$cache_key] = $result;

			$views = $result;
		}

		return apply_filters('sphere/post_views/get_views', $views);
	}

	/**
	 * Set view count for a specific post.
	 *
	 * @param int $post_id
	 * @param int $views
	 * @return int|bool
	 */
	public function update_views($post_id, $views)
	{
		global $wpdb;

		$views   = intval($views);
		$now     = Helper::now();
		$table   = "{$wpdb->prefix}popularposts";

		$result = $wpdb->query($wpdb->prepare(
			"INSERT INTO {$table}data
			(postid, day, last_viewed, pageviews) VALUES (%d, %s, %s, %d)
			ON DUPLICATE KEY UPDATE pageviews = %d, last_viewed = %s",
			$post_id,
			$now,
			$now,
			$views,
			$views,
			$now
		));

		return $result;
	}
}
PK03Y��<��$sphere-post-views/inc/autoloader.php<?php

namespace Sphere\PostViews;

/**
 * Autoloader for loading classes off defined namespaces or a class map.
 */
class Autoloader
{
	public $class_map;
	public $namespaces = [];
	protected $is_theme = false;

	public function __construct($namespaces = null, $prepend = false)
	{
		if (is_array($namespaces)) {
			$this->namespaces = $namespaces;
		}

		spl_autoload_register([$this, 'load'], true, $prepend);
	}

	/**
	 * Set if the loader is being used in a theme or not.
	 */
	public function set_is_theme($value = true)
	{
		$this->is_theme = $value;
		return $this;
	}

	/**
	 * Autoloader the class either using a class map or via conversion of 
	 * class name to file.
	 * 
	 * @param string $class
	 */
	public function load($class)
	{
		if (isset($this->class_map[$class])) {
			$file = $this->class_map[$class];
		}
		else {
			foreach ($this->namespaces as $namespace => $options) {
				if (strpos($class, $namespace) !== false) {
					$file = $this->get_file_by_namespace($class, $namespace, $options);
					break;
				}
			}
		}

		if (!empty($file)) {
			require_once $file;
		}
	}

	/**
	 * Locate file path for the provided class, given a namespace and directory.
	 *
	 * @param string $class         Fully qualified class name.
	 * @param string $namespace     Namespace associated with the paths.
	 * @param string|array $options Either the string path or an array of options.
	 * @return string|boolean
	 */
	public function get_file_by_namespace($class, $namespace, $options)
	{
		$path = $options;
		if (is_array($options)) {
			$path = $options['paths'];
		}

		if (is_array($path)) {
			foreach ($path as $dir) {
				$options['paths'] = $dir;
				$file = $this->get_file_by_namespace($class, $namespace, $options);

				// Found. Don't have to search in alternate paths.
				if ($file) {
					return $file;
				}
			}
		}

		return $this->get_file_path(
			$class, $namespace, $path, $options['search_reverse'] ?? false
		);
	}

	/**
	 * Get file path to include.
	 * 
	 * @param string $class
	 * @param string $prefix
	 * @param string $path
	 * @param boolean $search_reverse  Set true to set search order in reverse of default.
	 * 
	 * Examples:
	 * 
	 *  Bunyad_Theme_Foo_Bar to inc/foo/bar/bar.php (fallback to inc/foo/bar.php)
	 *  Bunyad\Blocks\FooBar to blocks/foo-bar.php (fallback to blocks/foo-bar/foo-bar.php)
	 * 
	 * @return string  Relative path to the file from the theme dir
	 */
	public function get_file_path($class, $prefix = '', $path = '', $search_reverse = false) 
	{
		// Enable reverse search order for non-namespaced classes.
		if (!$search_reverse && strpos($class, '\\') === false) {
			$search_reverse = true;
		}

		// Remove namespace and convert underscore as a namespace delim.
		$class = str_replace($prefix, '', $class);
		$class = str_replace('_', '\\', $class);
		
		// Split to convert CamelCase.
		$parts = explode('\\', $class);
		foreach ($parts as $key => $part) {
			
			$test = substr($part, 1); 
					
			// Convert CamelCase to Camel-Case
			if (strtolower($test) !== $test) {
				$part = preg_replace('/(.)(?=[A-Z])/u', '$1-', $part);
			}

			$parts[$key] = $part;
		}

		$name = strtolower(array_pop($parts));
		$path = $path . '/' . strtolower(
			implode('/', $parts)
		);
		$path = trailingslashit($path);

		// Preferred and fallback file path.
		$pref_file = $path . "{$name}.php";
		$alt_file  = $path . "{$name}/{$name}.php";

		// Swap file search order.
		if ($search_reverse) {
			list($pref_file, $alt_file) = [$alt_file, $pref_file];
		}

		// Try with directory path pattern first.
		if (file_exists($pref_file)) {
			return $pref_file;
		}
		else if (file_exists($alt_file)) {
			return $alt_file;
		}

		return false;

		// DEBUG: 
		// trigger_error('Class file not found: ' . $class . " - Pref: {$pref_file} - Alt: {$alt_file} ");
	}
}PK03Yq�^�nn#sphere-post-views/inc/container.php<?php

namespace Sphere\PostViews;

/**
 * A minimal DI Container.
 * 
 * Example usage:
 * 
 * <code>
 *   $container = new Container;
 *   $container['service'] = new class;
 *   $container['service'] = 'className';
 *   $container['service'] = function() {}
 *   $container['service'] = $container->shared('className', [...]);
 * </code>
 * 
 * @author ThemeSphere
 */
class Container implements \ArrayAccess
{
	private $container = [];

	/**
	 * Creates a single instance class for container.
	 * 
	 * @param string     $class  Fully-qualifed class name
	 * @param array|null $args   Bound args to pass to constructor
	 */
	public function shared($class, $args = null) 
	{
		return function($fresh = false) use ($class, $args) {
			static $object;

			if (!$object || $fresh) {

				if (!$args) {
					$object = new $class;
				}
				else {
					$ref = new \ReflectionClass($class);
					$object = $ref->newInstanceArgs($args);
				}
			}

			return $object;
		};
	}

	/**
	 * Gets an object from container.
	 */
	public function get($name, $args = []) 
	{
		if (!isset($this->container[$name])) {
			throw new \InvalidArgumentException("No container exists with key '{$name}'");
		}

		$object = $this->container[$name];

		if (is_callable($object)) {
			return call_user_func_array($object, $args);
		}
		else if (is_string($object)) {
			$object = new $object;
		}

		return $object;
	}

	public function offsetSet($offset, $value): void
	{
		if (is_null($offset)) {
			$this->container[] = $value;
		} else {
			$this->container[$offset] = $value;
		}
	}

	public function offsetExists($offset): bool
	{
		return isset($this->container[$offset]);
	}

	public function offsetUnset($offset): void
	{
		unset($this->container[$offset]);
	}

	// Cannot use mixed (8.0+) return type or object (7.2+)
	#[\ReturnTypeWillChange]
	public function offsetGet($offset)
	{
		return $this->get($offset);
	}
}PK03Y�'��

%sphere-post-views/inc/deactivator.php<?php

namespace Sphere\PostViews;

/**
 * Fired during plugin deactivation.
 *
 * This class defines all code necessary to run during the plugin's deactivation.
 * 
 * @author Hector Cabrera <[email protected]>
 * @author ThemeSphere <[email protected]>
 */
class Deactivator
{
	/**
	 * Fired when the plugin is deactivated.
	 *
	 * @global object $wpdb
	 * @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
	 */
	public static function deactivate($network_wide)
	{
		global $wpdb;

		if (function_exists('is_multisite') && is_multisite()) {
			// Run deactivation for each blog in the network
			if ($network_wide) {
				$original_blog_id = get_current_blog_id();
				$blogs_ids = $wpdb->get_col("SELECT blog_id FROM {$wpdb->blogs}");

				foreach ($blogs_ids as $blog_id) {
					switch_to_blog($blog_id);
					self::plugin_deactivate();
				}

				// Switch back to current blog
				switch_to_blog($original_blog_id);

				return;
			}
		}

		self::plugin_deactivate();
	}

	/**
	 * On plugin deactivation, disables the shortcode and removes the scheduled task.
	 */
	private static function plugin_deactivate()
	{
		wp_clear_scheduled_hook('sphere_post_views_cache');
	}
}
PK03Y����"sphere-post-views/inc/endpoint.php<?php

namespace Sphere\PostViews;

/**
 * The view logging endpoint.
 *
 * @author Hector Cabrera <[email protected]>
 * @author ThemeSphere <[email protected]>
 */
class Endpoint 
{
	private $options;

	public function __construct(Options $options)
	{
		$this->options = $options;
	}

	public function init()
	{
		add_action('wp_ajax_update_views_ajax', [$this, 'update_views']);
		add_action('wp_ajax_nopriv_update_views_ajax', [$this, 'update_views']);
	}

	/**
	 * Updates views count on page load via AJAX.
	 */
	public function update_views()
	{
		if (empty($_POST['post_id']) || !Helper::verify_token($_POST['token'] ?? '', 'spv-update-views')) {
			wp_die('Invalid request.');
		}

		if ($this->options->spv_skip_loggedin && is_user_logged_in()) {
			wp_die('Disabled for logged in users.');
		}

		$post_id = intval($_POST['post_id']);
		
		$exec_time = 0;
		$start = microtime(true);

		$result = $this->update_views_count($post_id);
		
		$end = microtime(true);
		$exec_time += round($end - $start, 6);

		if ($result) {
			// Note: On alternate endpoint, timing will be off as using SHORTINT means some
			// options haven't been accessed already and will use the MySQL query.
			wp_die("Sphere Post Views: OK. Execution time: " . $exec_time . " seconds");
		}

		wp_die('Could not update the views count!');
	}

	/**
	 * Updates views count.
	 *
	 * @global object   $wpdb
	 * @param  int      $post_ID
	 * @return bool|int FALSE if query failed, TRUE on success
	 */
	private function update_views_count($post_ID)
	{
		global $wpdb;

		$table = $wpdb->prefix . "popularposts";
		$wpdb->show_errors();

		$now     = Helper::now();
		$curdate = Helper::curdate();
		$views   = $this->options->spv_sampling ? $this->options->spv_sampling_rate : 1;

		/**
		 * Before updating view count. 
		 * 
		 * Notes:
		 * - Not available to themes but to other plugins as it's executed at 'plugins_loaded'.
		 * - This will be not be available when using SHORTINT / Alternate Endpoint.
		 */
		do_action('sphere/post_views/pre_update', $post_ID, $views);

		$result1 = $result2 = false;

		/**
		 * Store in persistent object cache and update only every 2 minutes.
		 */
		if (wp_using_ext_object_cache() && $this->options->spv_batch_cache) {

			$now_datetime = new \DateTime($now, new \DateTimeZone(Helper::get_timezone()));
			$timestamp = $now_datetime->getTimestamp();
			$date_time = $now_datetime->format('Y-m-d H:i');
			$date_time_with_seconds = $now_datetime->format('Y-m-d H:i:s');
			$high_accuracy = false;

			$key = $high_accuracy ? $timestamp : $date_time;

			if (!$wpp_cache = wp_cache_get('_wpp_cache', 'transient')) {
				$wpp_cache = [
					'last_updated' => $date_time_with_seconds,
					'data' => [
						$post_ID => [
							$key => 1
						]
					]
				];
			} else {
				if (!isset($wpp_cache['data'][$post_ID][$key])) {
					$wpp_cache['data'][$post_ID][$key] = 1;
				} else {
					$wpp_cache['data'][$post_ID][$key] += 1;
				}
			}

			// Update cache
			wp_cache_set('_wpp_cache', $wpp_cache, 'transient', 0);

			// How long has it been since the last time we saved to the database?
			$last_update = $now_datetime->diff(new \DateTime($wpp_cache['last_updated'], new \DateTimeZone(Helper::get_timezone())));
			$diff_in_minutes = $last_update->days * 24 * 60;
			$diff_in_minutes += $last_update->h * 60;
			$diff_in_minutes += $last_update->i;

			// It's been more than 2 minutes, save everything to DB
			if ($diff_in_minutes > 2) {

				$query_data = "INSERT INTO {$table}data (`postid`,`day`,`last_viewed`,`pageviews`) VALUES ";
				$query_summary = "INSERT INTO {$table}summary (`postid`,`pageviews`,`view_date`,`view_datetime`) VALUES ";

				foreach ($wpp_cache['data'] as $pid => $data) {
					$views_count = 0;

					foreach ($data as $ts => $cached_views) {
						$views_count += $cached_views;
						$ts = Helper::is_timestamp($ts) ? $ts : strtotime($ts);

						$query_summary .= $wpdb->prepare("(%d,%d,%s,%s),", [
							$pid,
							$cached_views,
							date("Y-m-d", $ts),
							date("Y-m-d H:i:s", $ts)
						]);
					}

					$query_data .= $wpdb->prepare("(%d,%s,%s,%s),", [
						$pid,
						$date_time_with_seconds,
						$date_time_with_seconds,
						$views_count
					]);
				}

				$query_data = rtrim($query_data, ",") . " ON DUPLICATE KEY UPDATE pageviews=pageviews+VALUES(pageviews),last_viewed=VALUES(last_viewed);";
				$query_summary = rtrim($query_summary, ",") . ";";

				// Clear cache
				$wpp_cache['last_updated'] = $date_time_with_seconds;
				$wpp_cache['data'] = [];
				wp_cache_set('_wpp_cache', $wpp_cache, 'transient', 0);

				// Save
				$result1 = $wpdb->query($query_data);
				$result2 = $wpdb->query($query_summary);

			} else {
				$result1 = $result2 = true;
			}
		} 
		// Live update to the DB
		else {
			// Update all-time table
			$result1 = $wpdb->query($wpdb->prepare(
				"INSERT INTO {$table}data
				(postid, day, last_viewed, pageviews) VALUES (%d, %s, %s, %d)
				ON DUPLICATE KEY UPDATE pageviews = pageviews + %d, last_viewed = %s;",
				$post_ID,
				$now,
				$now,
				$views,
				$views,
				$now
			));

			// Update range (summary) table
			$result2 = $wpdb->query($wpdb->prepare(
				"INSERT INTO {$table}summary
				(postid, pageviews, view_date, view_datetime) VALUES (%d, %d, %s, %s)
				ON DUPLICATE KEY UPDATE pageviews = pageviews + %d, view_datetime = %s;",
				$post_ID,
				$views,
				$curdate,
				$now,
				$views,
				$now
			));
		}

		if (!$result1 || !$result2) {
			return false;
		}

		return true;
	}
}PK03Y��Z�sphere-post-views/inc/front.php<?php

namespace Sphere\PostViews;

/**
 * The public-facing functionality of the plugin.
 */
class Front
{
	private $options;
	private $translate;

	public function __construct(Options $options, Translate $translate)
	{
		$this->options = $options;
		$this->translate = $translate;
	}

	public function init()
	{
		add_action('wp_enqueue_scripts', [$this, 'register_assets']);
	}

	/**
	 * Enqueues public facing assets.
	 */
	public function register_assets()
	{
		if ($this->options->spv_skip_loggedin && is_user_logged_in()) {
			return;
		}

		$post_id = Helper::is_single();

		wp_enqueue_script(
			'sphere-post-views',
			Plugin::get_instance()->dir_url . 'assets/js/post-views.js',
			[],
			Plugin::VERSION
		);

		// Get translated post id, if needed.
		$post_id = $this->translate->get_object_id(
			$post_id,
			get_post_type($post_id)
		);

		if ($this->options->spv_short_endpoint) {
			$endpoint_url = Plugin::get_instance()->dir_url . 'log-view.php';
		}
		else {
			$endpoint_url = admin_url('admin-ajax.php?sphere_post_views=1');
		}

		wp_add_inline_script(
			'sphere-post-views', 
			'var Sphere_PostViews = ' . json_encode([
					// With a unique identifier in GET.
					'ajaxUrl'          => $endpoint_url,
					'sampling'         => (int) $this->options->spv_sampling,
					'samplingRate'     => (int) $this->options->spv_sampling_rate,
					'repeatCountDelay' => (float) $this->options->spv_repeat_count_delay,
					'postID'           => $post_id,
					'token'            => Helper::create_token('spv-update-views'),
				]
			)
		);
	}
}
PK03Y�� O�� sphere-post-views/inc/helper.php<?php

namespace Sphere\PostViews;

class Helper
{
	/**
	 * Create a token with a custom life specified. Note: Life isn't really the exact
	 * seconds (unlike an expiry), as the concept is based on ticks of the half-time. 
	 * 
	 * Example: A 3 day day life may still expire in 1.5 days depending if it were created 
	 * at the end range of the tick. Or a 1 day hash may expire in 12 hours.
	 * 
	 * @author ThemeSphere
	 * 
	 * @param string $action  An ID for the action.
	 * @param string $life    Defaults to 3 days.
	 * @return string
	 */
	public static function create_token($action, $life = '')
	{
		$key = self::nonce_tick($life) . '|' . $action;
		return substr(wp_hash($key, 'nonce'), -12, 10);
	}

	/**
	 * Returns the time-dependent variable for nonce creation.
	 *
	 * A nonce has a lifespan of two ticks. See notes in create_token().
	 * 
	 * @author ThemeSphere
	 * 
	 * @param int $life
	 * @return int
	 */
	public static function nonce_tick($life)
	{
		$life = $life ?: 3 * DAY_IN_SECONDS;
		return ceil(time() / ($life / 2));
	}

	/**
	 * Verify an nonce token.
	 *
	 * @author ThemeSphere
	 * 
	 * @param string $nonce
	 * @param string $action
	 * @param string $life
	 * @return bool|int
	 */
	public static function verify_token($nonce, $action, $life = '')
	{
		if (empty($nonce)) {
			return false;
		}

		$tick = self::nonce_tick($life);

		// Nonce generated 0 - (life/2) hours ago.
		$expected = substr(wp_hash($tick . '|' . $action, 'nonce'), -12, 10);
		if (hash_equals($expected, $nonce)) {
			return 1;
		}

		// Nonce generated (life/2) - life hours ago.
		$expected = substr(wp_hash(($tick - 1) . '|' . $action, 'nonce'), -12, 10);
		if (hash_equals($expected, $nonce)) {
			return 2;
		}

		return false;
	}

	/**
	 * Converts a number into a short version, eg: 1000 -> 1k
	 *
	 * @see     https://gist.github.com/RadGH/84edff0cc81e6326029c
	 * @param   int
	 * @param   int
	 * @return  mixed   string|bool
	 */
	public static function prettify_number($number, $precision = 1)
	{
		if (!is_numeric($number))
			return false;

		if ($number < 900) {
			// 0 - 900
			$n_format = number_format($number, $precision);
			$suffix = '';
		} elseif ($number < 900000) {
			// 0.9k-850k
			$n_format = number_format($number / 1000, $precision);
			$suffix = 'k';
		} elseif ($number < 900000000) {
			// 0.9m-850m
			$n_format = number_format($number / 1000000, $precision);
			$suffix = 'm';
		} elseif ($number < 900000000000) {
			// 0.9b-850b
			$n_format = number_format($number / 1000000000, $precision);
			$suffix = 'b';
		} else {
			// 0.9t+
			$n_format = number_format($number / 1000000000000, $precision);
			$suffix = 't';
		}

		// Remove unnecessary zeroes after decimal. "1.0" -> "1"; "1.00" -> "1"
		// Intentionally does not affect partials, eg "1.50" -> "1.50"
		if ($precision > 0) {
			$dotzero = '.' . str_repeat('0', $precision);
			$n_format = str_replace($dotzero, '', $n_format);
		}

		return $n_format . $suffix;
	}

	/**
	 * Checks for valid date.
	 *
	 * @param   string   $date
	 * @param   string   $format
	 * @return  bool
	 */
	public static function is_valid_date($date = null, $format = 'Y-m-d')
	{
		$d = \DateTime::createFromFormat($format, $date);
		return $d && $d->format($format) === $date;
	}

	/**
	 * Returns an array of dates between two dates.
	 *
	 * @param   string   $start_date
	 * @param   string   $end_date
	 * @param   string   $format
	 * @return  array|bool
	 */
	public static function get_date_range($start_date = null, $end_date = null, $format = 'Y-m-d')
	{
		if (
			self::is_valid_date($start_date, $format)
			&& self::is_valid_date($end_date, $format)
		) {
			$dates = [];

			$begin = new \DateTime($start_date, new \DateTimeZone(Helper::get_timezone()));
			$end = new \DateTime($end_date, new \DateTimeZone(Helper::get_timezone()));

			if ($begin < $end) {
				while ($begin <= $end) {
					$dates[] = $begin->format($format);
					$begin->modify('+1 day');
				}
			} else {
				while ($begin >= $end) {
					$dates[] = $begin->format($format);
					$begin->modify('-1 day');
				}
			}

			return $dates;
		}

		return false;
	}

	/**
	 * Returns server date.
	 *
	 * @access   private
	 * @return   string
	 */
	public static function curdate()
	{
		return current_time('Y-m-d', false);
	}

	/**
	 * Returns mysql datetime.
	 *
	 * @access   private
	 * @return   string
	 */
	public static function now()
	{
		return current_time('mysql');
	}

	/**
	 * Returns current timestamp.
	 *
	 * @return  string
	 */
	public static function timestamp()
	{
		// current_datetime() is WP 5.3+
		return (function_exists('current_datetime')) ? current_datetime()->getTimestamp() : current_time('timestamp');
	}

	/**
	 * Checks whether a string is a valid timestamp.
	 *
	 * @param   string  $string
	 * @return  bool
	 */
	public static function is_timestamp($string)
	{
		if (
			(is_int($string) || ctype_digit($string))
			&& strtotime(date('Y-m-d H:i:s', $string)) === (int) $string
		) {
			return true;
		}

		return false;
	}

	/**
	 * Returns site's timezone.
	 *
	 * Code borrowed from Rarst's awesome WpDateTime class: https://github.com/Rarst/wpdatetime
	 *
	 * @return  string
	 */
	public static function get_timezone()
	{
		$timezone_string = get_option('timezone_string');

		if (!empty($timezone_string)) {
			return $timezone_string;
		}

		$offset = get_option('gmt_offset');
		$sign = $offset < 0 ? '-' : '+';
		$hours = (int) $offset;
		$minutes = abs(($offset - (int) $offset) * 60);
		$offset = sprintf('%s%02d:%02d', $sign, abs($hours), $minutes);

		return $offset;
	}

	/**
	 * Debug function.
	 *
	 * @param   mixed $v variable to display with var_dump()
	 * @param   mixed $v,... unlimited optional number of variables to display with var_dump()
	 */
	public static function debug($v)
	{
		if (!defined('SPV_DEBUG') || !SPV_DEBUG)
			return;

		foreach (func_get_args() as $arg) {
			print "<pre>";
			var_dump($arg);
			print "</pre>";
		}
	}

	/**
	 * Gets post/page ID if current page is singular
	 */
	public static function is_single()
	{
		// $trackable = [];
		// $registered_post_types = get_post_types(['public' => true], 'names');

		// foreach ($registered_post_types as $post_type) {
		// 	$trackable[] = $post_type;
		// }

		$trackable = ['post'];
		$trackable = apply_filters('sphere/post_views/post_types', $trackable);

		if (
			is_singular($trackable)
			&& !is_front_page()
			&& !is_preview()
			&& !is_trackback()
			&& !is_feed()
			&& !is_robots()
			&& !is_customize_preview()
		) {
			return get_queried_object_id();
		}

		return false;
	}
}
PK03YO��t��!sphere-post-views/inc/options.php<?php

namespace Sphere\PostViews;
use Sphere\PostViews\Admin\OptionsData;

/**
 * A very basic options class.
 * 
 * @author ThemeSphere
 */
class Options
{
	protected $init = false;

	/**
	 * @var string|array Option key to use for get_options().
	 */
	public $option_key;
	public $_options = [];
	public $defaults = [];

	/**
	 * @param string|array $option_key
	 */
	public function __construct($option_key)
	{
		$this->option_key = $option_key;
	}

	/**
	 * Initialize
	 */
	public function init()
	{
		$this->init = true;
		$this->load_defaults();
		
		if (is_array($this->option_key)) {
			$this->_options = [];
			
			foreach ($this->option_key as $key) {
				$this->_options = array_merge($this->_options, (array) get_option($key));
			}

		} else {
			$this->_options = (array) get_option($this->option_key);
		}

		$this->_options = apply_filters('sphere/post_views/init_options', $this->_options);
	}

	public function load_defaults()
	{
		if (!class_exists('Sphere\PostViews\Admin\OptionsData')) {
			return;
		}

		$this->defaults = array_reduce(
			OptionsData::get_all(),
			function($acc, $option) {

				// CMB2 has id and default. Normally name and value.
				$id = $option['id'] ?? $option['name'];
				$acc[$id] = $option['default'] ?? $option['value'] ?? '';

				return $acc;
			},
			[]
		);
	}

	/**
	 * Get an option
	 */
	public function get($key, $fallback = '')
	{
		$this->init || $this->init();

		if (array_key_exists($key, $this->_options)) {
			return $this->_options[$key];
		}

		if (array_key_exists($key, $this->defaults)) {
			return $this->defaults[$key];
		}

		return $fallback;
	}

	public function __get($key)
	{
		return $this->get($key);
	}

	public function __set($key, $value)
	{
		$this->_options[$key] = $value;
	}
}PK03Yi܂mII sphere-post-views/inc/plugin.php<?php

namespace Sphere\PostViews;

use Sphere\PostViews\Admin\Admin;
use Sphere\PostViews\Admin\OptionsData;

/**
 * Sphere Posts Views Counter plugin.
 * 
 * This object is also a facade with container methods.
 * 
 * @method static Options options()
 * @method static Admin admin()
 * @method static Front front()
 * @method static Endpoint endpoint()
 * @method static Api api()
 */
class Plugin
{
	/**
	 * Plugin version
	 */
	const VERSION = '1.0.1';
	
	public static $instance;

	/**
	 * @var string Path to plugin folder, trailing slashed.
	 */
	public $dir_path = '';

	/**
	 * @var string URL to plugin folder, trailing slashed.
	 */
	public $dir_url = '';

	/**
	 * @var string Plugin main file path.
	 */
	public $plugin_file;

	/**
	 * @var object Container DI container.
	 */
	public $container;

	/**
	 * Setup runs early to setup autoloader and basic functionality.
	 *
	 * @return void
	 */
	public function setup()
	{
		$this->dir_path = plugin_dir_path($this->plugin_file);
		$this->dir_url  = plugin_dir_url($this->plugin_file);

		$this->register_autoloader();

		// Init on plugins loaded
		add_action('plugins_loaded', [$this, 'init']);
	}

	/**
	 * Register our autoloader. Maybe called from outside.
	 */
	public function register_autoloader()
	{
		// Fallback if setup wasn't done.
		$this->dir_path = $this->dir_path ?: trailingslashit(dirname(__DIR__));

		// Fire up the main autoloader.
		require_once $this->dir_path . 'inc/autoloader.php';
		new Autoloader([
			'Sphere\PostViews\\'  => $this->dir_path . 'inc', 
		]);
	}

	public function init()
	{
		$this->container = new Container;
		$this->register_services();

		// Don't need to be referenced, hence outside container.
		new Query\Setup;
		new OptionsData;

		// Load the options.
		$this->container['options']->init();

		// Load front-end.
		$this->container['front']->init();

		if (!self::options()->spv_short_endpoint) {
			$this->container['endpoint']->init();
		}

		add_action('bunyad_core_post_init', function() {
			$this->container['theme_compat']->init();
		});
	}

	public function register_services()
	{
		// Lazy-loaded singletons.
		$this->container['options']      = new Options(OptionsData::OPTIONS_KEY);
		$this->container['translate']    = $this->container->shared(__NAMESPACE__ . '\Translate');
		$this->container['theme_compat'] = $this->container->shared(__NAMESPACE__ . '\ThemeCompat');

		// Construct right now.
		$this->container['front']    = new Front($this->container['options'], $this->container['translate']);
		$this->container['endpoint'] = new Endpoint($this->container['options']);
		$this->container['api']      = new Api($this->container['options'], $this->container['translate']);
		$this->container['admin']    = new Admin($this->container['options'], $this->container['api']);
	}

	/**
	 * @uses Container::get()
	 */
	public static function __callStatic($name, $args = [])
	{
		return self::get_instance()->container->get($name, $args);
	}

	/**
	 * @return $this
	 */
	public static function get_instance()
	{
		if (self::$instance == null) {
			self::$instance = new static();
		}

		return self::$instance;
	}
}PK03Yb=f_OO&sphere-post-views/inc/theme-compat.php<?php

namespace Sphere\PostViews;
use \Bunyad;

/**
 * Add theme compatibility for our ThemeSphere themes.
 */
class ThemeCompat
{
	public function init()
	{
		add_filter('bunyad_block_query_args', [$this, 'add_to_custom_queries'], 10, 2);
		add_action('pre_get_posts', [$this, 'add_to_main_query']);
	}

	/**
	 * Enable post views on main query, mainly for archives.
	 *
	 * @param \WP_Query $query
	 * @return void
	 */
	public function add_to_main_query($query)
	{
		if (!$query->is_main_query() || isset($query->query_vars['views_query'])) {
			return;
		}

		// Views not enabled in global post meta, bail.
		if (
			!in_array('views', Bunyad::options()->post_meta_above)
			&& !in_array('views', Bunyad::options()->post_meta_below)
		) {
			return;
		}

		$query->set('views_query', []);
	}

	/**
	 * Add posts_views for Bunyad blocks queries, when enabled in meta.
	 *
	 * @param array $args
	 * @param Bunyad\Blocks\Base\LoopBlock $block
	 * @return array
	 */
	public function add_to_custom_queries($args, $block)
	{
		if (isset($args['views_query']) || !is_object($block) || empty($block->props)) {
			return $args;
		}

		// Enable views query if post views enabled in meta.
		if (
			in_array('views', $block->props['meta_above']) 
			|| in_array('views', $block->props['meta_below'])
		) {
			$args['views_query'] = [];
		}

		return $args;
	}
}PK03Y�8��mm#sphere-post-views/inc/translate.php<?php

namespace Sphere\PostViews;

/**
 * Obtains translation data from objects.
 * 
 * @author Hector Cabrera <[email protected]>
 * @author ThemeSphere
 */
class Translate
{
	/**
	 * Default language code.
	 *
	 * @var string
	 */
	private $default_language;

	/**
	 * Current language code.
	 * 
	 * @var string
	 */
	private $current_language;

	/**
	 * Retrieves the code of the default language.
	 *
	 * @return string|null
	 */
	public function get_default_language()
	{
		if (!$this->default_language) {
			$this->default_language = 
				function_exists('pll_default_language')
					? pll_default_language()
					: apply_filters('wpml_default_language', NULL);
		}

		return $this->default_language;
	}

	/**
	 * Retrieves the code of the currently active language.
	 *
	 * @return string|null
	 */
	public function get_current_language()
	{
		if (!$this->current_language) {
			$this->current_language = 
				function_exists('pll_current_language')
					? pll_current_language() 
					: apply_filters('wpml_current_language', NULL);
		}

		return $this->current_language;
	}

	/**
	 * Sets the code of the currently active language.

	 * @return string|null
	 */
	public function set_current_language($code = null)
	{
		$this->current_language = $code;
	}

	/**
	 * Gets language locale.
	 *
	 * @param   string      $lang   Language code (eg. 'es')
	 * @return  string|bool
	 */
	public function get_locale($lang = null)
	{
		// Polylang support
		if (function_exists('PLL')) {
			$lang_object = PLL()->model->get_language($lang);
			if ($lang_object && isset($lang_object->locale)) {
				return $lang_object->locale;
			}
			
		} else {

			// WPML support
			global $sitepress;
			if (is_object($sitepress) && method_exists($sitepress, 'get_locale_from_language_code')) {
				return $sitepress->get_locale_from_language_code($lang);
			}
		}

		return false;
	}

	/**
	 * Retrieves the ID of an object.
	 *
	 * @param    integer    $object_id
	 * @param    string     $object_type
	 * @param    boolean    $return_original_if_missing
	 * @param    string     $lang_code
	 * @return   integer
	 */
	public function get_object_id($object_id = null, $object_type = '', $return_original_if_missing = true, $lang_code = null)
	{
		$object_type = $object_type ?: get_post_type();
		if (!$object_type) {
			$object_type = 'post';
		}

		return apply_filters(
			'wpml_object_id',
			$object_id,
			$object_type,
			$return_original_if_missing,
			null == $lang_code ? $this->get_current_language() : $lang_code
		);
	}

	/**
	 * Translates URL.
	 *
	 * @param   string      $original_permalink
	 * @param   string      $lang
	 * @return  string
	 */
	public function url($original_permalink, $lang)
	{
		return apply_filters('wpml_permalink', $original_permalink, $lang);
	}

	/**
	 * Retrieves the language code of an object.
	 *
	 * @param    integer    $object_id
	 * @param    string     $object_type
	 * @return   string|null
	 */
	public function get_object_lang_code($object_id = null, $object_type = 'post')
	{
		return apply_filters(
			'wpml_element_language_code',
			null,
			[
				'element_id' => $object_id,
				'element_type' => $object_type
			]
		);
	}
}
PK03Y���#�#%sphere-post-views/inc/admin/admin.php<?php

namespace Sphere\PostViews\Admin;

use Sphere\PostViews\Activator;
use Sphere\PostViews\Api;
use Sphere\PostViews\Helper;
use Sphere\PostViews\Options;
use Sphere\PostViews\Plugin;

/**
 * Admin related functionality
 * 
 * @author ThemeSphere <[email protected]>
 */
class Admin
{
	/**
	 * Slug of the plugin screen.
	 *
	 * @var  string
	 */
	protected $screen_hook_suffix;

	/**
	 * Plugin options.
	 */
	protected $options;
	protected $api;

	public function __construct(Options $options, Api $api)
	{
		$this->options = $options;
		$this->api     = $api;
		
		$this->init();
	}

	/**
	 * WordPress public-facing hooks.
	 */
	public function init()
	{
		// Add plugin settings link.
		add_filter('plugin_action_links', [$this, 'add_plugin_settings_link'], 10, 2);

		if ($this->options->spv_admin_columns) {
			add_action('admin_init', [$this, 'register_columns']);
			add_action('admin_enqueue_scripts', [$this, 'register_assets']);
		}
		
		// Add admin screen
		// add_action('admin_menu', [$this, 'add_plugin_admin_menu']);
		// Delete plugin data
		// add_action('wp_ajax_wpp_clear_data', [$this, 'clear_data']);

		// Purge post data on post/page deletion.
		add_action('delete_post', [$this, 'purge_post']);
		
		// Purge old data on the scheduled cron event.
		add_action('sphere_post_views_cache', [$this, 'purge_expired_data']);

		// Hook fired when a new blog is activated on WP Multisite
		add_action('wpmu_new_blog', [$this, 'activate_new_site']);

		// Hook fired when a blog is deleted on WP Multisite.
		add_filter('wpmu_drop_tables', [$this, 'delete_site_data'], 10, 2);

		// Performance message.
		add_action('admin_init', [$this, 'performance_check']);

		add_action('admin_init', function() {
			$metabox = new MetaBox($this->options, $this->api);
			$metabox->init();
		});

		/**
		 * Old data purge schedule check.
		 */
		add_action('admin_init', function() {

			// Setup a job to delete old data if enabled.
			if ($this->options->spv_log_limit) {
				if (!wp_next_scheduled('sphere_post_views_cache')) {
					$midnight = strtotime('midnight') - (get_option('gmt_offset') * HOUR_IN_SECONDS) + DAY_IN_SECONDS;
					wp_schedule_event($midnight, 'daily', 'sphere_post_views_cache');
				}
			} else {
				// Remove the scheduled event if exists
				if ($timestamp = wp_next_scheduled('sphere_post_views_cache')) {
					wp_unschedule_event($timestamp, 'sphere_post_views_cache');
				}
			}
		});
	}

	public function register_assets($hook)
	{
		// Only need the CSS for edit.php for now.
		if (!in_array($hook, ['edit.php'])) {
			return;
		}

		wp_enqueue_style(
			'sphere-post-views-admin',
			Plugin::get_instance()->dir_url . 'assets/css/admin.css',
			[],
			Plugin::VERSION
		);
	}

	/**
	 * Register columns for admin area posts table.
	 */
	public function register_columns()
	{
		$post_types = apply_filters('sphere/post_views/post_types', ['post']);
		foreach ($post_types as $type) {
			add_filter("manage_{$type}_posts_columns", [$this, 'add_columns']);
			add_filter("manage_edit-{$type}_sortable_columns", [$this, 'add_sortable_columns']);

			add_action("manage_{$type}_posts_custom_column", [$this, 'column_views'], 10, 2);
		}
	}

	public function add_columns($columns)
	{
		$post_views = '<span>' . esc_attr__('Views', 'sphere-post-views') . '</span>';

		$insert = false;
		$insert = isset($columns['comments']) ? 'comments' : $insert;
		$insert = isset($columns['date']) ? 'date' : $insert;

		if ($insert && function_exists(('\Bunyad\Util\array_insert'))) {
			\Bunyad\Util\array_insert(
				$columns, 
				$insert,
				['post_views' => $post_views],
				'before'
			);
		}
		else {
			$columns['post_views'] = $post_views;
		}

		return $columns;
	}

	public function add_sortable_columns($columns)
	{
		$columns['post_views'] = 'post_views';
		return $columns;
	}

	public function column_views($column, $id)
	{
		if ($column !== 'post_views') {
			return;
		}

		echo esc_html(
			number_format_i18n((int) get_post()->post_views)
		);
	}

	/**
	 * Checks whether a performance tweak may be necessary.
	 */
	public function performance_check()
	{
		global $wpdb;

		if (!class_exists('\Bunyad') || !\Bunyad::admin_notices()) {
			return;
		}

		if (!current_user_can('manage_options')) {
			return;
		}

		// Check if already using optimizations.
		$optimizations = $this->options->spv_sampling && $this->options->spv_short_endpoint;
		if ($optimizations && wp_using_ext_object_cache()) {
			return;
		}

		/**
		 * Get existing status of the performance check.
		 */
		$views_count = get_transient('spv_performance_check');
		if (false === $views_count) {

			$views_count = $wpdb->get_var(
				$wpdb->prepare(
					"SELECT IFNULL(SUM(pageviews), 0) AS views FROM {$wpdb->prefix}popularpostssummary WHERE view_datetime > DATE_SUB(%s, INTERVAL 1 HOUR);",
					Helper::now()
				)
			);
			
			set_transient('spv_performance_check', (int) $views_count, DAY_IN_SECONDS);
		}

		// Not a high traffic site.
		if ($views_count <= 300) {
			return;
		}

		\Bunyad::admin_notices()->add(
			'spv-performance',
			sprintf(
				'<h4>Performance for Sphere Post Views</h4>
				<p>It seems like you have a high traffic site. Consider adding object cache and other performance tweaks: %s</p>',
				'<a href="https://theme-sphere.com/docs/smart-mag/#sphere-post-views-performance" target="_blank"> &raquo; Read About Performance</a>'
			),
			[
				'buttons' => [
					'dismiss' => true,
					'remind'  => true,
				],
				'dismiss_expiry' => 3 * MONTH_IN_SECONDS
			]
		);
	}

	/**
	 * Fired when a new blog is activated on WP Multisite.
	 *
	 * @param int $blog_id New blog ID
	 */
	public function activate_new_site($blog_id)
	{
		if (!did_action('wpmu_new_blog')) {
			return;
		}

		// run activation for the new blog
		switch_to_blog($blog_id);
		Activator::track_new_site();
		// switch back to current blog
		restore_current_blog();
	}

	/**
	 * Fired when a blog is deleted on WP Multisite.
	 *
	 * @param  array $tables
	 * @param  int   $blog_id
	 * @return array
	 */
	public function delete_site_data($tables, $blog_id)
	{
		global $wpdb;

		$tables[] = $wpdb->prefix . 'popularpostsdata';
		$tables[] = $wpdb->prefix . 'popularpostssummary';

		return $tables;
	}

	/**
	 * Register the administration menu for this plugin into the WordPress Dashboard menu.
	 */
	public function add_plugin_admin_menu()
	{
		// $this->screen_hook_suffix = add_submenu_page(
		// 	'edit.php',
		// 	'Post Views Count',
		// 	'Post Views Count',
		// 	'edit_published_posts',
		// 	'sphere_post_views_stats',
		// 	[$this, 'display_stats']
		// );
	}

	/**
	 * Registers Settings link on plugin description.
	 *
	 * @param array  $links
	 * @param string $file
	 * @return array
	 */
	public function add_plugin_settings_link($links, $file)
	{
		$plugin = plugin_basename(Plugin::get_instance()->plugin_file);

		if (!class_exists('\Bunyad') || !\Bunyad::theme()) {
			return $links;
		}

		if (is_plugin_active($plugin) && $plugin == $file) {
			array_unshift(
				$links,
				'<a href="' . admin_url('customize.php?autofocus[section]=sphere-post-views') . '">' . esc_html__('Settings') . '</a>'
			);
		}

		return $links;
	}

	/**
	 * Truncates data and cache on demand.
	 *
	 * @global object $wpdb
	 */
	public function clear_data()
	{
		$token = isset($_POST['token']) ? $_POST['token'] : null;
		$clear = isset($_POST['clear']) ? $_POST['clear'] : null;

		if (
			current_user_can('manage_options')
			&& wp_verify_nonce($token, 'wpp_nonce_reset_data')
			&& $clear
		) {
			global $wpdb;

			// set table name
			$prefix = $wpdb->prefix . "popularposts";

			if ($clear == 'cache') {
				if ($wpdb->get_var("SHOW TABLES LIKE '{$prefix}summary'")) {
					$wpdb->query("TRUNCATE TABLE {$prefix}summary;");
					echo 1;
				} else {
					echo 2;
				}
			} elseif ($clear == 'all') {
				if ($wpdb->get_var("SHOW TABLES LIKE '{$prefix}data'") && $wpdb->get_var("SHOW TABLES LIKE '{$prefix}summary'")) {
					$wpdb->query("TRUNCATE TABLE {$prefix}data;");
					$wpdb->query("TRUNCATE TABLE {$prefix}summary;");
					echo 1;
				} else {
					echo 2;
				}
			} else {
				echo 3;
			}
		} else {
			echo 4;
		}

		wp_die();
	}

	/**
	 * Purges post from data/summary tables.
	 *
	 * @global object $wpdb
	 */
	public function purge_post($post_ID)
	{
		global $wpdb;

		if ($wpdb->get_var($wpdb->prepare("SELECT postid FROM {$wpdb->prefix}popularpostsdata WHERE postid = %d", $post_ID))) {

			// Delete from data table
			$wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->prefix}popularpostsdata WHERE postid = %d;", $post_ID));
			
			// Delete from summary table
			$wpdb->query($wpdb->prepare("DELETE FROM {$wpdb->prefix}popularpostssummary WHERE postid = %d;", $post_ID));
		}
	}

	/**
	 * Purges old post data from summary table.
	 *
	 * @global object $wpdb
	 */
	public function purge_expired_data()
	{
		global $wpdb;
		
		$wpdb->query($wpdb->prepare(
			"DELETE FROM {$wpdb->prefix}popularpostssummary WHERE view_date < DATE_SUB(%s, INTERVAL %d DAY)",
			Helper::curdate(),
			intval($this->options->spv_log_expiry)
		));
	}
}
PK03Y�����(sphere-post-views/inc/admin/meta-box.php<?php

namespace Sphere\PostViews\Admin;

use Sphere\PostViews\Api;
use Sphere\PostViews\Options;

class MetaBox
{
	protected $options;
	protected $api;

	public function __construct(Options $options, Api $api)
	{
		$this->options = $options;
		$this->api = $api;
	}

	public function init()
	{
		add_action('add_meta_boxes', [$this, 'register']);
		add_action('save_post', [$this, 'save']);
	}

	public function register()
	{
		$screens = apply_filters('sphere/post_views/post_types', ['post']);
		foreach($screens as $screen) {
			add_meta_box(
				'sphere_post_views',
				esc_html__('Post Views', 'sphere-post-views'),
				[$this, 'display'],
				$screen,
				'side'
			);
		}
	}

	public function display($post)
	{
		$views = $this->api->get_views($post->ID);

		?>
		<input type="hidden" name="spv_views_current" value="<?php echo esc_attr($views); ?>" />
		<input type="number" name="spv_views" value="<?php echo esc_attr($views); ?>" />
		<p class="small">Note: Changing views will not affect 7 days or custom days popular sort.</p>
		<?php
	}

	public function save($post_id)
	{
		if (!current_user_can('edit_post', $post_id)) {
			return;
		}

		if (!isset($_POST['spv_views']) || !isset($_POST['spv_views_current'])) {
			return;
		}

		// Unchanged. We check this as it might have already changed in DB due to visits occuring after
		// the post editing started.
		if ((int) $_POST['spv_views_current'] === (int) $_POST['spv_views']) {
			return;
		}

		$this->api->update_views($post_id, intval($_POST['spv_views']));
	}
}PK03YӍb�,sphere-post-views/inc/admin/options-data.php<?php

namespace Sphere\PostViews\Admin;
use Sphere\PostViews\Plugin;

/**
 * Options data.
 */
class OptionsData
{
	const OPTIONS_KEY = 'sphere_post_views_options';
	
	public function __construct()
	{
		add_filter('bunyad_theme_options', [$this, 'customizer_options']);

		// Note: Hook after default options have been cleaned up.
		add_action('customize_save_after', [$this, 'customizer_save_options'], 11);
	}

	/**
	 * Copy the options from theme customizer to options.
	 */
	public function customizer_save_options()
	{
		if (!class_exists('\Bunyad') || !\Bunyad::options()) {
			return;
		}

		\Bunyad::options()->reinit();

		$options = \Bunyad::options()->get_all('spv_');
		update_option(self::OPTIONS_KEY, $options);
	}

	/**
	 * Add to theme customizer options.
	 *
	 * @param array $options
	 */
	public function customizer_options(array $options)
	{
		$options[] = [
			'sections' => [[
				'title'  => esc_html__('Sphere Post Views', 'sphere-post-views'),
				'id'     => 'sphere-post-views',
				'priority' => 40,
				'fields' => self::get_options(),
			]]
		];

		return $options;
	}

	public static function get_options()
	{
		$options = [];

		$options[] = [
			'name'  => 'spv_log_limit',
			'label' => esc_html__('Expire Data Log', 'sphere-post-views'),
			'desc'  => esc_html__('To reduce DB size. This does not affect total number count. Enable to set an expiry date for data used for sorting by 30 days, 90 days views etc.', 'sphere-post-views'),
			'value' => 1,
			'type'  => 'toggle',
			'style' => 'inline-sm'
		];

		$options[] = [
			'name'  => 'spv_log_expiry',
			'label' => esc_html__('Log Expiry Days', 'sphere-post-views'),
			'desc'  => esc_html__('If you only do 30 days popular sort, you can set it 30 days to keep database size low. Or even lower if just using overall views count without days limit.', 'sphere-post-views'),
			'value' => 180,
			'type'  => 'number',
			'style' => 'inline-sm',
			'context' => [['key' => 'spv_log_limit', 'value' => '', 'compare' => '!=']],
		];

		$options[] = [
			'name'  => 'spv_skip_loggedin',
			'label' => esc_html__('Skip Logged-in Users', 'sphere-post-views'),
			'desc'  => '',
			'value' => 0,
			'type'  => 'toggle',
			'style' => 'inline-sm',
		];
			
		$options[] = [
			'name'  => 'spv_repeat_count_delay',
			'label' => esc_html__('Repeat Count Delay Hours', 'sphere-post-views'),
			'desc'  => esc_html__('Minimum hours delay to re-count a repeating visitor.', 'sphere-post-views'),
			'value' => 0,
			'type'  => 'number',
			'style' => 'inline-sm',
			'input_attrs' => ['min' => 0, 'max' => 5000, 'step' => .5],
			'classes' => 'sep-bottom',
		];

		// Note: This method is called on SHORTINIT endpoint too where dir_url is unavailable.
		if (Plugin::get_instance()->dir_url !== '') {
			$endpoint_desc = sprintf(
				esc_html__('SHORTINT endpoint that may not work on all hosts. Test if %s shows Successful.', 'sphere-post-views'),
				sprintf(
					'<a href="%s" target="_blank">%s</a>',
					esc_url(Plugin::get_instance()->dir_url . 'log-view.php?test=1'),
					esc_html__('This Link', 'sphere-post-views')
				)
			);
		}

		$options[] = [
			'name'  => 'spv_short_endpoint',
			'label' => 'Performance: Alternate Endpoint',
			'desc'  => $endpoint_desc ?? '',
			'value' => 0,
			'type'  => 'toggle',
			'style' => 'inline-sm',
		];

		$options[] = [
			'name'  => 'spv_sampling',
			'label' => esc_html__('Performance: Enable Sampling', 'sphere-post-views'),
			'desc'  => 
				esc_html__('Only for very high traffic sites. Sampling will only count one visit out of every N vists and update by same N. Acccuracy will eventually be decent based on a maths formula, on high traffic sites.', 'sphere-post-views')
				. ' <a href="https://theme-sphere.com/docs/smartmag/#sphere-post-views-sampling" target="_blank">' 
				. esc_html__('Learn More', 'sphere-post-views') 
				. '</a>',
			'value' => 0,
			'type'  => 'toggle',
			'style' => 'inline-sm'
		];

		$options[] = [
			'name'  => 'spv_sampling_rate',
			'label' => esc_html__('Performance: Sampling Rate', 'sphere-post-views'),
			'desc'  => 
				esc_html__('A sampling rate of 5-25 appropriate for 10-50k visits per day, 100 for 200-300k visits per day. Lower number means more accuracy, but more server load.', 'sphere-post-views')
				. ' <a href="https://theme-sphere.com/docs/smartmag/#sphere-post-views-sampling" target="_blank">' 
				. esc_html__('Learn More', 'sphere-post-views') 
				. '</a>',
			'value' => 10,
			'type'  => 'number',
			'style' => 'inline-sm',
			'context' => [['key' => 'spv_sampling', 'value' => '', 'compare' => '!=']],
		];

		$options[] = [
			'name'  => 'spv_batch_cache',
			'label' => esc_html__('Performance: Batch Update', 'sphere-post-views'),
			'desc'  => 
				esc_html__('For very high traffic sites. If your server has Redis or Memcached (and the plugins installed), we can skip writing to database on each update. Views will be collected in redis/memcached RAM and updated every few minutes instead.', 'sphere-post-views')
				. ' <a href="https://theme-sphere.com/docs/smartmag/#sphere-post-views-batch" target="_blank">' 
				. esc_html__('Learn More', 'sphere-post-views') 
				. '</a>',
			'value' => 0,
			'type'  => 'toggle',
			'style' => 'inline-sm',
		];

		$options[] = [
			'name'  => 'spv_admin_columns',
			'label' => esc_html__('Views Column In Admin', 'sphere-post-views'),
			'desc'  => esc_html__('Show post views in the posts list table in admin.', 'sphere-post-views'),
			'value' => 1,
			'type'  => 'toggle',
			'style' => 'inline-sm',
		];

		return $options;
	}

	public static function get_all() {
		return self::get_options();
	}
}PK03Y�c^��%sphere-post-views/inc/query/query.php<?php

namespace Sphere\PostViews\Query;
use Sphere\PostViews\Helper;

/**
 * Uses and modified the WP_Query SQL to include post views.
 * 
 * @author ThemeSphere
 */
class Query
{
	protected $orderby = false;

	/**
	 * @var string[]
	 */
	protected $clauses = [];

	/**
	 * @var \WP_Query
	 */
	protected $query;

	/**
	 * Query vars set via 'views_query' => [] in original query.
	 *
	 * @var array|null
	 */
	protected $views_query = null;

	/**
	 * Whether there's a date range for post views.
	 *
	 * @var boolean
	 */
	protected $has_range = false;

	public function __construct(\WP_Query $query, $options = [])
	{
		$this->query = $query;
		$this->views_query = $this->query->query['views_query'] ?? [];

		foreach ($options as $key => $value) {
			$this->$key = $value;
		}

		$this->has_range = !empty($this->views_query['range']);
	}

	/**
	 * Modifies the WP Query to add additional sorting and post views query.
	 *
	 * @param array $clauses
	 * @param \WP_Query $query
	 * @return array
	 */
	public function modify_query(array $clauses = [], $query = null)
	{
		// Not the same query instance.
		if (!$query || $this->query !== $query) {
			return $clauses;
		}

		$this->clauses = $clauses;

		$this->do_joins();
		$this->do_fields();
		$this->do_orderby();

		return $this->clauses;
	}

	/**
	 * Add in the joins for the view query.
	 *
	 * @global object $wpdb
	 */
	public function do_joins()
	{
		global $wpdb;

		/**
		 * No range defined, fallback to all time.
		 */
		$totals_query = " LEFT JOIN `{$wpdb->prefix}popularpostsdata` spv ON spv.postid = {$wpdb->posts}.ID";
		if (!$this->has_range) {
			$this->clauses['join'] .= $totals_query;
			return;
		}

		/**
		 * Date range available.
		 * 
		 * @author Hector Cabrera
		 */
		$start_date = new \DateTime(
			Helper::now(), 
			new \DateTimeZone(Helper::get_timezone())
		);

		$time_units = ["MINUTE", "HOUR", "DAY", "WEEK", "MONTH"];

		// Valid time unit
		if (
			isset($this->views_query['time_unit'])
			&& in_array(strtoupper($this->views_query['time_unit']), $time_units)
			&& isset($this->views_query['time_quantity'])
			&& filter_var($this->views_query['time_quantity'], FILTER_VALIDATE_INT)
			&& $this->views_query['time_quantity'] > 0
		) {
			$time_quantity = $this->views_query['time_quantity'];
			$time_unit = strtoupper($this->views_query['time_unit']);

			if ('MINUTE' == $time_unit) {
				$start_date = $start_date->sub(new \DateInterval('PT' . (60 * $time_quantity) . 'S'));
				$start_datetime = $start_date->format('Y-m-d H:i:s');
				$views_time_range = "view_datetime >= '{$start_datetime}'";
			} elseif ('HOUR' == $time_unit) {
				$start_date = $start_date->sub(new \DateInterval('PT' . ((60 * $time_quantity) - 1) . 'M59S'));
				$start_datetime = $start_date->format('Y-m-d H:i:s');
				$views_time_range = "view_datetime >= '{$start_datetime}'";
			} elseif ('DAY' == $time_unit) {
				$start_date = $start_date->sub(new \DateInterval('P' . ($time_quantity - 1) . 'D'));
				$start_datetime = $start_date->format('Y-m-d');
				$views_time_range = "view_date >= '{$start_datetime}'";
			} elseif ('WEEK' == $time_unit) {
				$start_date = $start_date->sub(new \DateInterval('P' . ((7 * $time_quantity) - 1) . 'D'));
				$start_datetime = $start_date->format('Y-m-d');
				$views_time_range = "view_date >= '{$start_datetime}'";
			} else {
				$start_date = $start_date->sub(new \DateInterval('P' . ((30 * $time_quantity) - 1) . 'D'));
				$start_datetime = $start_date->format('Y-m-d');
				$views_time_range = "view_date >= '{$start_datetime}'";
			}
		} 
		// Invalid time unit, default to 30 days
		else {
			$start_date = $start_date->sub(new \DateInterval('P29D'));
			$start_datetime = $start_date->format('Y-m-d H:i:s');
			$views_time_range = "view_datetime >= '{$start_datetime}'";
		}

		$this->clauses['join'] .= " LEFT JOIN (
				SELECT SUM(pageviews) AS pageviews, postid FROM `{$wpdb->prefix}popularpostssummary` WHERE {$views_time_range} GROUP BY postid
			) spvr ON spvr.postid = {$wpdb->posts}.ID";

		// Add total view counts as well.
		if (!empty($this->views_query['add_totals'])) {
			$this->clauses['join'] .= $totals_query;
		}
	}

	/**
	 * Order posts by post views.
	 *
	 * @global object $wpdb
	 */
	public function do_orderby()
	{
		global $wpdb;

		if (!$this->orderby) {
			return;
		}

		$order = $this->query->get('order');
		$this->clauses['orderby'] = "post_views {$order}, {$wpdb->posts}.post_date {$order}";
	}

	/**
	 * Add in the post_views counter field.
	 */
	public function do_fields()
	{
		if ($this->clauses['fields']) {
			$prefix = $this->has_range ? 'spvr' : 'spv';
			$this->clauses['fields'] .=  ", COALESCE({$prefix}.pageviews, 0) AS post_views";

			if (!empty($this->views_query['add_totals'])) {
				$this->clauses['fields'] .= ', COALESCE(spv.pageviews, 0) AS total_views';
			}
		}
	}
}
PK03YER�A��%sphere-post-views/inc/query/setup.php<?php

namespace Sphere\PostViews\Query;

/**
 * Setup the query interception and modifications.
 * 
 * @author ThemeSphere
 */
class Setup
{
	public function __construct()
	{
		// Runs before pre_query.
		add_action('pre_get_posts', [$this, 'enable_admin_table_query'], 1);
		
		add_action('pre_get_posts', [$this, 'pre_query'], 1);
		add_filter('query_vars', [$this, 'query_vars']);
	}

	/**
	 * Extend query with post_views orderby parameter.
	 *
	 * @param \WP_Query $query
	 * @return void
	 */
	public function pre_query($query)
	{
		$orderby = isset($query->query_vars['orderby']) && $query->query_vars['orderby'] === 'post_views';
		
		if (!$orderby && !isset($query->query_vars['views_query'])) {
			return;
		}

		$spv_query = new Query($query, [
			'orderby' => $orderby,
		]);

		// Store the object in the query to reference later, if needed.
		$query->spv_query = $spv_query;

		// Setup the query.
		add_filter('posts_clauses', [$spv_query, 'modify_query'], 9, 2);
	}

	/**
	 * Enable for admin columns query.
	 * 
	 * @param \WP_Query $query
	 */
	public function enable_admin_table_query($query)
	{
		if (is_admin() && did_action('load-edit.php')) {
			$post_types = apply_filters('sphere/post_views/post_types', ['post']);

			// wp-admin/admin.php setups for edit.php
			$current = $GLOBALS['typenow'];

			if (in_array($current, $post_types) && !$query->get('views_query')) {
				$query->query_vars['views_query'] = [];
			}
		}
	}

	/**
	 * Register views_query var for making it accessible publicly.
	 *
	 * @param array $query_vars
	 * @return array
	 */
	public function query_vars($query_vars)
	{
		$query_vars[] = 'views_query';
		return $query_vars;
	}
}PK03YM�[�@@2sphere-post-views/mu-plugins/sphere-post-views.txt<?php
/**
 * Plugin Name: Sphere Post Views Performance
 * Description: For performance improvement of default AJAX endpoint.
 * Plugin URI: https://theme-sphere.com
 * Author: ThemeSphere
 * Author URI: https://theme-sphere.com
 * Version: 1.0.0
 * License: GPLv2 or later
 * Requires at least: 5.5
 * Requires PHP: 7.1
 */

/*
 * To Setup
 *  - Rename to sphere-posts-views.php and copy this file to wp-content/mu-plugins/
 *  - That's all.
 * 
 * Notes: 
 *  - Enabling this will disable all normal plugins on the AJAX request, so if you wish
 *    to use the filters/hooks of Sphere Post Views, you will have to create another
 *    mu-plugin of your own.
 */

defined('ABSPATH') || exit;

if (empty($_GET['sphere_post_views']) || !wp_doing_ajax()) {
	return;
}

$filter_plugins = function($plugins) {
	$plugins = (array) $plugins ?: [];
	return array_filter($plugins, function($plugin) {
		return $plugin === 'sphere-post-views/sphere-post-views.php';
	});
};

add_filter('option_active_plugins', $filter_plugins);
add_filter('site_option_active_sitewide_plugins', $filter_plugins);
PK03YsB�����sphere-post-views/log-view.phpPK03Y��66��sphere-post-views/readme.txtPK03Y5�
'���sphere-post-views/sphere-post-views.phpPK03Yz�S"�����
sphere-post-views/uninstall.phpPK03Y���44&��	sphere-post-views/assets/css/admin.cssPK03Y�C<lT
T
)���sphere-post-views/assets/js/post-views.jsPK03YR�&&#��sphere-post-views/inc/activator.phpPK03Y��9qq���%sphere-post-views/inc/api.phpPK03Y��<��$��/,sphere-post-views/inc/autoloader.phpPK03Yq�^�nn#��f;sphere-post-views/inc/container.phpPK03Y�'��

%��Csphere-post-views/inc/deactivator.phpPK03Y����"��bHsphere-post-views/inc/endpoint.phpPK03Y��Z���G^sphere-post-views/inc/front.phpPK03Y�� O�� ���dsphere-post-views/inc/helper.phpPK03YO��t��!���~sphere-post-views/inc/options.phpPK03Yi܂mII ����sphere-post-views/inc/plugin.phpPK03Yb=f_OO&��H�sphere-post-views/inc/theme-compat.phpPK03Y�8��mm#��ۗsphere-post-views/inc/translate.phpPK03Y���#�#%����sphere-post-views/inc/admin/admin.phpPK03Y�����(��O�sphere-post-views/inc/admin/meta-box.phpPK03YӍb�,����sphere-post-views/inc/admin/options-data.phpPK03Y�c^��%����sphere-post-views/inc/query/query.phpPK03YER�A��%��,�sphere-post-views/inc/query/setup.phpPK03YM�[�@@2���sphere-post-views/mu-plugins/sphere-post-views.txtPK��Downloaded From GPLAstra.com

Youez - 2016 - github.com/yon3zu
LinuXploit