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/fyntric.com/wp-content/themes/smart-mag/lib/vendor/plugins/

Upload File :
current_dir [ Writeable] document_root [ Writeable]

 

Command :


[ Back ]     

Current File : /home/redwjova/fyntric.com/wp-content/themes/smart-mag/lib/vendor/plugins/sphere-core.zip
PK03Y�Ĕ���sphere-core/sphere-core.php<?php
/**
 * Plugin Name: Sphere Core
 * Plugin URI: https://theme-sphere.com
 * Description: Core plugin for ThemeSphere themes.
 * Version: 1.6.9
 * Requires PHP: 7.0
 * Author: ThemeSphere
 * Author URI: https://theme-sphere.com
 * License: GPL2
 */

namespace Sphere\Core;

// Note: This class name will NOT change due to dependencies
class Plugin
{
	/**
	 * @since 1.0.2
	 */
	const VERSION = '1.6.9';
	
	public $components;
	public $registry;
	
	protected static $instance;

	/**
	 * Path to plugin folder, trailing slashed.
	 */
	public $path;
	public $path_url;
	
	public function __construct() 
	{
		$this->path = plugin_dir_path(__FILE__);

		// URL for the plugin dir
		$this->path_url = plugin_dir_url(__FILE__);

		add_action('bunyad_core_pre_init', array($this, 'setup'));

		/**
		 * Directory path to components
		 * @deprecated 1.1.4
		 */
		define('SPHERE_COMPONENTS', plugin_dir_path(__FILE__) . 'components/');
		define('SPHERE_LIBS_VENDOR', plugin_dir_path(__FILE__) . 'components/vendor/');

		/**
		 * Register autoloader. Usually uses the loader from theme if present.
		 */
		if (!class_exists('\Bunyad\Lib\Loader', false)) {
			require_once $this->path . 'lib/loader.php';
		}

		$loader = new \Bunyad\Lib\Loader([
			'Sphere\Core\\' => $this->path . 'components',
		]);

		require_once $this->path . 'lib/plugin-updates.php';
		new \Bunyad_Plugin_Updates;
	}
	
	/**
	 * Initialize and include the components
	 * 
	 * Note: Setup is called before after_setup_theme and Bunyad::options()->init() 
	 * at the hook bunyad_core_pre_init.
	 */
	public function setup()
	{
		/**
		 * Registered components can be filtered with a hook at bunyad_core_pre_init or in the 
		 * Bunyad::core()->init() bootstrap function via the key sphere_components.
		 */
		$this->components = apply_filters('sphere_plugin_components', array(
			'social-share', 
			'likes', 
			'social-follow',
			// 'breadcrumbs',
			// 'auto-load-post', 
			// 'adblock-detect',
			// 'elementor\layouts',
			// 'elementor\dynamic-tags'
		));
		
		foreach ($this->components as $component) {
			
			$module_name = implode('', array_map('ucfirst', explode('-', $component)));
			$class = '\Sphere\Core\\' . $module_name . '\Module';

			if (class_exists($class)) {
				
				// Use singleton or init new instance.
				$this->registry[$component] = (
					method_exists($class, 'instance')
						? $class::instance()
						: new $class
				);

				// Legacy: Aliases for legacy versions. Deprecated.
				class_alias($class, 'Sphere_Plugin_' . $module_name);
			}
		}
	}
	
	/**
	 * Static shortcut to retrieve component object from registry
	 * 
	 * @param  string $component
	 * @return object|boolean 
	 */
	public static function get($component)
	{
		$object = self::instance();
		if (isset($object->registry[$component])) {
			return $object->registry[$component];
		}
		
		return false;
	}
	
	/**
	 * Get singleton object
	 * 
	 * @return self
	 */
	public static function instance()
	{
		if (!isset(self::$instance)) {
			self::$instance = new self;
		}
		
		return self::$instance;
	}
}

// Legacy: Aliases for legacy versions. Deprecated.
class_alias('\Sphere\Core\Plugin', 'Sphere_Plugin_Core');

Plugin::instance();PK03Y���^DD0sphere-core/components/adblock-detect/module.php<?php
namespace Sphere\Core\AdblockDetect;
use Sphere\Core\Plugin;

/**
 * Adblocker Detection.
 */
class Module 
{
	protected $path_url;
	protected $path;

	public function __construct()
	{
		$this->path_url = Plugin::instance()->path_url . 'components/adblock-detect/';
		$this->path     = Plugin::instance()->path . 'components/adblock-detect/';
		
		add_action('wp', [$this, 'setup']);

		$options = new Options;
		$options->register_hooks();	
	}

	public function setup()
	{
		// Only for ThemeSphere themes.
		if (!class_exists('\Bunyad', false)) {
			return;
		}

		// Auto-load next post is disabled. The filter can return true to force enable.
		$is_enabled = apply_filters('sphere/adblock/enabled', $this->get_option('adblock_enabled'));
		if (!$is_enabled) {
			return;
		}

		add_action('wp_enqueue_scripts', [$this, 'register_assets']);
		add_action('wp_footer', [$this, 'add_modal_markup']);
		add_action('wp_footer', [$this, 'add_js']);

	}

	/**
	 * Registe frontend assets.
	 *
	 * @return void
	 */
	public function register_assets()
	{
		if (!class_exists('Bunyad_Theme_SmartMag', false)) {
			wp_enqueue_style(
				'ts_modal',
				$this->path_url . 'css/ts-modal.css',
				[],
				Plugin::VERSION
			);
		}

		wp_enqueue_style(
			'detect-modal',
			$this->path_url . 'css/modal.css',
			[],
			Plugin::VERSION
		);
	}

	/**
	 * Modal markup and configs.
	 *
	 * @return void
	 */
	public function add_modal_markup()
	{
		?>
			<div id="detect-modal" class="ts-modal detect-modal" aria-hidden="true" 
				data-delay="<?php echo esc_attr($this->get_option('adblock_delay')); ?>" 
				<?php echo ($this->get_option('adblock_no_reshow') ? ' data-no-reshow ' : ''); ?>
				data-reshow-timeout="<?php echo esc_attr($this->get_option('adblock_reshow_timeout')); ?>">
				<div class="ts-modal-overlay" tabindex="-1">
					<div class="ts-modal-container" role="dialog" aria-modal="true" aria-labelledby="detect-modal-title">
						<header class="ts-modal-header">
							<div id="detect-modal-title" class="visuallyhidden">
								<?php echo esc_html($this->get_option('adblock_title')); ?>
							</div>

							<?php if ($this->get_option('adblock_dismissable')): ?>
								<button class="close-btn" aria-label="<?php esc_attr_e('Close modal', 'bunyad'); ?>" data-micromodal-close></button>
							<?php endif; ?>
						</header>

						<div class="detect-modal-content">
							<svg class="stop-icon" width="70px" height="70px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><g id="Warning"><path id="Vector" d="M5.75 5.75L18.25 18.25M12 21C7.02944 21 3 16.9706 3 12C3 7.02944 7.02944 3 12 3C16.9706 3 21 7.02944 21 12C21 16.9706 16.9706 21 12 21Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></g></svg>
							<h5 class="heading"><?php echo esc_html($this->get_option('adblock_title')); ?></h5>
							<div class="message">
								<?php echo wp_kses_post($this->get_option('adblock_message')); ?>
							</div>

							<?php if ($this->get_option('adblock_button')): ?>
							<div class="buttons">
								<a href="<?php echo esc_attr($this->get_option('adblock_button_link')); ?>" class="ts-button" target="_blank">
									<?php echo esc_html($this->get_option('adblock_button_label')); ?>
								</a>
							</div>
							<?php endif; ?>
						</div>

					</div>
				</div>
			</div>
		<?php
	}

	/**
	 * Add JS code to the footer.
	 * Inline JS so adblocks don't block the detection script URL. 
	 * 
	 * @return void
	 */
	public function add_js()
	{
		$inline_js = file_get_contents($this->path . 'js/detect.js');

		if (!WP_DEBUG) {
			$inline_js = str_replace(["\r", "\n", "\t"], '', $inline_js);
		}

		echo '<script>' . $inline_js . '</script>';
	}

	/**
	 * Get an option from the theme customizer options if available.
	 *
	 * @param string $key
	 * @return mixed|null
	 */
	public function get_option($key)
	{
		if (class_exists('\Bunyad') && \Bunyad::options()) {
			return \Bunyad::options()->get($key);
		}

		$defaults = [
			'adblock_enabled'     => 0,
			'adblock_title'       => '',
			'adblock_message'     => '',
			'adblock_delay'       => 0,
			'adblock_dismissable' => 1,
			'adblock_no_reshow'   => 0,
			'adblock_reshow_timeout' => 24,
			'adblock_button'         => 0,
			'adblock_button_label'   => '',
			'adblock_button_link'    => ''
		];

		return isset($defaults[$key]) ? $defaults[$key] : null;
	}
}PK03YT'����1sphere-core/components/adblock-detect/options.php<?php
namespace Sphere\Core\AdblockDetect;

/**
 * Adblock Detection options.
 */
class Options
{
	public function register_hooks()
	{
		// Add relevant options
		add_filter('bunyad_theme_options', [$this, 'add_options'], 10, 2);
	}

	/**
	 * Callback: Add options to theme customizer.
	 *
	 * @param  array  $options
	 * @param  string $type
	 * @return array
	 */
	public function add_options($options, $type = 'short')
	{
		// Note: To be made translatable + localized by the theme.
		$strings = apply_filters('sphere/adblock/options_strings', [
			'title'   => 'Adblocker Detected',
			'message' => 'Please disable your Ad Blocker to continue browsing this site.',
		]);

		$fields = [
			[
				'name'    => 'adblock_enabled',
				'label'   => esc_html__('Enable Adblock Detection', 'sphere-core'),
				'desc'    => '',
				'value'   => 0,
				// 'style'   => 'inline-sm',
				'classes' => 'sep-bottom',
				'type'    => 'toggle',
			],
			[
				'name'  => 'adblock_title',
				'label' => esc_html__('Message Title', 'sphere-core'),
				'desc'  => '',
				'value' => $strings['title'],
				'type'  => 'text',
			],
			[
				'name'  => 'adblock_message',
				'label' => esc_html__('Message', 'sphere-core'),
				'desc'  => 'Basic html allowed.',
				'value' => $strings['message'],
				'type'  => 'textarea',
			],
			[
				'name'  => 'adblock_delay',
				'label' => esc_html__('Modal Delay', 'sphere-core'),
				'desc'  => '',
				'value' => 0,
				'style' => 'inline-sm',
				'type'  => 'number',
			],
			[
				'name'  => 'adblock_dismissable',
				'label' => esc_html__('Allow Dismissing Message', 'sphere-core'),
				'desc'  => '',
				'value' => 0,
				'type'  => 'toggle',
				'style' => 'inline-sm',
			],
			[
				'name'  => 'adblock_no_reshow',
				'label' => esc_html__('Dont Show After Dismissed', 'sphere-core'),
				'desc'  => '',
				'value' => 0,
				'type'  => 'toggle',
				'style' => 'inline-sm',
				'context' => [['key' => 'adblock_dismissable', 'value' => 1]]
			],
			[
				'name'  => 'adblock_reshow_timeout',
				'label' => esc_html__('Dont Show For Hours', 'sphere-core'),
				'desc'  => '',
				'value' => 24,
				'type'  => 'number',
				'style' => 'inline-sm',
				'context' => [['key' => 'adblock_no_reshow', 'value' => 1]]
			],

			[
				'name'  => 'adblock_button',
				'label' => esc_html__('Show Button', 'sphere-core'),
				'desc'  => '',
				'value' => 0,
				'type'  => 'toggle',
				'style' => 'inline-sm',
			],
			[
				'name'  => 'adblock_button_label',
				'label' => esc_html__('Button Label', 'sphere-core'),
				'desc'  => '',
				'value' => '',
				'type'  => 'text',
				'style' => 'inline-sm',
				'context' => [['key' => 'adblock_button', 'value' => 1]]
			],
			[
				'name'  => 'adblock_button_link',
				'label' => esc_html__('Button Link', 'sphere-core'),
				'desc'  => '',
				'value' => '',
				'type'  => 'text',
				'context' => [['key' => 'adblock_button', 'value' => 1]]
			],
		];

		if ($type !== 'short') {
			array_push($fields, ...[
				[
					'name'  => 'css_adblock_bg_color',
					'label' => esc_html__('Modal Background', 'sphere-core'),
					'desc'  => '',
					'value' => '',
					'type'  => 'color',
					'style' => 'inline-sm',
					'classes' => 'sep-top',
					'css'   => [
						'.detect-modal .ts-modal-container' => ['props' => ['background' => '%s']]
					]
				],
				[
					'name'  => 'css_adblock_bg_color_sd',
					'label' => esc_html__('Dark: Modal Background', 'sphere-core'),
					'desc'  => '',
					'value' => '',
					'type'  => 'color',
					'style' => 'inline-sm',
					'css'   => [
						'.s-dark .detect-modal .ts-modal-container' => ['props' => ['background' => '%s']]
					]
				],

				[
					'name'  => 'css_adblock_h_color',
					'label' => esc_html__('Heading Color', 'sphere-core'),
					'desc'  => '',
					'value' => '',
					'type'  => 'color',
					'style' => 'inline-sm',
					'css'   => [
						'.detect-modal .heading' => ['props' => ['color' => '%s']]
					]
				],
				[
					'name'  => 'css_adblock_h_color_sd',
					'label' => esc_html__('Dark: Heading Color', 'sphere-core'),
					'desc'  => '',
					'value' => '',
					'type'  => 'color',
					'style' => 'inline-sm',
					'css'   => [
						'.s-dark .detect-modal .heading' => ['props' => ['color' => '%s']]
					]
				],

				[
					'name'  => 'css_adblock_text_color',
					'label' => esc_html__('Text Color', 'sphere-core'),
					'desc'  => '',
					'value' => '',
					'type'  => 'color',
					'style' => 'inline-sm',
					'css'   => [
						'.detect-modal .message' => ['props' => ['color' => '%s']]
					]
				],
				[
					'name'  => 'css_adblock_text_color_sd',
					'label' => esc_html__('Dark: Text Color', 'sphere-core'),
					'desc'  => '',
					'value' => '',
					'type'  => 'color',
					'style' => 'inline-sm',
					'css'   => [
						'.detect-modal .message' => ['props' => ['color' => '%s']]
					]
				],

				[
					'name'  => 'css_adblock_hide_icon',
					'label' => esc_html__('Hide Icon', 'sphere-core'),
					'desc'  => '',
					'value' => 0,
					'type'  => 'toggle',
					'style' => 'inline-sm',
					'css'   => [
						'.detect-modal .stop-icon' => ['props' => ['display' => 'none']]
					]
				],

			]);
		}

		$add_options = [
			'priority' => 40,
			'sections' => [[
				'title'    => esc_html__('Ad Blocker Detection', 'sphere-core'),
				'id'       => 'sphere-adblock-detect',
				'fields'   => $fields
			]]
		];

		$options['sphere-adblock-detect'] = apply_filters('sphere/adblock/options', $add_options);
		return $options;
	}
}PK03Y�\VG3sphere-core/components/adblock-detect/css/modal.css/**
 * Detection Modal
 */
.detect-modal .ts-modal-container {
	width: 600px;
	padding: 50px 45px;
	text-align: center;
}

.detect-modal .heading {
	margin-top: 12px;
	margin-bottom: 18px;
	font-size: 28px;
	line-height: 1.3;
	font-weight: 700;
}

.detect-modal .message {
	font-size: 15px;
	margin-top: 4px;
	margin-bottom: 0;
}

.detect-modal .message p:last-child {
	margin-bottom: 0;
}

.detect-modal .stop-icon {
	color: rgb(211, 14, 14);
}

.detect-modal .buttons {
	margin-top: 22px;
	display: flex;
	justify-content: center;
}PK03Y�2n��6sphere-core/components/adblock-detect/css/ts-modal.css/**
 * ThemeSphere Modal CSS
 */
.ts-modal {
	display: none;
	position: relative;
	z-index: 10001;
}

.ts-modal.is-open {
	display: block;
}

.ts-modal-overlay {
	position: fixed;
	top: 0;
	left: 0;
	right: 0;
	bottom: 0;
	background: rgba(0, 0, 0, 0.6);
	display: flex;
	justify-content: center;
	align-items: center;
	outline: none;
}

.ts-modal[aria-hidden=false] .ts-modal-overlay {
	animation: fade-in-up-lg .3s ease-in-out;
}

.ts-modal[aria-hidden=true] .ts-modal-overlay {
	animation: fade-in .3s ease-in-out;
	animation-direction: reverse;
}

.ts-modal-container {
	position: relative;
	background-color: #fff;
	padding: 30px;
	max-width: 98vw;
	max-height: 98vh;
	border-radius: 4px;
	overflow-y: auto;
}

.ts-modal-header {
	display: flex;
}

.ts-modal .close-btn {
	position: absolute;
	top: 8px;
	right: 9px;
	padding: 10px;
	height: auto;
	line-height: 1;
	background: none;
	border: 0;
	box-shadow: none;
	color: #777;
	font-size: 1.1em;
}

.ts-modal .close-btn:hover {
	color: #000;
}

.ts-modal .close-btn:before {
	content: "\2715";
}

@keyframes fade-in-up-lg {
	from {
		opacity: 0;
		transform: translate3d(0, 8px, 0);
	}

	to {
		opacity: 1;
		transform: none;
	}
}

@keyframes fade-in {
	0% {
		opacity: 0;
	}

	100% {
		opacity: 1;
	}
}

.visuallyhidden {
	border: 0;
	clip: rect(0 0 0 0);
	height: 1px;
	margin: -1px;
	overflow: hidden;
	padding: 0;
	position: absolute;
	width: 1px;
}PK03Y�ʬDD.sphere-core/components/adblock-detect/js/ad.js"use strict";
var Bunyad_Adblock_Detect_Run = 1;
var $tieE3 = true;
PK03Y�n��	�	2sphere-core/components/adblock-detect/js/detect.js/** @copyright 2023 ThemeSphere. */
"use strict";

(function() {
	
	let theModal;
	let noReshow = 0;
	let didTest  = false;

	const STORAGE_KEY = 'detect-message-shown';

	function init() {
		document.readyState === 'complete' ? ready() : window.addEventListener('load', ready);
	}

	function ready() {
		theModal = document.querySelector('#detect-modal');
		
		const delay = parseFloat(theModal.dataset.delay);
		(delay > 0 
			? setTimeout(() => doTest(), delay*1000) 
			: doTest()
		);
	}

	function doTest() {
		const random = max => Math.floor(Math.random() * max);
	
		if (didTest) {
			return;
		}

		const testWrap = document.createElement('ins');
		const classes = [
			'adsbygoogle', 
			'ad-slot',
			random(1000)
		];

		const testStyle = 'background: transparent; z-index: -1; height: 1px; width: 0; position: absolute;';
		Object.assign(testWrap, {
			className: classes.sort(() => .5 - Math.random()).join(' '),
			style: testStyle,
			'data-ad-slot': random(10^6)
		});
		document.body.append(testWrap);

		const testWrap2 = document.createElement('div');
		document.body.append(Object.assign(
			testWrap2,
			{
				className: 'ad-250',
				style: testStyle
			}
		));

		requestAnimationFrame(() => {
			if (!testWrap.clientHeight || !testWrap2.clientHeight) {
				showModal();
			}

			testWrap.remove();
			testWrap2.remove();

			didTest = true;
		});
	}

	function toggleScroll(toggle) {
		switch (toggle) {
			case 'enable':
				Object.assign(document.body.style, { overflow: '' });
				break;
			case 'disable':
				Object.assign(document.body.style, { overflow: 'hidden' });
				break;
			default:
		}
	}

	function initModal() {
		noReshow = theModal.hasAttribute('data-no-reshow') ? 1 : 0;
	}

	function showModal() {

		initModal();

		if (noReshow) {
			const value = localStorage.getItem(STORAGE_KEY);
			if (value && value > Date.now()) {
				return;
			}
		}

		theModal.classList.toggle('is-open');
		theModal.setAttribute('aria-hidden', 'false');
		toggleScroll('disable');

		theModal.addEventListener('click', e => {
			if (e.target.hasAttribute('data-micromodal-close')) {
				closeModal();
				e.preventDefault();
			}
		});
	}

	function closeModal() {
		theModal.classList.toggle('is-open');
		theModal.setAttribute('aria-hidden', 'true');
		toggleScroll('enable');

		if (noReshow) {
			localStorage.setItem(
				STORAGE_KEY, 
				Date.now() + (parseInt(theModal.dataset.reshowTimeout) * 3600 * 1000)
			);
		}
		else {
			localStorage.removeItem(STORAGE_KEY);
		}
	}

	init();

})();PK03Y�^��AA7sphere-core/components/adblock-detect/js/micro-modal.js/* Credit: https://github.com/Ghosh/micromodal */
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self).MicroModal=t()}(this,(function(){"use strict";function e(e,t){for(var o=0;o<t.length;o++){var n=t[o];n.enumerable=n.enumerable||!1,n.configurable=!0,"value"in n&&(n.writable=!0),Object.defineProperty(e,n.key,n)}}function t(e){return function(e){if(Array.isArray(e))return o(e)}(e)||function(e){if("undefined"!=typeof Symbol&&Symbol.iterator in Object(e))return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return o(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(n);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return o(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function o(e,t){(null==t||t>e.length)&&(t=e.length);for(var o=0,n=new Array(t);o<t;o++)n[o]=e[o];return n}var n,i,a,r,s,l=(n=["a[href]","area[href]",'input:not([disabled]):not([type="hidden"]):not([aria-hidden])',"select:not([disabled]):not([aria-hidden])","textarea:not([disabled]):not([aria-hidden])","button:not([disabled]):not([aria-hidden])","iframe","object","embed","[contenteditable]",'[tabindex]:not([tabindex^="-"])'],i=function(){function o(e){var n=e.targetModal,i=e.triggers,a=void 0===i?[]:i,r=e.onShow,s=void 0===r?function(){}:r,l=e.onClose,c=void 0===l?function(){}:l,d=e.openTrigger,u=void 0===d?"data-micromodal-trigger":d,f=e.closeTrigger,h=void 0===f?"data-micromodal-close":f,v=e.openClass,m=void 0===v?"is-open":v,g=e.disableScroll,b=void 0!==g&&g,y=e.disableFocus,p=void 0!==y&&y,w=e.awaitCloseAnimation,E=void 0!==w&&w,k=e.awaitOpenAnimation,M=void 0!==k&&k,C=e.debugMode,A=void 0!==C&&C;!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,o),this.modal=document.getElementById(n),this.config={debugMode:A,disableScroll:b,openTrigger:u,closeTrigger:h,openClass:m,onShow:s,onClose:c,awaitCloseAnimation:E,awaitOpenAnimation:M,disableFocus:p},a.length>0&&this.registerTriggers.apply(this,t(a)),this.onClick=this.onClick.bind(this),this.onKeydown=this.onKeydown.bind(this)}var i,a,r;return i=o,(a=[{key:"registerTriggers",value:function(){for(var e=this,t=arguments.length,o=new Array(t),n=0;n<t;n++)o[n]=arguments[n];o.filter(Boolean).forEach((function(t){t.addEventListener("click",(function(t){return e.showModal(t)}))}))}},{key:"showModal",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;if(this.activeElement=document.activeElement,this.modal.setAttribute("aria-hidden","false"),this.modal.classList.add(this.config.openClass),this.scrollBehaviour("disable"),this.addEventListeners(),this.config.awaitOpenAnimation){var o=function t(){e.modal.removeEventListener("animationend",t,!1),e.setFocusToFirstNode()};this.modal.addEventListener("animationend",o,!1)}else this.setFocusToFirstNode();this.config.onShow(this.modal,this.activeElement,t)}},{key:"closeModal",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null,t=this.modal;if(this.modal.setAttribute("aria-hidden","true"),this.removeEventListeners(),this.scrollBehaviour("enable"),this.activeElement&&this.activeElement.focus&&this.activeElement.focus(),this.config.onClose(this.modal,this.activeElement,e),this.config.awaitCloseAnimation){var o=this.config.openClass;this.modal.addEventListener("animationend",(function e(){t.classList.remove(o),t.removeEventListener("animationend",e,!1)}),!1)}else t.classList.remove(this.config.openClass)}},{key:"closeModalById",value:function(e){this.modal=document.getElementById(e),this.modal&&this.closeModal()}},{key:"scrollBehaviour",value:function(e){if(this.config.disableScroll){var t=document.querySelector("body");switch(e){case"enable":Object.assign(t.style,{overflow:""});break;case"disable":Object.assign(t.style,{overflow:"hidden"})}}}},{key:"addEventListeners",value:function(){this.modal.addEventListener("touchstart",this.onClick),this.modal.addEventListener("click",this.onClick),document.addEventListener("keydown",this.onKeydown)}},{key:"removeEventListeners",value:function(){this.modal.removeEventListener("touchstart",this.onClick),this.modal.removeEventListener("click",this.onClick),document.removeEventListener("keydown",this.onKeydown)}},{key:"onClick",value:function(e){e.target.hasAttribute(this.config.closeTrigger)&&this.closeModal(e)}},{key:"onKeydown",value:function(e){27===e.keyCode&&this.closeModal(e),9===e.keyCode&&this.retainFocus(e)}},{key:"getFocusableNodes",value:function(){var e=this.modal.querySelectorAll(n);return Array.apply(void 0,t(e))}},{key:"setFocusToFirstNode",value:function(){var e=this;if(!this.config.disableFocus){var t=this.getFocusableNodes();if(0!==t.length){var o=t.filter((function(t){return!t.hasAttribute(e.config.closeTrigger)}));o.length>0&&o[0].focus(),0===o.length&&t[0].focus()}}}},{key:"retainFocus",value:function(e){var t=this.getFocusableNodes();if(0!==t.length)if(t=t.filter((function(e){return null!==e.offsetParent})),this.modal.contains(document.activeElement)){var o=t.indexOf(document.activeElement);e.shiftKey&&0===o&&(t[t.length-1].focus(),e.preventDefault()),!e.shiftKey&&t.length>0&&o===t.length-1&&(t[0].focus(),e.preventDefault())}else t[0].focus()}}])&&e(i.prototype,a),r&&e(i,r),o}(),a=null,r=function(e){if(!document.getElementById(e))return console.warn("MicroModal: ❗Seems like you have missed %c'".concat(e,"'"),"background-color: #f8f9fa;color: #50596c;font-weight: bold;","ID somewhere in your code. Refer example below to resolve it."),console.warn("%cExample:","background-color: #f8f9fa;color: #50596c;font-weight: bold;",'<div class="modal" id="'.concat(e,'"></div>')),!1},s=function(e,t){if(function(e){e.length<=0&&(console.warn("MicroModal: ❗Please specify at least one %c'micromodal-trigger'","background-color: #f8f9fa;color: #50596c;font-weight: bold;","data attribute."),console.warn("%cExample:","background-color: #f8f9fa;color: #50596c;font-weight: bold;",'<a href="#" data-micromodal-trigger="my-modal"></a>'))}(e),!t)return!0;for(var o in t)r(o);return!0},{init:function(e){var o=Object.assign({},{openTrigger:"data-micromodal-trigger"},e),n=t(document.querySelectorAll("[".concat(o.openTrigger,"]"))),r=function(e,t){var o=[];return e.forEach((function(e){var n=e.attributes[t].value;void 0===o[n]&&(o[n]=[]),o[n].push(e)})),o}(n,o.openTrigger);if(!0!==o.debugMode||!1!==s(n,r))for(var l in r){var c=r[l];o.targetModal=l,o.triggers=t(c),a=new i(o)}},show:function(e,t){var o=t||{};o.targetModal=e,!0===o.debugMode&&!1===r(e)||(a&&a.removeEventListeners(),(a=new i(o)).showModal())},close:function(e){e?a.closeModalById(e):a.closeModal()}});return window.MicroModal=l,l}));PK03Y��(	��0sphere-core/components/auto-load-post/module.php<?php
namespace Sphere\Core\AutoLoadPost;

use Sphere\Core\Plugin;
use Sphere\Debloat\Plugin as DebloatPlugin;

/**
 * Auto load next post.
 */
class Module 
{
	protected $path_url;

	public function __construct()
	{
		$this->path_url = Plugin::instance()->path_url . 'components/auto-load-post/';
		
		add_action('wp', [$this, 'setup']);

		$options = new Options;
		$options->register_hooks();	
	}

	public function setup()
	{
		// Only for ThemeSphere themes.
		if (!class_exists('Bunyad', false)) {
			return;
		}

		// Auto-load next post is disabled. The filter can return true to force enable.
		$is_enabled = apply_filters('sphere/alp/enabled', $this->get_option('alp_enabled'));
		if (!$is_enabled) {
			return;
		}

		$supported_types = apply_filters('sphere/alp/post_types', ['post']);
		$is_supported    = is_single() && in_array(get_post_type(), $supported_types);
		if (!$is_supported) {
			return;
		}

		// Only needed for iframe.
		// add_action('wp_head', [$this, 'add_head_js']);
		add_action('wp_enqueue_scripts', [$this, 'register_assets']);

		add_action('wp_footer', [$this, 'add_next_post_ref']);

		/**
		 * Debloat plugin compatibility for ALP. 
		 * 
		 * If remove CSS is enabled, delayed load of all CSS must also be enabled as 
		 * dynamically loaded posts may have a lot of classes missing in original CSS.
		 */
		add_action('debloat/process_markup', function() {
			$options = DebloatPlugin::options();
			if (
				$options->remove_css && 
				(!$options->delay_css_load || !in_array('posts', $options->delay_css_on))
			) {
				$options->delay_css_load = true;
				$options->delay_css_on = ['posts'];
			}
		});
	}

	/**
	 * Registe frontend assets.
	 *
	 * @return void
	 */
	public function register_assets()
	{
		// Only enqueue on single.
		if (is_single()) {
			wp_enqueue_script(
				'spc-auto-load-post',
				$this->path_url . 'js/auto-load-post.js',
				[],
				Plugin::VERSION,
				true
			);
		}
	}

	public function add_head_js()
	{
		$css_link = $this->path_url . 'css/iframe.css';

		?>
		
		<script data-cfasync="false">
			<?php // var instead of let for window.BunyadIsIframe / global context. ?>
			var BunyadIsIframe;
			(() => {
				if (location.hash && location.hash.indexOf('auto-load-post') !== -1 && self !== top) {
					BunyadIsIframe = true;
					document.documentElement.style.opacity = 0; <?php // For race-conditions where header maybe rendered first and give a flash, before iframe.css renders. ?> 
					document.head.append(
						Object.assign(document.createElement('link'), {rel: 'stylesheet', href: '<?php echo esc_url($css_link); ?>'}),
						Object.assign(document.createElement('base'), {target: '_top'})
					);
				}
			})();
		</script>

		<?php
	}

	/**
	 * Get an option from the theme customizer options if available.
	 *
	 * @param string $key
	 * @return mixed|null
	 */
	public function get_option($key)
	{
		if (class_exists('\Bunyad') && \Bunyad::options()) {
			return \Bunyad::options()->get($key);
		}

		$defaults = [
			'alp_enabled'   => 0,
			'alp_posts'     => 5,
			'alp_load_type' => 'previous',
			'alp_same_term' => false,
		];

		return isset($defaults[$key]) ? $defaults[$key] : null;
	}

	/**
	 * Add reference data for the next post.
	 *
	 * @return void
	 */
	public function add_next_post_ref()
	{
		$posts = $this->get_adjacent_posts(
			$this->get_option('alp_posts'),
			$this->get_option('alp_load_type'),
			$this->get_option('alp_same_term')
		);

		if (!$posts) {
			return;
		}

		$final_posts  = [];
		$have_gallery = false;
		foreach ($posts as $post) {
			$final_posts[] = [
				'id'    => $post->ID,
				'title' => $post->post_title,
				'url'   => get_permalink($post)
			];

			if (get_post_format($post) === 'gallery') {
				$have_gallery = true;
			}
		}

		// Add slickslider if needed and available.
		if ($have_gallery) {
			$script = \Bunyad::options()->get_config('theme_name') . '-slick';
			if (wp_script_is($script, 'registered')) {
				wp_enqueue_script($script);
			}
		}

		do_action('sphere/alp/next_post_ref', $final_posts, $posts);

		printf(
			'<script data-cfasync="false">SphereCore_AutoPosts = %s;</script>', 
			json_encode($final_posts)
		);
	}

	/**
	 * Get adjacent posts to the current post.
	 *
	 * @param integer $count Number of posts.
	 * @param string  $type  Selection type: 'previous', 'next' and 'random'.
	 * @param boolean $same_term 
	 * 
	 * @return array
	 */
	public function get_adjacent_posts($count, $type = 'previous', $same_term = false)
	{
		wp_reset_query();
		$current_post = get_queried_object();

		if (!$current_post || !$current_post->ID) {
			return;
		}

		$query_args = [
			'post_type'           => $current_post->post_type,
			'posts_per_page'      => $count,
			'no_found_rows'       => true,
			'supress_filters'     => true,
			'ignore_sticky_posts' => true
		];

		/**
		 * Additional query params based on type of posts needed.
		 */
		if ($type !== 'random') {
			$adjacent = $type === 'previous' ? 'before' : 'after';
			$query_args += [
				'date_query' => [
					[
						$adjacent   => $current_post->post_date,
						'inclusive' => false
					]
				],

				// For previous posts, order by date desc. asc for next.
				'order' => $adjacent === 'before' ? 'DESC' : 'ASC'
			];
		}
		else {
			$query_args += [
				'orderby'      => 'rand',
				'post__not_in' => [$current_post->ID],
			];
		}

		/**
		 * Posts from the same term.
		 */
		if ($same_term) {

			$terms = wp_get_post_terms($current_post->ID, 'category', ['fields' => 'ids']);
			if ($terms) {
				$query_args['tax_query'] = [
					[
						'taxonomy' => 'category',
						'field'    => 'term_id',
						'terms'    => $terms
					]
				];
			}
		}

		$posts = get_posts(
			apply_filters('sphere/alp/posts_query_args', $query_args)
		);

		return $posts;
	}
}PK03Y�b��1sphere-core/components/auto-load-post/options.php<?php
namespace Sphere\Core\AutoLoadPost;

/**
 * Autoload post options.
 */
class Options
{
	public function register_hooks()
	{
		// Add relevant options
		add_filter('bunyad_theme_options', [$this, 'add_options']);
	}

	/**
	 * Callback: Add options to theme customizer.
	 *
	 * @param  array $options
	 * @return array
	 */
	public function add_options($options)
	{
		$add_options = [
			'priority' => 40,
			'sections' => [[
				'title'    => esc_html__('Auto-load Next Post', 'sphere-core'),
				'id'       => 'sphere-auto-load-post',
				'fields' => [
					[
						'name'    => 'alp_enabled',
						'label'   => esc_html__('Enable Auto-load Posts', 'sphere-core'),
						'desc'    => esc_html__('Activate the auto-load post on scroll for single post pages.', 'sphere-core'),
						'value'   => 0,
						'classes' => 'sep-bottom',
						'type'    => 'toggle',
					],
					[
						'name'  => 'alp_posts',
						'label' => esc_html__('Number of Posts', 'sphere-core'),
						'desc'  => esc_html__('Max number of posts to auto-load on scroll.', 'sphere-core'),
						'value' => 6,
						'type'  => 'number',
						'input_attrs' => ['min' => 1, 'max' => 25],
					],
					[
						'name'  => 'alp_load_type',
						'label' => esc_html__('Load Type', 'sphere-core'),
						'desc'  => '',
						'value' => 'previous',
						'type'  => 'radio',
						'options' => [
							'previous' => esc_html__('Previous By Date', 'sphere-core'),
							'next'     => esc_html__('Next By Date', 'sphere-core'),
							'random'   => esc_html_x('Random', 'sphere-core'),
						]
					],
					[
						'name'  => 'alp_same_term',
						'label' => esc_html__('From Same Category', 'sphere-core'),
						'desc'  => esc_html__('Select posts from same category(s) only as the original post.', 'sphere-core'),
						'value' => 0,
						'type'  => 'toggle',
					],
				]
			]]
		];

		$options['sphere-auto-load-post'] = apply_filters('sphere/alp/options', $add_options);
		return $options;
	}
}PK03Y���PVV:sphere-core/components/auto-load-post/js/auto-load-post.js/**
 * Auto load post module front-end JS.
 * 
 * @copyright 2022 ThemeSphere.
 */
"use strict";

(function() {
	// Percentage reading to trigger the next.
	const TRIGGER_NEXT_FACTOR = 0.65;

	/** @type {!Array<Object>} */
	let postsToLoad = [];

	/** @type {HTMLElement} */
	let mainPostElement;

	/** @type {IntersectionObserver} */
	let inViewObserver;

	/**
	 * States and current refs.
	 */
	let isLoading = false;

	// All the loaded posts elements.
	let postElements = [];
	
	// Latest loaded post element.
	let postElement;

	/**
	 * Set up.
	 */
	function init() {
		// Set posts on ready.
		callOnReady(setup);
	}

	/**
	 * Setup events. Should be called after DOMContentLoaded.
	 */
	function setup() {

		if (typeof SphereCore_AutoPosts === 'undefined' || !window.fetch) {
			return;
		}
		
		postsToLoad     = SphereCore_AutoPosts;
		postElement     = document.querySelector('.main');
		mainPostElement = postElement;
		
		postElements.push(mainPostElement);

		if (!mainPostElement) {
			return;
		}

		Object.assign(mainPostElement.dataset, {
			title: document.title,
			url: window.location.href
		});

		document.addEventListener('scroll', () => {

			// isLoading is false once iframe is inserted but iframe's dataset.loading
			// is empty only once onload event has fired (on full load).
			if (isLoading || postElement.dataset.loading) {
				return;
			}

			let triggerLoad = postElement.offsetTop + (postElement.offsetHeight * TRIGGER_NEXT_FACTOR);
			if (window.scrollY > triggerLoad) {
				isLoading = true;
				requestAnimationFrame(loadPost);
			}
		});

		inViewObserver = new IntersectionObserver(observePostsInView, {
			root: null,
			rootMargin: '0px 0px -50%',
			threshold: 0
		});
	}

	/**
	 * Observe posts entering the viewport and update URL etc.
	 * 
	 * @param {Array} entries 
	 */
	function observePostsInView(entries) {

		let thePost;

		// Current visible post, that will be inactivated, if any.
		let currentPost;

		for (let element of entries) {
			if (element.intersectionRatio <= 0) {
				currentPost = element.target;
				continue;
			}
			
			thePost = element.target;
			break;
		}

		// Revert to previous post if available.
		if (!thePost) {
			const index    = postElements.findIndex(post => post === currentPost);
			const prevPost = postElements[index - 1];

			if (prevPost && prevPost.getBoundingClientRect().bottom >= 0) {
				thePost = prevPost;
			}
		}

		if (thePost && thePost.dataset.url) {
			window.history.pushState(null, thePost.dataset.title, thePost.dataset.url);
			document.title = thePost.dataset.title;

			sendPageView();
		}
	}

	/**
	 * Add a loader before the current post element/iframe.
	 */
	function addLoader(target) {

		target = target || postElement;
		const loader = document.createElement('div');
		Object.assign(loader, {
			className: 'spc-alp-loader ts-spinner'
		});

		target.after(loader);
	}

	/**
	 * Load the next post.
	 */
	function loadPost() {
		const post = postsToLoad.shift();

		if (!post) {
			return;
		}

		// Loading for the first time, add class to main element.
		if (mainPostElement === postElement) {
			mainPostElement.classList.add('spc-alp-main');
		}

		const addPostContainer = (html) => {
			if (!html) {
				return;
			}

			const parser = new DOMParser();
			const doc    = parser.parseFromString(html, 'text/html');
			
			// Get the post content.
			const content  = doc.querySelector('.main-wrap > .main');
			if (!content) {
				return;
			}

			const container = document.createElement('div');
			postElement.after(container);

			Object.assign(container.dataset, {
				url: post.url,
				title: post.title,
				id: post.id
				// loading: '1'
			});

			Object.assign(container, {
				id: `spc-alp-${post.id}`,
				className: 'spc-auto-load-post',
				innerHTML: content.outerHTML
			});

			postElement = container;
			postElements.push(container);

			return container;
		};
		
		addLoader();

		fetch(post.url)
			.then(resp => resp.text())
			.then(html => {
				const container = addPostContainer(html);

				// Remove loader.
				document.querySelectorAll('.spc-alp-loader').forEach(e => e.remove());	

				if (!container) {
					return;
				}
				
				executeScripts(container);

				// Reload twitter embeds.
				if (window.twttr && twttr.widgets && twttr.widgets.load) {
					twttr.widgets.load();
				}

				requestAnimationFrame(() => {
					isLoading = false;

					// Ensure visibility.
					ensureVisible(container);

					// Add to observers after visibility.
					inViewObserver.observe(container);

					document.dispatchEvent(new Event('spc-alp-loaded'));

					// Do the theme reinit functions.
					const theme = Bunyad.theme || Bunyad_Theme;
					if (theme.reInit) {
						theme.reInit(container);
					}
				});
			});
	}

	/**
	 * Execute script tags for content added via innerHTML.
	 * 
	 * @param {HTMLElement} element 
	 */
	function executeScripts(element) {
		let debloatDelay;

		element.querySelectorAll('script').forEach(item => {
			const script = document.createElement('script');
			script.text = item.textContent;
	
			// Set attributes.
			const attrs = item.attributes;
			for (const attr of attrs) {
				script.setAttribute(attr.name, attr.value || true);
			}

			// Lazy / delay loads.
			if (script.type && ['rocketlazyloadscript', 'text/debloat-script', '/javascript'].includes(script.type)) {
				script.type = 'text/javascript';
			}

			if (script.dataset.debloatDelay) {
				debloatDelay = true;
			}

			if (!script.src && script.dataset.src) {
				script.src = script.dataset.src;
			}
			
			document.body.append(script);
		});

		if (debloatDelay) {
			document.dispatchEvent(new Event('debloat-load-js'));
		}
	}

	/**
	 * Ensure the post element is visible, if at end of the page.
	 * 
	 * @param {HTMLElement} postElement 
	 */
	function ensureVisible(postElement) {

		// Scroll to post if at footer / almost end of page.
		const doc = document.documentElement;
		if (doc.scrollHeight - doc.scrollTop <= doc.clientHeight + 75) {
			if (Bunyad.theme) {
				Bunyad.theme.stickyBarPause = true;
				setTimeout(() => Bunyad.theme.stickyBarPause = false, 5);
			}

			postElement.scrollIntoView();
		}
	}

	/**
	 * Send a pageview to analytics - should be called when post is visible.
	 */
	function sendPageView() {
		if (!postElement || postElement.dataset.viewTracked) {
			return;
		}

		// New Google Tag
		if (window.gtag) {
			window.gtag('event', 'page_view', {
				page_title: postElement.dataset.title,
				page_location: postElement.dataset.url
			});
		}

		// Analytics.js
		if (window.ga) {
			window.ga('send', 'pageview', postElement.dataset.url);
		}

		document.dispatchEvent(
			new CustomEvent('spc-alp-pageview', {
				detail: {
					id: postElement.dataset.id,
					ele: postElement
				}
			})
		);

		postElement.dataset.viewTracked = 1;
	}

	function callOnReady(cb) {
		document.readyState !== 'loading' 
			? cb() 
			: document.addEventListener('DOMContentLoaded', cb);
	}

	init();

})();PK03Y��l�OO0sphere-core/components/breadcrumbs/generator.php<?php
namespace Sphere\Core\Breadcrumbs;

/**
 * Generate the breadcrumbs trail.
 * 
 * Originally based on WooCommerce breadcrumbs.
 */
class Generator 
{
	protected $crumbs = [];
	protected $primary_cat_callback;
	protected $labels = [];

	public function __construct($args = [])
	{
		foreach ($args as $option => $value) {
			if (property_exists($this, $option)) {
				$this->{$option} = $value;
			}
		}
	}

	/**
	 * Generate breadcrumb trail.
	 *
	 * @return array of breadcrumbs
	 */
	public function generate()
	{
		// Doesn't make sense to have it for home.
		if (is_home() || is_front_page()) {
			return;
		}

		// Add homepage trail always. 
		$this->add_crumb(
			$this->labels['home'],
			home_url('/')
		);

		$conditionals = array(
			'is_404',
			'is_attachment',
			'is_single',
			'is_page',
			'is_post_type_archive',
			'is_category',
			'is_tag',
			'is_author',
			'is_date',
			'is_tax',
		);

		foreach ($conditionals as $conditional) {
			if (call_user_func($conditional)) {
				call_user_func([
					$this, 
					'add_crumbs_' . substr($conditional, 3)
				]);
				break;
			}
		}

		$this->search_trail();
		$this->paged_trail();

		return $this->get_breadcrumb();
	}

	/**
	 * Add a crumb so we don't get lost.
	 *
	 * @param string $name Text.
	 * @param string $link Link.
	 * @param array  $extras
	 */
	public function add_crumb($name, $link = '', $extras = [])
	{
		$this->crumbs[] = array_replace([
			'text' => wp_strip_all_tags($name),
			'url'  => $link,
		], $extras);
	}

	/**
	 * Reset crumbs.
	 */
	public function reset()
	{
		$this->crumbs = array();
	}

	/**
	 * Get the breadcrumb.
	 *
	 * @return array
	 */
	public function get_breadcrumb()
	{
		return apply_filters('sphere_breadcrumbs_get', $this->crumbs, $this);
	}

	/**
	 * 404 trail.
	 */
	protected function add_crumbs_404()
	{
		$this->add_crumb($this->labels['404']);
	}

	/**
	 * Attachment trail.
	 */
	protected function add_crumbs_attachment()
	{
		global $post;

		$this->add_crumbs_single($post->post_parent, get_permalink($post->post_parent));
		$this->add_crumb(get_the_title(), get_permalink());
	}

	/**
	 * Single post trail.
	 *
	 * @param int    $post_id   Post ID.
	 * @param string $permalink Post permalink.
	 */
	protected function add_crumbs_single($post_id = null, $permalink = '')
	{
		$post = get_post($post_id);

		if (!$permalink) {
			$permalink = get_permalink($post);
		}

		if ('post' !== get_post_type($post)) {
			$post_type = get_post_type_object(get_post_type($post));

			if (!empty($post_type->has_archive)) {
				$this->add_crumb(
					$post_type->labels->singular_name, 
					get_post_type_archive_link(get_post_type($post))
				);
			}
		} 
		else {
			$cat = $this->get_primary_cat($post_id);
			if ($cat) {
				$this->term_ancestors($cat->term_id, 'category');
				$this->add_crumb($cat->name, get_term_link($cat));
			}
		}

		$this->add_crumb(get_the_title($post), $permalink);
	}

	/**
	 * Page trail.
	 */
	protected function add_crumbs_page()
	{
		$post = get_post();

		if ($post->post_parent) {
			$parent_crumbs = array();
			$parent_id     = $post->post_parent;

			while ($parent_id) {
				$page            = get_post($parent_id);
				$parent_id       = $page->post_parent;
				$parent_crumbs[] = array(
					get_the_title($page->ID), 
					get_permalink($page->ID)
				);
			}

			$parent_crumbs = array_reverse($parent_crumbs);

			foreach ($parent_crumbs as $crumb) {
				$this->add_crumb($crumb[0], $crumb[1]);
			}
		}

		$this->add_crumb(get_the_title(), get_permalink());
	}

	/**
	 * Post type archive trail.
	 */
	protected function add_crumbs_post_type_archive($type = null)
	{
		$type = $type ? $type : get_post_type();
		$post_type = get_post_type_object($type);

		if ($post_type) {
			$this->add_crumb($post_type->labels->name, get_post_type_archive_link($type));
		}
	}

	/**
	 * Category trail.
	 */
	protected function add_crumbs_category()
	{
		$this_category = get_category($this->get_current_object());

		if (0 !== intval($this_category->parent)) {
			$this->term_ancestors($this_category->term_id, 'category');
		}

		$this->add_crumb(
			sprintf($this->labels['category'], single_term_title('', false)),
			get_category_link($this_category->term_id)
		);
	}

	/**
	 * Tag trail.
	 */
	protected function add_crumbs_tag()
	{
		$queried_object = $this->get_current_object();

		$this->add_crumb(
			sprintf(
				$this->labels['tag'], 
				single_tag_title('', false)
			),
			get_tag_link($queried_object->term_id)
		);
	}

	/**
	 * Add crumbs for date based archives.
	 */
	protected function add_crumbs_date()
	{
		if (is_year() || is_month() || is_day()) {
			$this->add_crumb(
				get_the_time('Y'), 
				get_year_link(get_the_time('Y'))
			);
		}
		if (is_month() || is_day()) {
			$this->add_crumb(
				get_the_time('F'), 
				get_month_link(get_the_time('Y'), get_the_time('m'))
			);
		}
		if (is_day()) {
			$this->add_crumb(get_the_time('d'));
		}
	}

	/**
	 * Add crumbs for taxonomies
	 */
	protected function add_crumbs_tax()
	{
		$this_term  = $this->get_current_object();
		$taxonomy   = get_taxonomy($this_term->taxonomy);

		// Add a parent Custom Post Type if it exists.
		$post_types = array_diff($taxonomy->object_type, ['post', 'page', 'attachment', 'nav_menu_item', 'revision']);
		if (count($post_types)) {
			$this->add_crumbs_post_type_archive($post_types[0]);
		}

		// $this->add_crumb($taxonomy->labels->name);

		if (0 !== intval($this_term->parent)) {
			$this->term_ancestors($this_term->term_id, $this_term->taxonomy);
		}

		$this->add_crumb(
			sprintf($this->labels['tax'], single_term_title('', false)), 
			get_term_link($this_term->term_id, $this_term->taxonomy)
		);
	}

	/**
	 * Add a breadcrumb for author archives.
	 */
	protected function add_crumbs_author()
	{
		global $author;

		$userdata = get_userdata($author);

		$this->add_crumb(sprintf(
			$this->labels['author'], 
			$userdata->display_name
		));
	}

	/**
	 * Add crumbs for a term.
	 *
	 * @param int    $term_id  Term ID.
	 * @param string $taxonomy Taxonomy.
	 */
	protected function term_ancestors($term_id, $taxonomy)
	{
		$ancestors = get_ancestors($term_id, $taxonomy);
		$ancestors = array_reverse($ancestors);

		foreach ($ancestors as $ancestor) {
			$ancestor = get_term($ancestor, $taxonomy);

			if (!is_wp_error($ancestor) && $ancestor) {
				$this->add_crumb($ancestor->name, get_term_link($ancestor));
			}
		}
	}

	/**
	 * Add a breadcrumb for search results.
	 */
	protected function search_trail()
	{
		if (is_search()) {
			$this->add_crumb(
				sprintf(
					$this->labels['search'], 
					get_search_query()
				),
				remove_query_arg('paged')
			);
		}
	}

	/**
	 * Add a breadcrumb for pagination.
	 */
	protected function paged_trail()
	{
		if (get_query_var('paged')) {

			$last         = array_pop($this->crumbs);
			$last['text'] .= sprintf(
				$this->labels['paged'],
				get_query_var('paged')
			);

			array_push($this->crumbs, $last);
		}
	}

	// --------------------

	/**
	 * Get primary category for the post. 
	 *
	 * @param int $post_id
	 * @return void
	 */
	protected function get_primary_cat($post_id = null)
	{
		if (isset($this->primary_cat_callback)) {
			return call_user_func($this->primary_cat_callback, $post_id);
		}

		return current(get_the_category($post_id));
	}

	/**
	 * Return current global queried object (taxonomy, post, page etc.)
	 *
	 * @return object
	 */
	protected function get_current_object()
	{
		return $GLOBALS['wp_query']->get_queried_object();
	}
}PK03Yv�O���-sphere-core/components/breadcrumbs/module.php<?php
namespace Sphere\Core\Breadcrumbs;

/**
 * Breadcrumbs trail.
 */
class Module
{
	protected $labels = [];

	/**
	 * Initialize can be with options specified.
	 *
	 * @param array $args
	 */
	public function __construct()
	{
		$this->labels = [
			'home'     => esc_html_x('Home', 'breadcrumbs', 'sphere-core'), // text for the 'Home' link
			'category' => esc_html_x('Category: "%s"', 'breadcrumbs', 'sphere-core'), // text for a category page
			'tax'      => esc_html_x('Archive for "%s"', 'breadcrumbs', 'sphere-core'), // text for a taxonomy page
			'search'   => esc_html_x('Search Results for "%s"', 'breadcrumbs', 'sphere-core'), // text for a search results page
			'tag'      => esc_html_x('Posts Tagged "%s"', 'breadcrumbs', 'sphere-core'), // text for a tag page
			'404'      => esc_html_x('Error 404', 'breadcrumbs', 'sphere-core'), // text for the 404 page
			'author'   => esc_html_x('Author: %s', 'breadcrumbs', 'sphere-core'), // text for an author page
			'paged'    => esc_html_x(' (Page %d)', 'breadcrumbs', 'sphere-core'), // appended to paged.
		];
	}

	/**
	 * Output the breadcrumbs.
	 * 
	 * @param array $options
	 * @return void
	 */
	public function render($options = array()) 
	{	
		$defaults = array(
			'before'         => '<nav class="breadcrumbs">',
			'after'          => '</nav>',
			'delimiter'      => '<span class="delim">&raquo;</span>',
			'current_before' => '<span class="current">',
			'current_after'  => '</span>',
			'home_link'      => home_url() . '/',
			'show_current'   => true,

			// Whether to show current item on single page.
			'show_current_single' => true,

			// Callback for getting primary category.
			'primary_cat_callback' => null,

			'link_before'    => '<span>',
			'link_after'     => '</span>',
			'link_in_before' => '<span>',
			'link_in_after'  => '</span>',
			'disable_at'     => []
		);
		
		extract(
			apply_filters('sphere_breadcrumbs_defaults', $defaults)
		);

		require_once SPHERE_COMPONENTS . '/breadcrumbs/schema.php';
		require_once SPHERE_COMPONENTS . '/breadcrumbs/generator.php';

		// Form whole link option.
		$link = '<a href="%1$s">' . $link_in_before . '%2$s' . $link_in_after . '</a>';
		$link = $link_before . $link . $link_after;

		if (isset($options['labels'])) {
			$this->labels = array_replace($this->labels, (array) $options['labels']);
		}

		// This is final before render. Options already applied.
		$this->labels = apply_filters('sphere_breadcrumbs_labels', $this->labels);

		$options = array_replace($defaults, $options);

		// Check if breadcrumbs are disabled at this location.
		foreach ($options['disable_at'] as $check) {
			$checker = 'is_' . $check;
			if (call_user_func($checker)) {
				return;
			}
		}
				
		/**
		 * Use bbPress's breadcrumbs when available
		 */
		if (function_exists('bbp_breadcrumb') && is_bbpress()) {
						
			$bbp_crumbs = 
				bbp_get_breadcrumb(array(
					'home_text'      => $this->labels['home'],
					'sep'            => $options['delimiter'],
					'sep_before'     => '',
					'sep_after'      => '',
					'pad_sep'        => 0,
					'before'         => $options['before'],
					'after'          => $options['after'],
					'current_before' => $options['current_before'],
					'current_after'  => $options['current_after'],
				));
			
			if ($bbp_crumbs) {
				echo $bbp_crumbs;
				return;
			}
		}
		
		/**
		 * Use WooCommerce's breadcrumbs when available
		 */
		if (function_exists('woocommerce_breadcrumb') && (is_woocommerce() || is_cart() || is_shop())) {

			add_filter('woocommerce_get_breadcrumb', [$this, 'add_shop_woocommerce']);

			woocommerce_breadcrumb(array(
				'delimiter'   => $options['delimiter'],
				'before'      => '',
				'after'       => '',
				'wrap_before' => $options['before'],
				'wrap_after'  => $options['after'],
				'home'        => $this->labels['home'],
			));

			return;
		}
		
		// Show on homepage?
		if (is_home() || is_front_page()) {
			return;
		}

		$breadcrumbs = new Generator([
			'labels' => $this->labels,
			'primary_cat_callback' => $options['primary_cat_callback']
		]);

		$crumbs = $breadcrumbs->generate();

		// Start the output.
		$items  = count($crumbs);
		$count  = 0;
		$output = [];

		$show_current = $options['show_current'];
		if (is_single() && !$options['show_current_single']) {
			$show_current = false;
		}

		foreach ($crumbs as $crumb) {
			$count++;

			// Last item.
			$is_last = $count === $items;
			
			if ($is_last) {
				if ($show_current) {
					$output[] = $options['current_before'] . esc_html($crumb['text']) . $options['current_after'];
				}
				break;
			}

			$output[] = sprintf($link, esc_url($crumb['url']), esc_html($crumb['text']));
		}

		// Safe output generated above.
		echo $options['before']
			. join($options['delimiter'], $output)
			. $options['after'];

		// Setup JSON+LD to be output.
		add_action('wp_footer', function() use ($crumbs) {
			$schema = new Schema($crumbs);
			$schema->render();
		});
	}

	/**
	 * Callback: Add WooCommerce shop link.
	 */
	public function add_shop_woocommerce($crumbs) 
	{
		$permalinks   = wc_get_permalink_structure();
		$shop_page_id = wc_get_page_id('shop');
		$shop_page    = get_post( $shop_page_id );

		// If currently at shop, or home is same as shop page, do nothing.
		if (is_shop() || !$shop_page || intval(get_option('page_on_front')) == $shop_page_id) {
			return $crumbs;
		}

		// Opposite test. If WC didn't append the shop page to the crumbs.
		if (
			!isset($permalinks['product_base']) 
			|| !strstr($permalinks['product_base'], '/' . $shop_page->post_name) 
		) {
			$crumb = [
				wp_strip_all_tags(get_the_title($shop_page)), 
				get_permalink($shop_page) 
			];
			
			$first = array_shift($crumbs);
			array_unshift($crumbs, $first, $crumb);
		}

		return $crumbs;
	}
}PK03Y�zB���-sphere-core/components/breadcrumbs/schema.php<?php
namespace Sphere\Core\Breadcrumbs;
/**
 * Generate JSON+LD schema for breadcrumbs.
 */
class Schema 
{
	/**
	 * Breadcrumbs to use
	 *
	 * @var array
	 */
	public $crumbs = [];

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

	/**
	 * Output breadcrumbs schema data.
	 *
	 * @return void
	 */
	public function render()
	{
		foreach ($this->crumbs as $index => $item) {

			// Both text and URL are needed for schema.
			if (empty($item['text']) || empty($item['url'])) {
				continue;
			}

			$items[] = [
				'@type'    => 'ListItem',
				'position' => ($index + 1),

				// Consistent with how Yoast does it.
				'item'     => [
					'@type' => 'WebPage',
					'@id'   => $item['url'],
					'name'  => $item['text'],
				]

				// This can also be used instead of item above, for brevity. Google's example
				// uses this way, but it differs from the schema.org definition.
				// 'name'  => $item['text'],
				// 'item'  => $item['url'],
			];
		}

		$schema = [
			'@context'        => 'https://schema.org',
			'@type'           => 'BreadcrumbList',
			'itemListElement' => $items,
		];

		echo '<script type="application/ld+json">' . json_encode($schema) . "</script>\n";
	}
}PK03YV�B���8sphere-core/components/elementor/dynamic-tags/module.php<?php

namespace Sphere\Core\Elementor\DynamicTags;

use Elementor\Plugin;

/**
 * Our custom dynamic tags for Elementor.
 */
class Module
{
	public $path;
	public $path_url;

	/**
	 * Types of custom layouts.
	 *
	 * @var array
	 */
	public $types = [];

	protected $groups_registered = false;
	
	protected static $instance;

	public function __construct()
	{
		// Register CPT whether elementor exists or not, mainly for import.
		add_action('elementor/dynamic_tags/register', [$this, 'register_tags']);

		// Elementor plugin missing.
		if (!did_action('elementor/loaded')) {
			return;
		}

		$this->path = \Sphere\Core\Plugin::instance()->path . 'components/elementor/layouts/';
		$this->path_url = \Sphere\Core\Plugin::instance()->path_url . 'components/elementor/layouts/';
	}

	public function register_tags($dynamic_tags)
	{
		$this->register_groups();
		
		$tags = [
			'ArchiveTitle',
			'Copyright',
		];

		// These are very similar to Elementor Pro, so skip in pro.
		if (!defined('ELEMENTOR_PRO_VERSION')) {
			array_push($tags, ...[
				'ArchiveDescription',
				'AuthorName',
				'SiteUrl',
			]);
		}

		foreach ($tags as $tag_class) {
			$class = __NAMESPACE__ . '\Tags\\' . $tag_class;
			$dynamic_tags->register(new $class);
		}
	}

	public function get_groups()
	{
		if (defined('ELEMENTOR_PRO_VERSION')) {
			return [];
		}

		return [
			'site' => [
				'title' => 'Site',
			],
			'archive' => [
				'title' => 'Archive',
			],
			'author' => [
				'title' => 'Author',
			]
		];
	}
	
	public function register_groups()
	{
		if ($this->groups_registered) {
			return;
		}

		foreach ($this->get_groups() as $group => $settings) {
			Plugin::instance()->dynamic_tags->register_group($group, $settings);
		}
	}
	/**
	 * Get singleton object
	 * 
	 * @return self
	 */
	public static function instance()
	{
		if (!isset(self::$instance)) {
			self::$instance = new self;
		}
		
		return self::$instance;
	}
}PK03Y%Qa>>Jsphere-core/components/elementor/dynamic-tags/tags/archive-description.php<?php

namespace Sphere\Core\Elementor\DynamicTags\Tags;

use Elementor\Core\DynamicTags\Tag;
use Elementor\Modules\DynamicTags\Module as TagsModule;

class ArchiveDescription extends Tag
{
	public function get_name() 
	{
		return 'archive-description';
	}

	public function get_title()
	{
		return esc_html__('Archive Description', 'sphere-core');
	}

	public function get_group()
	{
		return 'archive';
	}

	public function get_categories()
	{
		return [TagsModule::TEXT_CATEGORY];
	}

	public function render()
	{
		echo wp_kses_post(get_the_archive_description());
	}	
}PK03Y�YttDsphere-core/components/elementor/dynamic-tags/tags/archive-title.php<?php

namespace Sphere\Core\Elementor\DynamicTags\Tags;

use Elementor\Controls_Manager;
use Elementor\Core\DynamicTags\Tag;
use Elementor\Modules\DynamicTags\Module as TagsModule;

class ArchiveTitle extends Tag
{
	public function get_name() 
	{
		return 'archive-title';
	}

	public function get_title()
	{
		return esc_html__('Archive Title', 'sphere-core');
	}

	public function get_group()
	{
		return 'archive';
	}

	public function get_categories()
	{
		return [TagsModule::TEXT_CATEGORY];
	}

	public function render() 
	{
		$include_context = 'yes' === $this->get_settings('include_context');

		if ($include_context) {
			$title = \Bunyad::archives() ? \Bunyad::archives()->get_heading() : get_the_archive_title();
		}
		else {
			add_filter('get_the_archive_title_prefix', '__return_empty_string');
			$title = get_the_archive_title();
			remove_filter('get_the_archive_title_prefix', '__return_empty_string');
		}

		// Fix for archive preview sample titles.
		if ($title === 'Sample Title') {
			if ($include_context && strpos($title, ':') === false) {
				$title = 'Browsing: <span>' . $title . '</span>';
			}
		}

		echo wp_kses_post($title);
	}

	protected function register_controls() {
		$this->add_control(
			'include_context',
			[
				'label' => esc_html__('Include Context', 'sphere-core'),
				'type' => Controls_Manager::SWITCHER,
				'default' => 'yes',
			]
		);
	}
}PK03YBsphere-core/components/elementor/dynamic-tags/tags/author-meta.phpPK03YRi0�Bsphere-core/components/elementor/dynamic-tags/tags/author-name.php<?php

namespace Sphere\Core\Elementor\DynamicTags\Tags;

use Elementor\Core\DynamicTags\Tag;
use Elementor\Modules\DynamicTags\Module as TagsModule;

class AuthorName extends Tag
{
	public function get_name() 
	{
		return 'author-name';
	}

	public function get_title()
	{
		return esc_html__('Author Name', 'sphere-core');
	}

	public function get_group()
	{
		return 'author';
	}

	public function get_categories()
	{
		return [TagsModule::TEXT_CATEGORY];
	}

	public function render()
	{
		echo wp_kses_post(get_the_author());
	}	
}PK03Y����@sphere-core/components/elementor/dynamic-tags/tags/copyright.php<?php

namespace Sphere\Core\Elementor\DynamicTags\Tags;

use Elementor\Core\DynamicTags\Tag;
use Elementor\Modules\DynamicTags\Module as TagsModule;

class Copyright extends Tag
{
	public function get_name() 
	{
		return 'ts-copyright';
	}

	public function get_title()
	{
		return esc_html__('Footer Copyright', 'sphere-core');
	}

	public function get_group()
	{
		return 'site';
	}

	public function get_categories()
	{
		return [TagsModule::TEXT_CATEGORY];
	}

	public function render()
	{
		\Bunyad::theme()->the_copyright();
	}	
}PK03Y�p
?sphere-core/components/elementor/dynamic-tags/tags/site-url.php<?php

namespace Sphere\Core\Elementor\DynamicTags\Tags;

use Elementor\Core\DynamicTags\Data_Tag;
use Elementor\Modules\DynamicTags\Module as TagsModule;

class SiteUrl extends Data_Tag
{
	public function get_name() 
	{
		return 'site-url';
	}

	public function get_title()
	{
		return esc_html__('Site URL', 'sphere-core');
	}

	public function get_group()
	{
		return 'site';
	}

	public function get_categories()
	{
		return [TagsModule::URL_CATEGORY];
	}

	public function get_value(array $options = [])
	{
		return home_url();
	}	
}PK03Y���J��2sphere-core/components/elementor/layouts/admin.php<?php

namespace Sphere\Core\Elementor\Layouts;

/**
 * Admin related functionality.
 */
class Admin
{
	public function __construct()
	{
		add_action('admin_init', [$this, 'init']);
		add_action('admin_menu',  [$this, 'add_menu']);
		add_action('admin_enqueue_scripts', [$this, 'register_assets']);
	}

	public function init()
	{
		// Remove page template options for this CPT.
		add_action('add_meta_boxes_' . Module::POST_TYPE, function() {
			unset( 
				$GLOBALS['wp_meta_boxes'][ Module::POST_TYPE ]['side']['core']['pageparentdiv']
			);
		}, 999);

		add_filter('views_edit-' . Module::POST_TYPE, [$this, 'output_tabs']);
		add_action('admin_action_spc_el_layout_add', [$this, 'create_template']);
	}

	public function register_assets()
	{
		wp_enqueue_style(
			'spc-el-layout-admin',
			Module::instance()->path_url . 'css/admin.css',
			[],
			\Sphere\Core\Plugin::VERSION
		);

		$screen = get_current_screen();

		if ($screen->id === 'edit-' . Module::POST_TYPE) {

			wp_enqueue_style('wp-jquery-ui-dialog');
			wp_enqueue_script(
				'spc-el-layout-admin-js',
				Module::instance()->path_url . 'js/admin.js',
				['jquery-ui-dialog'],
				\Sphere\Core\Plugin::VERSION
			);

			add_action('admin_footer', [$this, 'output_modal_template']);
		}
	}

	public function add_menu()
	{
		// Add submenu but render using the default CPT page.
		add_submenu_page(
			'sphere-dash',
			esc_html__('Custom Layouts', 'sphere-core'),
			esc_html__('Custom Layouts', 'sphere-core'),
			'edit_pages',
			'edit.php?post_type=' . Module::POST_TYPE
		);
	}

	/**
	 * Action callback to create the custom template.
	 *
	 * @return void
	 */
	public function create_template()
	{
		if (!check_admin_referer('spc-el-layout-add') || !current_user_can('edit_posts')) {
			wp_die(
				esc_html__('Sorry, you do not have permission for this.', 'sphere-core' ),
				esc_html__('Error', 'sphere-core')
			);
		}

		$template_type = $_POST['template_type'];
		if (!$template_type) {
			wp_die('Missing fields. Please select correct template type.');
		}

		if (!class_exists('\Elementor\Plugin')) {
			wp_die('Elementor plugin is required to create the template. Please install and activate and the Elementor plugin.');
		}

		$document = \Elementor\Plugin::instance()->documents->get_document_type($template_type);
		
		$post_data = [
			'post_type' => Module::POST_TYPE,
			'tax_input' => [
				Module::TAXONOMY => $template_type,
			],
			'post_title' => $_POST['template_name'],
			'meta_input' => [
				'_elementor_edit_mode' => 'builder',
				$document::TYPE_META_KEY => $template_type
			]
		];

		$post_id = wp_insert_post($post_data);

		wp_safe_redirect(
			\Elementor\Plugin::$instance->documents->get($post_id)->get_edit_url()
		);
	}

	/**
	 * Filter callback: Print our custom tabs on views_edit-CPT filter due to lack of 
	 * a better one in core.
	 *
	 * @param  $current
	 * @return void
	 */
	public function output_tabs($current)
	{
		$tabs = [
			'ts-archive' => esc_html__('Archive', 'sphere-core'),
			'ts-footer'  => esc_html__('Footer', 'sphere-core'),
		];

		$tabs = ['all' => esc_html__('All', 'sphere-core')] + $tabs;
		
		/**
		 * Variables below are used by view file.
		 */
		$active_tab = isset($_GET[ Module::TAXONOMY ]) ? $_GET[ Module::TAXONOMY ] : 'all';
		if (!isset($tabs[$active_tab])) {
			$active_tab = 'all';
		}

		$tab_link   = admin_url('edit.php?post_type=' . Module::POST_TYPE);
		$query_arg  = Module::TAXONOMY;

		require_once Module::instance()->path . 'views/tabs.php';

		return $current;
	}

	public function output_modal_template()
	{
		$submit_url = admin_url('admin.php?action=spc_el_layout_add');
		$types      = Module::instance()->types;
		
		require_once Module::instance()->path . 'views/add-modal.php';	
	}
}PK03YP:t3sphere-core/components/elementor/layouts/module.php<?php

namespace Sphere\Core\Elementor\Layouts;

/**
 * Elementor Custom Layouts.
 */
class Module
{
	const TAXONOMY  = 'spc-el-layout';
	const POST_TYPE = 'spc-el-layouts';

	public $path;
	public $path_url;

	/**
	 * Types of custom layouts.
	 *
	 * @var array
	 */
	public $types = [];

	/**
	 * Classes objects references.
	 */
	public $preview;
	public $template;
	public $admin;
	
	protected static $instance;

	public function __construct()
	{
		// Register CPT whether elementor exists or not, mainly for import.
		add_action('init', [$this, 'register_cpt']);

		// Elementor plugin missing.
		if (!did_action('elementor/loaded')) {
			return;
		}

		$this->types = [
			'ts-archive' => [
				'label'     => esc_html__('Archive', 'admin'),
				'doc_class' => 'Archive',
				'doc_id'    => 'ts-archive',
			],
			'ts-footer' => 	[
				'label'     => esc_html__('Footer', 'admin'),
				'doc_class' => 'Footer',
				'doc_id'    => 'ts-footer',
			],
		];

		// Initialize the admin.
		if (is_admin()) {
			$this->admin = new Admin;
		}

		$this->preview = new Preview;

		// Handle templates at the correct locations.
		$this->template = new Template;

		$this->path = \Sphere\Core\Plugin::instance()->path . 'components/elementor/layouts/';
		$this->path_url = \Sphere\Core\Plugin::instance()->path_url . 'components/elementor/layouts/';
	}

	public function register_cpt()
	{
		$args = [
			'labels' => [
				'name'               => esc_html__('Custom Templates', 'sphere-core'),
				'singular_name'      => esc_html__('Template', 'sphere-core'),
				'add_new'            => esc_html__('Add New', 'sphere-core'),
				'add_new_item'       => esc_html__('Add New Template', 'sphere-core'),
				'edit_item'          => esc_html__('Edit Template', 'sphere-core'),
				'new_item'           => esc_html__('Add New Template', 'sphere-core'),
				'view_item'          => esc_html__('View Template', 'sphere-core'),
				'search_items'       => esc_html__('Search Template', 'sphere-core'),
				'not_found'          => esc_html__('No Templates Found', 'sphere-core'),
				'not_found_in_trash' => esc_html__('No Templates Found In Trash', 'sphere-core'),
				'menu_name'          => esc_html__('Custom Templates', 'sphere-core'),
			],
			'public'              => true,
			'hierarchical'        => false,
			'show_ui'             => true,
			'show_in_menu'        => false,
			'show_in_nav_menus'   => false,
			'can_export'          => true,
			'exclude_from_search' => true,
			'rewrite'             => false,
			'capability_type'     => 'post',
			'supports'            => [
				'title', 'editor', 'thumbnail', 'author', 'elementor'
			],
		];

		register_post_type(self::POST_TYPE, $args);

		// Taxonomy to store the type.
		register_taxonomy(self::TAXONOMY, self::POST_TYPE, [
			'label'             => esc_html__('Type', 'sphere-core'),
			'hierarchical'      => false,
			'query_var'         => is_admin(),
			'show_ui'           => true,
			'show_admin_column' => true,
			'show_in_nav_menus' => false,
			'public'            => false,
			'rewrite'           => false,
		]);
	}

	/**
	 * Get custom layouts options array.
	 *
	 * @param string $type
	 * @return array
	 */
	public function get_options($type = '')
	{
		$query_args = [
			'post_type'      => Module::POST_TYPE,
			'post_status'    => 'publish',
			'posts_per_page' => -1
		];

		if ($type) {
			$query_args['tax_query'] = [
				[
					'taxonomy' => Module::TAXONOMY,
					'field'    => 'slug',
					'terms'    => [$type]
				]
			];
		}

		$results = get_posts($query_args);
		$layouts = [];
		foreach ($results as $post) {
			$layouts[$post->ID] = $post->post_title;
		}

		return $layouts;
	}

	/**
	 * Get singleton object
	 * 
	 * @return self
	 */
	public static function instance()
	{
		if (!isset(self::$instance)) {
			self::$instance = new self;
		}
		
		return self::$instance;
	}
}PK03Ys��%%4sphere-core/components/elementor/layouts/preview.php<?php

namespace Sphere\Core\Elementor\Layouts;

/**
 * Preview handlers.
 */
class Preview
{
	public function __construct()
	{
		add_action('elementor/dynamic_tags/before_render', [$this, 'switch_to_preview_query']);
		add_action('elementor/dynamic_tags/after_render', [$this, 'restore_current_query']);		
	}
	
	public function get_document()
	{
		$current_post_id = get_the_ID();
		$document        = \Elementor\Plugin::instance()->documents->get_doc_or_auto_save($current_post_id);
		
		return $document;
	}

	public function switch_to_preview_query()
	{
		$document = $this->get_document();

		if (!is_object($document) || !method_exists($document, 'get_preview_as_query_args')) {
			return;
		}

		$new_query_vars = $document->get_preview_as_query_args();
		if (!$new_query_vars) {
			return;
		}

		\Elementor\Plugin::instance()->db->switch_to_query($new_query_vars, true);

		if (method_exists($document, 'after_preview_switch_to_query')) {
			$document->after_preview_switch_to_query();
		}
	}

	public function restore_current_query()
	{
		\Elementor\Plugin::instance()->db->restore_current_query();

		$document = $this->get_document();
		if (!is_object($document)) {
			return;
		}
		
		if (method_exists($document, 'after_restore_current_query')) {
			$document->after_restore_current_query();
		}
	}

}

PK03YV=ִ�5sphere-core/components/elementor/layouts/template.php<?php

namespace Sphere\Core\Elementor\Layouts;
use \Bunyad;
use Elementor\Core\Base\Document;

/**
 * Template handlers.
 */
class Template
{
	public $types = [];

	/**
	 * @var array
	 */
	protected $templates = null;

	public function __construct()
	{
		add_action('elementor/documents/register', [$this, 'register_documents']);
		add_action('wp_enqueue_scripts',[$this, 'enqueue_styles']);

		// 11 = after WooCommerce.
		add_filter('template_include', [$this, 'set_editor_template'], 11);

		/**
		 * Change page template if one of the content locations have a custom layout.
		 * 
		 * Currently 'ts-archive' is the location that goes in content and requires a 
		 * canvas page template.
		 */
		add_filter('template_include', function($current) {
			if (!$this->get_for_current('content')) {
				return $current;
			}

			$template = Module::instance()->path . 'page-templates/canvas.php';
			return apply_filters('sphere/el-layouts/page_template', $template);

		}, 99);

		/**
		 * Render custom templates using the filters.
		 */
		$filters = [
			'bunyad_do_partial_footer' => 'ts-footer',
		];

		foreach ($filters as $filter => $location) {
			add_filter($filter, function() use ($location) {
				return !$this->render_by_location($location);
			});
		}
	}

	public function enqueue_styles()
	{
		$templates = $this->get_templates();
		if (!$templates) {
			return;
		}

		$css_files = [];
		$current_post_id = get_the_ID();

		foreach ($templates as $template_id) {

			// Don't enqueue current post here (let the  preview/frontend components to handle it)
			if ($current_post_id !== $template_id) {
				$css_files[] = new \Elementor\Core\Files\CSS\Post($template_id);
			}
		}

		if ($css_files) {
			$front_end = \Elementor\Plugin::instance()->frontend;
			if (!is_object($front_end)) {
				return;
			}
			$front_end->enqueue_styles();
			
			foreach ($css_files as $css_file) {
				$css_file->enqueue();
			}
		}
	}

	/**
	 * Set the template for CPT (hence the editor).
	 *
	 * @param string $template
	 * @return string
	 */
	public function set_editor_template($template)
	{
		if (!is_singular(Module::POST_TYPE)) {
			return $template;
		}

		$doc_type = $this->get_doc_type();
		$template = 'canvas.php';

		switch($doc_type) {
			case 'ts-footer':
				$template = 'ts-footer.php';
				break;
		}

		$template = Module::instance()->path . 'page-templates/' . $template;
		return apply_filters('sphere/el-layouts/editor_template', $template);
	}

	/**
	 * Get document meta type: ts-archive, ts-footer etc.
	 *
	 * @return string
	 */
	protected function get_doc_type()
	{
		return get_post_meta(get_the_ID(), Document::TYPE_META_KEY, true);
	}

	/**
	 * Get templates for current WP view by location.
	 * 
	 * @see self::get_templates()
	 * @return array|string
	 */
	public function get_for_current(string $location)
	{
		$templates = $this->get_templates();
		$current_template = null;

		if ($location && isset($templates[$location])) {
			$current_template = $templates[$location];
		}
		else if ($location === 'content') {
			/**
			 * Content locations have a single result, usually. See if there's any available
			 * in the $templates array from above.
			 * 
			 * Note: 'ts-archive' is the only template that goes in content location yet.
			 */
			$content_templates = array_intersect_key($templates, array_flip([
				'ts-archive'
			]));

			if (count($content_templates)) {
				$current_template = current($content_templates);
			}
		}

		return apply_filters('sphere/el-layouts/current_template', $current_template, $location);
	}

	/**
	 * Get valid configured templates based on current WP view.
	 *
	 * @return array
	 */
	protected function get_templates()
	{
		// Already computed for current view.
		if (is_array($this->templates)) {
			return $this->templates;
		}

		$templates = [];

		/**
		 * Custom Archives templates.
		 */
		if (is_archive()) {

			// Woocommerce doesn't respect is_post_type_archive().
			$is_woocommerce = class_exists('woocommerce') && is_woocommerce();

			if (Bunyad::options()->category_loop_custom && is_category()) {
				$templates['ts-archive'] = Bunyad::options()->category_loop_custom;
			}
			else if (Bunyad::options()->author_loop_custom && is_author()) {
				$templates['ts-archive'] = Bunyad::options()->author_loop_custom;
			}
			else if (Bunyad::options()->archive_loop_custom && !is_post_type_archive()) {
	
				// These have explicit settings, checked above.
				if (!$is_woocommerce && !is_author() && !is_search() && !is_category()) {
					$templates['ts-archive'] = Bunyad::options()->archive_loop_custom;
				}
			}
			else if (Bunyad::options()->cpt_loop_custom && is_post_type_archive()) {
				if (!$is_woocommerce) {
					$templates['ts-archive'] = Bunyad::options()->cpt_loop_custom;
				}
			}

			/**
			 * Setup template from term meta configs, such as per-category settings.
			 */
			$object = get_queried_object();
			if (is_object($object) && property_exists($object, 'term_id')) {
				$term_template = get_term_meta($object->term_id, '_bunyad_custom_template', true);

				if ($term_template) {
					$templates['ts-archive'] = $term_template;
				}

				// If it's none, the global shouldn't apply either.
				if ($term_template === 'none') {
					unset($templates['ts-archive']);
				}
			}
		}

		/**
		 * Custom footer templates.
		 */
		if (Bunyad::options()->footer_custom) {

			// Global layout.
			$templates['ts-footer'] = Bunyad::options()->footer_custom;
		}

		if (Bunyad::options()->footer_custom_conditions) {
			$conditions = [
				'pages'    => 'is_page',
				'posts'    => 'is_single',
				'archives' => 'is_archive',
				'home' => function() {
					return is_home() || is_front_page();
				},
			];

			$template_id = false;
			foreach ($conditions as $type => $condition) {

				// Check if a custom layout for this type even set.
				$value = Bunyad::options()->get('footer_custom_' . $type);
				if (!$value) {
					continue;
				}

				if (call_user_func($condition)) {
					$template_id = $value;
					break;
				}
			}

			if ($template_id) {
				$templates['ts-footer'] = $template_id;
			}
		}

		// Remove any empty values.
		$this->templates = array_filter($templates);

		return apply_filters('sphere/el-layouts/location_templates', $templates);
	}

	/**
	 * Render a template for a particular location.
	 *
	 * @param string $location
	 * @return boolean
	 */
	public function render_by_location($location)
	{
		// Showing the template CPT (editor or front preview)
		if (is_singular(Module::POST_TYPE)) {

			if ($location === 'ts-footer' && $this->get_doc_type() === 'ts-footer') {
				the_content();
				return true;
			}
		}

		$template = $this->get_for_current($location);
		if (!$template) {
			return false;
		}

		$this->render($template);
		return true;
	}

	public function render_content()
	{
		if (did_action('elementor/preview/init')) {
			return the_content();
		}

		$this->render_by_location('content');
	}

	public function render($template_id)
	{
		echo \Elementor\Plugin::instance()->frontend->get_builder_content($template_id, false); // XSS ok
	}

	public function register_documents($manager)
	{
		foreach (Module::instance()->types as $type) {
			$manager->register_document_type(
				$type['doc_id'], 
				'\Sphere\Core\Elementor\Layouts\Documents\\' . $type['doc_class']
			);
		}
	}
}PK03YeӬ66sphere-core/components/elementor/layouts/css/admin.css.spc-el-tabs {
	margin-top: 10px;
	margin-bottom: 18px;
}

.spc-el-add-layout {
	border-radius: 3px;
}

.spc-el-add-layout .ui-dialog-titlebar {
	padding: 10px 25px;
	height: auto;
	font-size: 16px;
}

.spc-el-add-layout .ui-dialog-titlebar-close {
	top: 8px;
	right: 6px;
}

.spc-el-add-layout-content {
	min-width: 500px;
	max-width: 95vw;
	padding: 30px 25px;
}

.spc-modal-form-field {
	display: flex;
	flex-direction: column;
	margin-bottom: 20px;
}

.spc-modal-form-field label {
	margin-bottom: 3px;
}

.spc-modal-form-field select,
.spc-modal-form-field input {
	width: 100%;
	max-width: 700px;
	padding: 6px 12px;
	border-radius: 3px;
}

.spc-el-add-layout .form-buttons {
	text-align: center;
}

.spc-el-add-layout .button-hero {
	width: 100%;
	margin-top: 10px;
	margin-bottom: 3px;
}PK03Y�
#/��>sphere-core/components/elementor/layouts/documents/archive.php<?php
namespace Sphere\Core\Elementor\Layouts\Documents;

class Archive extends Base
{
	public static function get_type()
	{
		return 'ts-archive';
	}

	public static function get_title()
	{
		return esc_html__('Archive', 'sphere-core');
	}

	public static function get_plural_title()
	{
		return esc_html__('Archives', 'sphere-core');
	}

	protected static function get_site_editor_icon()
	{
		return 'eicon-archive';
	}

	public function get_preview_as_query_args()
	{
		return [
			'post_type'   => 'post',
			'post_status' => 'publish',
			'numberposts' => get_option('posts_per_page', 10),
		];
	}

	public function after_preview_switch_to_query()
	{
		global $wp_query;
		$wp_query->is_archive = true;

		add_filter('get_the_archive_title', [$this, 'dummy_archive_title']);
		add_filter('get_the_archive_description', [$this, 'dummy_archive_desc']);
	}

	public function dummy_archive_title() 
	{
		return 'Sample Title';
	}

	public function dummy_archive_desc()
	{
		return 'Sample description text here for the archive.';
	}

	public function after_restore_current_query()
	{
		remove_filter('get_the_archive_title', [$this, 'dummy_archive_title']);
		remove_filter('get_the_archive_description', [$this, 'dummy_archive_desc']);
	}

}PK03Yvn��;;;sphere-core/components/elementor/layouts/documents/base.php<?php

namespace Sphere\Core\Elementor\Layouts\Documents;

use Sphere\Core\Elementor\Layouts\Module;

/**
 * Base document class.
 */
abstract class Base extends \Elementor\Core\Base\Document
{
	public static function get_properties()
	{
		$properties = parent::get_properties();

		$properties['admin_tab_group'] = '';
		$properties['support_kit']     = true;

		return $properties;
	}

	public function get_elements_raw_data($data = null, $with_html_content = false)
	{
		Module::instance()->preview->switch_to_preview_query();

		$editor_data = parent::get_elements_raw_data($data, $with_html_content);

		Module::instance()->preview->restore_current_query();

		return $editor_data;
	}

	public function render_element($data)
	{
		Module::instance()->preview->switch_to_preview_query();

		$render_html = parent::render_element( $data );

		Module::instance()->preview->restore_current_query();

		return $render_html;
	}

	/**
	 * Query args to use when overriding the global query for preview.
	 *
	 * @return array
	 */
	public abstract function get_preview_as_query_args();
}PK03YR�ؚ��=sphere-core/components/elementor/layouts/documents/footer.php<?php
namespace Sphere\Core\Elementor\Layouts\Documents;

class Footer extends Base
{
	public static function get_type()
	{
		return 'ts-footer';
	}

	public static function get_title()
	{
		return esc_html__('Footer', 'sphere-core');
	}

	public static function get_plural_title()
	{
		return esc_html__('Footers', 'sphere-core');
	}

	protected static function get_site_editor_icon()
	{
		return 'eicon-footer';
	}

	public function get_preview_as_query_args()
	{
		return [
			'p' => get_the_ID()
		];
	}
}PK03YŐ�eKK4sphere-core/components/elementor/layouts/js/admin.js"use strict";
(function($) {

	function openModal(e) {

		e.preventDefault();

		const modal = $('#spc-el-add-layout-modal');

		// Show modal.
		modal.dialog({
			title: modal.data('title'),
			autoOpen: false,
			draggable: false,
			classes: {'ui-dialog': 'wp-dialog spc-el-add-layout'},
			width: 'auto',
			modal: true,
			resizable: false,
			closeOnEscape: true,
			position: {
				my: "center",
				at: "center",
				of: window
			},
			open: function () {
				// Close dialog by clicking the overlay behind it
				$('.ui-widget-overlay').bind('click', function() {
					modal.dialog('close');
				})
			},
			create: function () {
				$('.ui-dialog-titlebar-close').addClass('ui-button');
			},
		});

		modal.dialog('open');
	}

	function init() {
		$(document).on('click', '.page-title-action', openModal);
	}

	init();

})(jQuery);PK03YțZ�PPBsphere-core/components/elementor/layouts/page-templates/canvas.php<?php
/**
 * Page template that's full width with header and footer.
 */
use Sphere\Core\Elementor\Layouts\Module;

if (class_exists('Bunyad') && Bunyad::core()) {
	Bunyad::core()->set_sidebar('none');
}

get_header();
?>

<div class="main-full">
	<?php Module::instance()->template->render_content(); ?>
</div>

<?php get_footer(); ?>
PK03Y�"~��Esphere-core/components/elementor/layouts/page-templates/ts-footer.php<?php
/**
 * Footer Page template that's full width with header.
 * 
 * Note: Only used for template preview, not for real footer rendering on frontend.
 */

if (class_exists('Bunyad') && Bunyad::core()) {
	Bunyad::core()->set_sidebar('none');
}

get_header();
?>

<div class="main ts-contain cf">
	<h3>Content Here</h3>
	<p>Sample body content here.</p>
</div>

<?php get_footer(); ?>PK03Y�����<sphere-core/components/elementor/layouts/views/add-modal.php<?php
/**
 * Partial: Popup modal for add new layout.
 */
?>
<div id="spc-el-add-layout-modal" class="spc-el-add-layout-content hidden" data-title="<?php esc_attr_e('Add Custom Layout', 'sphere-core'); ?>">

	<form method="post" action="<?php echo esc_url($submit_url); ?>">
		<?php wp_nonce_field('spc-el-layout-add'); ?>

		<div class="spc-modal-form-field">
			<label for="template_type">
				<?php esc_html_e('Select Type of Template', 'sphere-core'); ?>
			</label>
			
			<select name="template_type">
				<?php foreach ($types as $id => $type): ?>
					<option value="<?php echo esc_attr($id); ?>"><?php echo esc_attr($type['label']); ?></option>
				<?php endforeach; ?>
			</select>
		</div>

		<div class="spc-modal-form-field">
			<label for="template_name">
				<?php esc_html_e('Layout Template Name', 'sphere-core'); ?>
			</label>
			<input type="text" name="template_name" placeholder="<?php esc_attr_e('A descriptive name', 'sphere-core'); ?>" />
		</div>

		<div class="form-buttons">
			<input type="submit" class="button button-primary button-hero" value="<?php esc_attr_e('Create Template', 'sphere-core'); ?>" />
		</div>
	</form>

</div>PK03Y��ٜ��7sphere-core/components/elementor/layouts/views/tabs.php<?php
/**
 * Partial: Tabs for Custom Layouts.
 */
?>
<div class="nav-tab-wrapper spc-el-tabs">
	<?php 
		foreach ($tabs as $tab => $label):

			$the_link = $tab_link;

			if ($tab !== 'all') {
				$the_link = add_query_arg([$query_arg => $tab], $tab_link);
			}
	?>

		<a href="<?php echo esc_url($the_link); ?>" class="nav-tab<?php echo ($tab === $active_tab ? ' nav-tab-active' : ''); ?>">
			<?php echo esc_html($label); ?>
		</a>
	<?php endforeach; ?>
</div>PK03Y��j='''sphere-core/components/likes/module.php<?php
namespace Sphere\Core\Likes;

use Bunyad;

/**
 * A likes/+1 system handler
 */
class Module
{
	public function __construct()
	{
        add_action('wp_ajax_sphere_likes', array($this, 'ajax_like'));
		add_action('wp_ajax_nopriv_sphere_likes', array($this, 'ajax_like'));
		
		// add_action('wp_enqueue_scripts', array($this, 'register_script'));

		// Register AJAX URL.
		add_filter('wp_head', function() {

			if (Bunyad::amp() && Bunyad::amp()->active()) {
				return;
			}

			printf(
				'<script>var Sphere_Plugin = %s;</script>', 
				wp_json_encode([
					'ajaxurl' => admin_url('admin-ajax.php')
				])
			);
		});
	}
	
	/**
	 * AJAX handler for likes
	 */
	public function ajax_like()
	{
		// Can the rating be added - perform all checks
		if (!$this->can_like(intval($_POST['id']))) {
			echo -1;
			wp_die();
		}
		
		$likes = $this->add_like($_POST['id']);
		
		echo json_encode(array('count' => $likes['count']));
		
		wp_die();
	}
	
	/**
	 * Get existing count 
	 * 
	 * @param integer|null $post_id
	 */
	public function get_count($post_id = null)
	{
		if (!$post_id) {
			$post_id = get_the_ID();
		}
		
		$votes = get_post_meta($post_id, '_sphere_user_likes', true);
		return (!empty($votes['count']) ? $votes['count'] : 0);
	}
	
	/**
	 * Add a like for the post 
	 */
	public function add_like($post_id = null)
	{
		if (!$post_id) {
			$post_id = get_the_ID();
		}
		
		if (!$this->can_like($post_id)) {
			return false;
		}
		
		$likes = get_post_meta($post_id, '_sphere_user_likes', true);
		
		// Defaults if no votes yet
		if (!is_array($likes)) {
			$likes = array('votes' => array(), 'count' => 0);
		}
		
		$likes['count']++;
		
		// Add IP Address - @deprecated for privacy
		// $likes['votes'][time()] = $this->get_user_ip();
		$likes['votes'][time()] = 1;
		
			
		// save meta data
		update_post_meta(intval($_POST['id']), '_sphere_user_likes', $likes);
		update_post_meta(intval($_POST['id']), '_sphere_user_likes_count', $likes['count']); 
		
		// set the cookie
		$ids = array();
		if (!empty($_COOKIE['sphere_user_likes'])) {
			$ids = (array) explode('|', $_COOKIE['sphere_user_likes']);
		}
		
		array_push($ids, $_POST['id']);
		setcookie('sphere_user_likes', implode('|', $ids), time() + 30 * DAY_IN_SECONDS, COOKIEPATH);
		
		return $likes;
	}
	
	/**
	 * Whether a user can like
	 * 
	 * @param integer|null $post_id
	 */
	public function can_like($post_id = null)
	{
		if (!$post_id) {
			$post_id = get_the_ID();
		}
		
		// Only supported for posts
		if (get_post_type($post_id) !== 'post') {
			return false;
		}

		// IP check - @deprecated since GDPR update
		// $votes = get_post_meta($post_id, '_sphere_user_likes', true);
		// $user_ip = $this->get_user_ip();
		
		// if (!empty($votes['votes'])) {
			
		// 	foreach ((array) $votes['votes'] as $time => $data) {
		// 		if (!empty($data[1]) && $data[1] == $user_ip) {
		// 			return false;
		// 		}
		// 	}
		// }
		
		// Cookie check
		if (!empty($_COOKIE['sphere_user_likes'])) {
			$ids = (array) explode('|', $_COOKIE['sphere_user_likes']);
			
			if (in_array($post_id, $ids)) {
				return false;
			}
		}
		
		return true;
	}
	
	/**
	 * Get user ip
	 * 
	 * @deprecated No longer used since GDPR update
	 */
	// public function get_user_ip()
	// {
	// 	if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
	// 		// check ip from share internet
	// 		$ip = $_SERVER['HTTP_CLIENT_IP'];	
	// 	}
	// 	elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
	// 		// to check ip is pass from proxy
	// 		$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
	// 	}
	// 	else {
	// 		$ip = $_SERVER['REMOTE_ADDR'];
	// 	}

	// 	return $ip;
	// }
}PK03Y6B�1��/sphere-core/components/social-follow/module.php<?php
namespace Sphere\Core\SocialFollow;

/**
 * Social followers counter for several services
 */
class Module
{
	/**
	 * The settings related to this plugin
	 * @var array
	 */
	public $options;
	
	/**
	 * Timeout for remote connections
	 * @var integer
	 */
	public $timeout = 10;
	
	/**
	 * Constructor called at hook: bunyad_core_pre_init
	 */
	public function __construct()
	{
		// Add relevant options
		add_filter('bunyad_theme_options', [$this, 'add_theme_options']);
		
		// Flush cache on options save
		add_action('bunyad_options_saved', [$this, 'flush_cache']);
		add_action('customize_save', [$this, 'flush_cache']);
		
		// Initialize after bunyad frameowrk has run core setup
		add_action('after_setup_theme', [$this, 'init'], 12);
		
		define('SPHERE_SF_DIR', plugin_dir_path(__FILE__));
	}
	
	/**
	 * Initialize and setup settings
	 */
	public function init()
	{
		if (class_exists('\Bunyad')) {
			$this->options = \Bunyad::options()->get_all('sf_');
		}
		
			
		if (!is_admin()) {
			// DEBUG:
			//echo $this->count('facebook');
			//echo $this->count('gplus');
			//echo $this->count('youtube');
			//echo $this->count('vimeo');
			//echo $this->count('twitter');
			//echo $this->count('instagram');
			//echo $this->count('pinterest');
			//exit;
		}
	}
	
	/**
	 * Add to theme options array
	 * 
	 * @param  array $options
	 * @return array
	 */
	public function add_theme_options($options) 
	{
		$doc_link = apply_filters('sphere_theme_docs_url', 'https://theme-sphere.com/smart-mag/documentation/') . '#social-follow';
		
		$extra_options = [
			'title'    => esc_html__('Social Followers', 'sphere-core'),
			'id'       => 'sphere-social-followers',
			'priority' => 40,
			'sections' => [
				'general' => [
					'title'  => esc_html__('General', 'sphere-core'),
					'fields' => [
						'sf_counters' => [
							'name' 	  => 'sf_counters',
							'label'   => esc_html__('Enable Follower Counters?', 'sphere-core'),
							'value'   => 1,
							'desc'    => __('If follower counters/numbers are enabled, refer to <a href="'. esc_url($doc_link) .'" target="_blank">documentation</a> to learn how to set it up.', 'sphere-core'),
							'type'    => 'checkbox',
						],
					]
				],

				'facebook' => [
					'title'  => 'Facebook',
					'desc'   => __('If follower counters/numbers are enabled, refer to <a href="'. esc_url($doc_link) .'"  target="_blank">documentation</a> to learn how to set it up.', 'sphere-core'),
					'fields' => [
						[
							'name' 	  => 'sf_facebook_id',
							'label'   => esc_html__('Page Name / ID', 'sphere-core'),
							'value'   => '',
							'desc'    => esc_html__('If your page URL is https://facebook.com/themesphere enter themesphere as the id here.', 'sphere-core'),
							'type'    => 'text',
						],
							
						'sf_facebook_label' => [
							'name' 	  => 'sf_facebook_label',
							'label'   => esc_html__('Button Label', 'sphere-core'),
							'value'   => esc_html__('Facebook', 'sphere-core'),
							'desc'    => esc_html__('The text to use on the widget.', 'sphere-core'),
							'type'    => 'text',
						],

						[
							'name' 	  => 'sf_facebook_count',
							'label'   => esc_html__('Manual Count', 'sphere-core'),
							'desc'    => esc_html__('This will force this number to be used as counter. Useful if cannot use API.', 'sphere-core'),
							'value'   => '',
							'type'    => 'number',
						],
						// array(
						// 	'name' 	  => 'sf_facebook_app',
						// 	'label'   => esc_html__('App ID', 'sphere-core'),
						// 	'value'   => '',
						// 	'desc'    => '',
						// 	'type'    => 'text',
						// ),
							
						// array(
						// 	'name' 	  => 'sf_facebook_secret',
						// 	'label'   => esc_html__('App Secret', 'sphere-core'),
						// 	'value'   => '',
						// 	'desc'    => '',
						// 	'type'    => 'text',
						// ),
					]
				],
					
				// 'gplus' => array(
				// 	'title'  => 'Google Plus',
				// 	'desc'   => esc_html__('If follower counters/numbers are enabled, refer to <a href="'. esc_url($doc_link) .'" target="_blank">documentation</a> to learn how to set it up.', 'sphere-core'),
				// 	'fields' => array(
				// 		array(
				// 			'name' 	  => 'sf_gplus_id',
				// 			'label'   => esc_html__('Page Name / ID', 'sphere-core'),
				// 			'value'   => '',
				// 			'desc'    => esc_html__('If your page URL is https://plus.google.com/+themesphere enter +themesphere as the id here.', 'sphere-core'),
				// 			'type'    => 'text',
				// 		),
							
				// 		'sf_gplus_label' => array(
				// 			'name' 	  => 'sf_gplus_label',
				// 			'label'   => esc_html__('Button Label', 'sphere-core'),
				// 			'value'   => esc_html__('Follow on Google+', 'sphere-core'),
				// 			'desc'    => esc_html__('The text to use on the widget.', 'sphere-core'),
				// 			'type'    => 'text',
				// 		),
							
				// 		array(
				// 			'name' 	  => 'sf_gplus_key',
				// 			'label'   => esc_html__('Google API Key', 'sphere-core'),
				// 			'value'   => '',
				// 			'desc'    => '',
				// 			'type'    => 'text',
				// 		),
				// 	)
				// ),

				'youtube' => [
					'title'  => 'YouTube',
					'desc'   => __('If follower counters/numbers are enabled, refer to <a href="'. esc_url($doc_link) .'" target="_blank">documentation</a> to learn how to set it up.', 'sphere-core'),
					'fields' => [
						[
							'name' 	  => 'sf_youtube_id',
							'label'   => esc_html__('Channel ID', 'sphere-core'),
							'value'   => '',
							'desc'    => __('You can get the id from <a href="https://www.youtube.com/account_advanced" target="_blank">https://www.youtube.com/account_advanced</a>.', 'sphere-core'),
							'type'    => 'text',
						],
							
						'sf_youtube_label' => [
							'name' 	  => 'sf_youtube_label',
							'label'   => esc_html__('Button Label', 'sphere-core'),
							'value'   => esc_html__('YouTube', 'sphere-core'),
							'desc'    => esc_html__('The text to use on the widget.', 'sphere-core'),
							'type'    => 'text',
						],

						[
							'name' 	  => 'sf_youtube_count',
							'label'   => esc_html__('Manual Count', 'sphere-core'),
							'desc'    => esc_html__('This will force this number to be used as counter. Useful if cannot use API.', 'sphere-core'),
							'value'   => '',
							'type'    => 'number',
						],
							
						[
							'name' 	  => 'sf_youtube_url',
							'label'   => esc_html__('Channel URL', 'sphere-core'),
							'value'   => '',
							'desc'    => esc_html__('Full link to your YouTube channel.', 'sphere-core'),
							'type'    => 'text',
						],

						[
							'name' 	  => 'sf_youtube_key',
							'label'   => esc_html__('Google API Key', 'sphere-core'),
							'value'   => '',
							'desc'    => '',
							'type'    => 'text',
						],
					]
				],
					
				'vimeo' => [
					'title'  => 'Vimeo',
					'fields' => [
						[
							'name' 	  => 'sf_vimeo_id',
							'label'   => esc_html__('Vimeo Username / Channel', 'sphere-core'),
							'value'   => '',
							'desc'    => '',
							'type'    => 'text',
						],

						[
							'name' 	  => 'sf_vimeo_url',
							'label'   => esc_html__('Vimeo URL', 'sphere-core'),
							'value'   => '',
							'desc'    => esc_html__('Full link to your Vimeo channel or profile.', 'sphere-core'),
							'type'    => 'text',
						],
							
						'sf_vimeo_label' => [
							'name' 	  => 'sf_vimeo_label',
							'label'   => esc_html__('Button Label', 'sphere-core'),
							'value'   => esc_html__('Vimeo', 'sphere-core'),
							'desc'    => esc_html__('The text to use on the widget.', 'sphere-core'),
							'type'    => 'text',
						],

						[
							'name' 	  => 'sf_vimeo_count',
							'label'   => esc_html__('Manual Count', 'sphere-core'),
							'desc'    => esc_html__('This will force this number to be used as counter. Useful if cannot use API.', 'sphere-core'),
							'value'   => '',
							'type'    => 'number',
						],

						[
							'name' 	  => 'sf_vimeo_type',
							'label'   => esc_html__('Channel or User?', 'sphere-core'),
							'value'   => 'user',
							'desc'    => '',
							'type'    => 'select',
							'options' => [
								'user'    => esc_html__('User', 'sphere-core'),
								'channel' => esc_html__('Channel', 'sphere-core')
							]
						],
					]
				],
					
				'twitter' => [
					'title'  => 'X (Twitter)',
					'desc'   => __('If follower counters/numbers are enabled, refer to <a href="'. esc_url($doc_link) .'" target="_blank">documentation</a> to learn how to set it up.', 'sphere-core'),
					'fields' => [
							
						[
							'name' 	  => 'sf_twitter_id',
							'label'   => esc_html__('Twitter Username', 'sphere-core'),
							'value'   => '',
							'desc'    => '',
							'type'    => 'text',
						],
							
						'sf_twitter_label' => [
							'name' 	  => 'sf_twitter_label',
							'label'   => esc_html__('Button Label', 'sphere-core'),
							'value'   => esc_html__('Twitter', 'sphere-core'),
							'desc'    => esc_html__('The text to use on the widget.', 'sphere-core'),
							'type'    => 'text',
						],

						[
							'name' 	  => 'sf_twitter_count',
							'label'   => esc_html__('Manual Count', 'sphere-core'),
							'desc'    => esc_html__('Automatic counters are not supported for this network. A manual number is needed.', 'sphere-core'),
							'value'   => '',
							'type'    => 'number',
						],
							
						// [
						// 	'name' 	  => 'sf_twitter_key',
						// 	'label'   => esc_html__('Consumer Key', 'sphere-core'),
						// 	'value'   => '',
						// 	'desc'    => esc_html__('', 'sphere-core'),
						// 	'type'    => 'text',
						// ],
							
						// [
						// 	'name' 	  => 'sf_twitter_secret',
						// 	'label'   => esc_html__('Consumer Secret', 'sphere-core'),
						// 	'value'   => '',
						// 	'desc'    => esc_html__('', 'sphere-core'),
						// 	'type'    => 'text',
						// ],
							
						// [
						// 	'name' 	  => 'sf_twitter_token',
						// 	'label'   => esc_html__('Access Token', 'sphere-core'),
						// 	'value'   => '',
						// 	'desc'    => esc_html__('', 'sphere-core'),
						// 	'type'    => 'text',
						// ],
							
						// [
						// 	'name' 	  => 'sf_twitter_token_secret',
						// 	'label'   => esc_html__('Access Token Secret', 'sphere-core'),
						// 	'value'   => '',
						// 	'desc'    => esc_html__('', 'sphere-core'),
						// 	'type'    => 'text',
						// ],
					]
				],
					
				'instagram' => [
					'title'  => 'Instagram',
					'desc'   => '',
					'fields' => [
						[
							'name' 	  => 'sf_instagram_id',
							'label'   => esc_html__('Instagram Username', 'sphere-core'),
							'value'   => '',
							'desc'    => '',
							'type'    => 'text',
						],
							
						'sf_instagram_label' => [
							'name' 	  => 'sf_instagram_label',
							'label'   => esc_html__('Button Label', 'sphere-core'),
							'value'   => esc_html__('Instagram', 'sphere-core'),
							'desc'    => esc_html__('The text to use on the widget.', 'sphere-core'),
							'type'    => 'text',
						],

						[
							'name' 	  => 'sf_instagram_count',
							'label'   => esc_html__('Manual Count', 'sphere-core'),
							'desc'    => esc_html__('This will force this number to be used as counter. Useful if cannot use API.', 'sphere-core'),
							'value'   => '',
							'type'    => 'number',
						],
					]
				],
					
				'pinterest' => [
					'title'  => 'Pinterest',
					'desc'   => '',
					'fields' => [
						[
							'name' 	  => 'sf_pinterest_id',
							'label'   => esc_html__('Pinterest Username', 'sphere-core'),
							'value'   => '',
							'desc'    => '',
							'type'    => 'text',
						],
							
						'sf_pinterest_label' => [
							'name' 	  => 'sf_pinterest_label',
							'label'   => esc_html__('Button Label', 'sphere-core'),
							'value'   => esc_html__('Pinterest', 'sphere-core'),
							'desc'    => esc_html__('The text to use on the widget.', 'sphere-core'),
							'type'    => 'text',
						],

						[
							'name' 	  => 'sf_pinterest_count',
							'label'   => esc_html__('Manual Count', 'sphere-core'),
							'desc'    => esc_html__('This will force this number to be used as counter. Useful if cannot use API.', 'sphere-core'),
							'value'   => '',
							'type'    => 'number',
						],
					]
				],

				'linkedin' => [
					'title'  => 'LinkedIn',
					'desc'   => '',
					'fields' => [
						// [
						// 	'name' 	  => 'sf_linkedin_id',
						// 	'label'   => esc_html__('LinkedIn ID', 'sphere-core'),
						// 	'value'   => '',
						// 	'desc'    => '',
						// 	'type'    => 'text',
						// ],

						[
							'name' 	  => 'sf_linkedin_url',
							'label'   => esc_html__('LinkedIn URL', 'sphere-core'),
							'value'   => '',
							'desc'    => esc_html__('Full link to your LinkedIn company or profile.', 'sphere-core'),
							'type'    => 'text',
						],
							
						'sf_linkedin_label' => [
							'name' 	  => 'sf_linkedin_label',
							'label'   => esc_html__('Button Label', 'sphere-core'),
							'value'   => esc_html__('LinkedIn', 'sphere-core'),
							'desc'    => esc_html__('The text to use on the widget.', 'sphere-core'),
							'type'    => 'text',
						],

						[
							'name' 	  => 'sf_linkedin_type',
							'label'   => esc_html__('Company or Profile?', 'sphere-core'),
							'value'   => 'company',
							'desc'    => '',
							'type'    => 'select',
							'options' => [
								'company' => esc_html__('Company', 'sphere-core'),
								'profile' => esc_html__('Profile', 'sphere-core'),
							]
						],

						[
							'name' 	  => 'sf_linkedin_count',
							'label'   => esc_html__('Manual Count', 'sphere-core'),
							'desc'    => esc_html__('Automatic counters are not supported for linkedin. A manual number is needed.', 'sphere-core'),
							'value'   => '',
							'type'    => 'number',
						],
					]
				],

				'linkedin' => [
					'title'  => 'LinkedIn',
					'desc'   => '',
					'fields' => [
						// [
						// 	'name' 	  => 'sf_linkedin_id',
						// 	'label'   => esc_html__('LinkedIn ID', 'sphere-core'),
						// 	'value'   => '',
						// 	'desc'    => '',
						// 	'type'    => 'text',
						// ],

						[
							'name' 	  => 'sf_linkedin_url',
							'label'   => esc_html__('LinkedIn URL', 'sphere-core'),
							'value'   => '',
							'desc'    => esc_html__('Full link to your LinkedIn company or profile.', 'sphere-core'),
							'type'    => 'text',
						],
							
						'sf_linkedin_label' => [
							'name' 	  => 'sf_linkedin_label',
							'label'   => esc_html__('Button Label', 'sphere-core'),
							'value'   => esc_html__('LinkedIn', 'sphere-core'),
							'desc'    => esc_html__('The text to use on the widget.', 'sphere-core'),
							'type'    => 'text',
						],

						[
							'name' 	  => 'sf_linkedin_type',
							'label'   => esc_html__('Company or Profile?', 'sphere-core'),
							'value'   => 'company',
							'desc'    => '',
							'type'    => 'select',
							'options' => [
								'company' => esc_html__('Company', 'sphere-core'),
								'profile' => esc_html__('Profile', 'sphere-core'),
							]
						],

						[
							'name' 	  => 'sf_linkedin_count',
							'label'   => esc_html__('Manual Count', 'sphere-core'),
							'desc'    => esc_html__('Automatic counters are not supported for linkedin. A manual number is needed.', 'sphere-core'),
							'value'   => '',
							'type'    => 'number',
						],
					]
				],

				'soundcloud' => [
					'title'  => 'Soundcloud',
					'desc'   => '',
					'fields' => [
						[
							'name' 	  => 'sf_soundcloud_id',
							'label'   => esc_html__('Soundcloud ID', 'sphere-core'),
							'value'   => '',
							'desc'    => '',
							'type'    => 'text',
						],
							
						'sf_soundcloud_label' => [
							'name' 	  => 'sf_soundcloud_label',
							'label'   => esc_html__('Button Label', 'sphere-core'),
							'value'   => esc_html__('Soundcloud', 'sphere-core'),
							'desc'    => esc_html__('The text to use on the widget.', 'sphere-core'),
							'type'    => 'text',
						],

						[
							'name' 	  => 'sf_soundcloud_count',
							'label'   => esc_html__('Manual Count', 'sphere-core'),
							'desc'    => esc_html__('Automatic counters are not supported for this network. A manual number is needed.', 'sphere-core'),
							'value'   => '',
							'type'    => 'number',
						],
					]
				],

				'twitch' => [
					'title'  => 'Twitch',
					'desc'   => '',
					'fields' => [
						[
							'name' 	  => 'sf_twitch_id',
							'label'   => esc_html__('Twitch Channel ID', 'sphere-core'),
							'value'   => '',
							'desc'    => '',
							'type'    => 'text',
						],
							
						'sf_twitch_label' => [
							'name' 	  => 'sf_twitch_label',
							'label'   => esc_html__('Button Label', 'sphere-core'),
							'value'   => esc_html__('Twitch', 'sphere-core'),
							'desc'    => esc_html__('The text to use on the widget.', 'sphere-core'),
							'type'    => 'text',
						],

						[
							'name' 	  => 'sf_twitch_count',
							'label'   => esc_html__('Manual Count', 'sphere-core'),
							'desc'    => esc_html__('Automatic counters are not supported for this network. A manual number is needed.', 'sphere-core'),
							'value'   => '',
							'type'    => 'number',
						],
					]
				],

				'tiktok' => [
					'title'  => 'TikTok',
					'desc'   => '',
					'fields' => [
						[
							'name' 	  => 'sf_tiktok_id',
							'label'   => esc_html__('TikTok User', 'sphere-core'),
							'value'   => '',
							'desc'    => '',
							'type'    => 'text',
						],
							
						'sf_tiktok_label' => [
							'name' 	  => 'sf_tiktok_label',
							'label'   => esc_html__('Button Label', 'sphere-core'),
							'value'   => esc_html__('TikTok', 'sphere-core'),
							'desc'    => esc_html__('The text to use on the widget.', 'sphere-core'),
							'type'    => 'text',
						],

						[
							'name' 	  => 'sf_tiktok_count',
							'label'   => esc_html__('Manual Count', 'sphere-core'),
							'desc'    => esc_html__('Automatic counters are not supported for this network. A manual number is needed.', 'sphere-core'),
							'value'   => '',
							'type'    => 'number',
						],
					]
				],

				'telegram' => [
					'title'  => 'Telegram',
					'desc'   => '',
					'fields' => [
						[
							'name' 	  => 'sf_telegram_id',
							'label'   => esc_html__('Telegram Channel ID', 'sphere-core'),
							'value'   => '',
							'desc'    => '',
							'type'    => 'text',
						],
							
						'sf_telegram_label' => [
							'name' 	  => 'sf_telegram_label',
							'label'   => esc_html__('Button Label', 'sphere-core'),
							'value'   => esc_html__('Telegram', 'sphere-core'),
							'desc'    => esc_html__('The text to use on the widget.', 'sphere-core'),
							'type'    => 'text',
						],

						[
							'name' 	  => 'sf_telegram_count',
							'label'   => esc_html__('Manual Count', 'sphere-core'),
							'desc'    => esc_html__('Automatic counters are not supported for this network. A manual number is needed.', 'sphere-core'),
							'value'   => '',
							'type'    => 'number',
						],
					]
				],

				
				'whatsapp' => [
					'title'  => 'WhatsApp',
					'desc'   => '',
					'fields' => [
						[
							'name' 	  => 'sf_whatsapp_id',
							'label'   => esc_html__('WhatsApp Number', 'sphere-core'),
							'value'   => '',
							'desc'    => '',
							'type'    => 'text',
						],

						'sf_whatsapp_label' => [
							'name' 	  => 'sf_whatsapp_label',
							'label'   => esc_html__('Button Label', 'sphere-core'),
							'value'   => esc_html__('WhatsApp', 'sphere-core'),
							'desc'    => esc_html__('The text to use on the widget.', 'sphere-core'),
							'type'    => 'text',
						],
					]
				],

				'google-news' => [
					'title'  => 'Google News',
					'desc'   => '',
					'fields' => [
						[
							'name' 	  => 'sf_google_news_url',
							'label'   => esc_html__('Google News URL (Optional)', 'sphere-core'),
							'value'   => '',
							'desc'    => 'Will use from Social Profiles if not provided.',
							'type'    => 'text',
						],

						'sf_google_news_label' => [
							'name' 	  => 'sf_google_news_label',
							'label'   => esc_html__('Button Label', 'sphere-core'),
							'value'   => esc_html__('News', 'sphere-core'),
							'desc'    => esc_html__('The text to use on the widget.', 'sphere-core'),
							'type'    => 'text',
						],
					]
				],

				'flipboard' => [
					'title'  => 'Flipboard',
					'desc'   => '',
					'fields' => [
						[
							'name' 	  => 'sf_flipboard_url',
							'label'   => esc_html__('Flipboard URL (Optional)', 'sphere-core'),
							'value'   => '',
							'desc'    => 'Will use from Social Profiles if not provided.',
							'type'    => 'text',
						],

						'sf_flipboard_label' => [
							'name' 	  => 'sf_flipboard_label',
							'label'   => esc_html__('Button Label', 'sphere-core'),
							'value'   => esc_html__('Flipboard', 'sphere-core'),
							'desc'    => esc_html__('The text to use on the widget.', 'sphere-core'),
							'type'    => 'text',
						],
					]
				],

				'tumblr' => [
					'title'  => 'Tumblr',
					'desc'   => '',
					'fields' => [
						[
							'name' 	  => 'sf_tumblr_url',
							'label'   => esc_html__('Tumblr URL (Optional)', 'sphere-core'),
							'value'   => '',
							'desc'    => 'Will use from Social Profiles if not provided.',
							'type'    => 'text',
						],

						'sf_tumblr_label' => [
							'name' 	  => 'sf_tumblr_label',
							'label'   => esc_html__('Button Label', 'sphere-core'),
							'value'   => esc_html__('Tumblr', 'sphere-core'),
							'desc'    => esc_html__('The text to use on the widget.', 'sphere-core'),
							'type'    => 'text',
						],

						[
							'name' 	  => 'sf_tumblr_count',
							'label'   => esc_html__('Manual Count', 'sphere-core'),
							'desc'    => esc_html__('Automatic counters are not supported for this network. A manual number is needed.', 'sphere-core'),
							'value'   => '',
							'type'    => 'number',
						],
					]
				],

				'reddit' => [
					'title'  => 'Reddit',
					'desc'   => '',
					'fields' => [
						[
							'name' 	  => 'sf_reddit_url',
							'label'   => esc_html__('Reddit URL', 'sphere-core'),
							'value'   => '',
							'desc'    => esc_html__('Full link to your sub-reddit or user profile.', 'sphere-core'),
							'type'    => 'text',
						],
							
						'sf_reddit_label' => [
							'name' 	  => 'sf_reddit_label',
							'label'   => esc_html__('Button Label', 'sphere-core'),
							'value'   => esc_html__('Reddit', 'sphere-core'),
							'desc'    => esc_html__('The text to use on the widget.', 'sphere-core'),
							'type'    => 'text',
						],

						[
							'name' 	  => 'sf_reddit_type',
							'label'   => esc_html__('Sub-Reddit or User', 'sphere-core'),
							'value'   => 'sub',
							'desc'    => '',
							'type'    => 'select',
							'options' => [
								'sub' => esc_html__('Sub-reddit', 'sphere-core'),
								'user' => esc_html__('User Profile', 'sphere-core'),
							]
						],

						[
							'name' 	  => 'sf_reddit_count',
							'label'   => esc_html__('Manual Count', 'sphere-core'),
							'desc'    => esc_html__('Automatic counters are not supported for this network. A manual number is needed.', 'sphere-core'),
							'value'   => '',
							'type'    => 'number',
						],
					]
				],

				'mastodon' => [
					'title'  => 'Mastodon',
					'desc'   => '',
					'fields' => [
						[
							'name' 	  => 'sf_mastodon_url',
							'label'   => esc_html__('Mastodon URL', 'sphere-core'),
							'value'   => '',
							'desc'    => esc_html__('Will use from Social Profiles if not provided.', 'sphere-core'),
							'type'    => 'text',
						],
							
						'sf_mastodon_label' => [
							'name' 	  => 'sf_mastodon_label',
							'label'   => esc_html__('Button Label', 'sphere-core'),
							'value'   => esc_html__('Mastodon', 'sphere-core'),
							'desc'    => esc_html__('The text to use on the widget.', 'sphere-core'),
							'type'    => 'text',
						],

						[
							'name' 	  => 'sf_mastodon_count',
							'label'   => esc_html__('Manual Count', 'sphere-core'),
							'desc'    => esc_html__('Automatic counters are not supported for this network. A manual number is needed.', 'sphere-core'),
							'value'   => '',
							'type'    => 'number',
						],
					]
				],

				'threads' => [
					'title'  => 'Threads',
					'desc'   => '',
					'fields' => [
						[
							'name' 	  => 'sf_threads_url',
							'label'   => esc_html__('Threads URL', 'sphere-core'),
							'value'   => '',
							'desc'    => esc_html__('Will use from Social Profiles if not provided.', 'sphere-core'),
							'type'    => 'text',
						],
							
						'sf_threads_label' => [
							'name' 	  => 'sf_threads_label',
							'label'   => esc_html__('Button Label', 'sphere-core'),
							'value'   => esc_html__('Threads', 'sphere-core'),
							'desc'    => esc_html__('The text to use on the widget.', 'sphere-core'),
							'type'    => 'text',
						],

						[
							'name' 	  => 'sf_threads_count',
							'label'   => esc_html__('Manual Count', 'sphere-core'),
							'desc'    => esc_html__('Automatic counters are not supported for this network. A manual number is needed.', 'sphere-core'),
							'value'   => '',
							'type'    => 'number',
						],
					]
				],

				'spotify' => [
					'title'  => 'Spotify',
					'desc'   => '',
					'fields' => [
						[
							'name' 	  => 'sf_spotify_url',
							'label'   => esc_html__('Spotify URL', 'sphere-core'),
							'value'   => '',
							'desc'    => esc_html__('Will use from Social Profiles if not provided.', 'sphere-core'),
							'type'    => 'text',
						],
							
						'sf_spotify_label' => [
							'name' 	  => 'sf_spotify_label',
							'label'   => esc_html__('Button Label', 'sphere-core'),
							'value'   => esc_html__('Spotify', 'sphere-core'),
							'desc'    => esc_html__('The text to use on the widget.', 'sphere-core'),
							'type'    => 'text',
						],

						[
							'name' 	  => 'sf_spotify_count',
							'label'   => esc_html__('Manual Count', 'sphere-core'),
							'desc'    => esc_html__('Automatic counters are not supported for this network. A manual number is needed.', 'sphere-core'),
							'value'   => '',
							'type'    => 'number',
						],
					]
				],
			]
		];
		
		/**
		 * @deprecated 1.1.6 Use sphere/social-follow/options instead.
		 */
		$extra_options = apply_filters('sphere_social_follow_options', $extra_options);

		/**
		 * New filter for the options.
		 * 
		 * @param array $extra_options Customizer section options.
		 */
		$extra_options = apply_filters('sphere/social-follow/options', $extra_options);
		
		$options['options-tab-social-followers'] = $extra_options;
		return $options;
	}
	
	/**
	 * Get share count for a specific service
	 * 
	 * @param string $type The service name
	 */
	public function count($type)
	{
		// Use manually forced counter numbers.
		if (isset($this->options['sf_' . $type . '_count'])) {
			$manual_count = $this->options['sf_' . $type . '_count'];

			if ($manual_count) {
				return $manual_count;
			}
		}

		// Method exists?
		$method = 'get_' . $type;
		if (!method_exists($this, $method)) {
			return 0;
		}

		// Get the cache transient
		$cache = (array) get_transient('sphere_plugin_social_followers');
		$key   = $type;
		$count = isset($cache[$key]) ? $cache[$key] : '';

		if (empty($cache) || !isset($cache[$key])) {
		
			try {
				$latest = call_user_func([$this, $method]);
			} catch (\Exception $e) {
				// don't be verbose about connection errors
			}

			// Only update if latest count is valid or cache is empty
			if ($latest OR empty($cache[$key])) {
				$cache[$key] = $latest;
			}
			
			// Cache the results for a day
			set_transient(
				'sphere_plugin_social_followers', 
				$cache, 
				apply_filters('sphere_plugin_social_followers_cache', DAY_IN_SECONDS)
			);
		}

		return $cache[$key];
	}

	/** 
	 * Remove transient cache
	 */
	public function flush_cache()
	{
		delete_transient('sphere_plugin_social_followers');
	}
	
	/**
	 * Get facebook followers count
	 */
	public function get_facebook()
	{
		if (empty($this->options['sf_facebook_id'])) {
			return false;
		}
	
		$url = 'https://www.facebook.com/v3.2/plugins/page.php?' . http_build_query([
			'href'          => 'https://facebook.com/' . $this->options['sf_facebook_id'],
			'tabs'          => '',
			'show_facepile' => 'false',
			'small_header'  => 'true',
			'locale'        => 'en_US'
		]);
	
		// Get data from API
		$data = $this->remote_get($url);
		if ($data) {
			preg_match('/<\/?(?:[a-z]+)>([\d,\.]+(K|M|<|\s)).*?likes/is', $data, $match);

			if (!empty($match[1])) {

				$string     = strip_tags($match[1]);
				$multiplier = 1;

				if (strstr($string, 'M')) {
					$multiplier = 1000000;
				}
				else if (strstr($string, 'K')) {
					$multiplier = 1000;
				}

				$count  = filter_var($string, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION);
				$count  = abs(intval($count * $multiplier));
			}
		}
		
		return !empty($count) ? $count : 0;
	}
	
	/**
	 * Get Google+ followers count
	 * 
	 * @deprecated 1.1.6
	 */
	public function get_gplus()
	{
		// Options required
		if (empty($this->options['sf_gplus_id']) OR empty($this->options['sf_gplus_key'])) {
			return false;
		}
		
		$url = 'https://www.googleapis.com/plus/v1/people/' . urlencode($this->options['sf_gplus_id']) 
			 . '?key=' . urlencode($this->options['sf_gplus_key']);
		
		// Get data from API
		$data = $this->remote_get($url);
		$data = json_decode($data, true);
		
		return !empty($data['circledByCount']) ? intval($data['circledByCount']) : 0;
	}
	
	/**
	 * Get YouTube followers count
	 */
	public function get_youtube()
	{
		// Options required
		if (empty($this->options['sf_youtube_id']) OR empty($this->options['sf_youtube_key'])) {
			return false;
		}
		
		$url = 'https://www.googleapis.com/youtube/v3/channels?' . http_build_query([
			'part' => 'statistics',
			'id'   => $this->options['sf_youtube_id'],
			'key'  => $this->options['sf_youtube_key']
		]);
		
		// Get data from API
		$data = $this->remote_get($url);
		$data = json_decode($data, true);
		$count = 0;
		
		if (!empty($data['items'][0]['statistics']['subscriberCount'])) {
			$count = $data['items'][0]['statistics']['subscriberCount'];
		}
		
		return intval($count);
	}
	
	/**
	 * Get YouTube followers count
	 */
	public function get_vimeo()
	{
		// Options required
		if (empty($this->options['sf_vimeo_id'])) {
			return false;
		}
		
		$base = 'https://vimeo.com/api/v2/';
		$key  = 'total_contacts';
		
		// Is it a channel?
		$type = !empty($this->options['sf_vimeo_type']) ? $this->options['sf_vimeo_type'] : '';
		if ($type == 'channel') {
			$base = 'https://vimeo.com/api/v2/channel/';
			$key  = 'total_subscribers';
		}
		
		$url = $base . urlencode($this->options['sf_vimeo_id']) .'/info.json';
		
		// Get data from API
		$data = $this->remote_get($url);
		$data = json_decode($data, true);
		
		return !empty($data[$key]) ? $data[$key] : 0;
	}
	
	
	/**
	 * Get Twitter follower count.
	 * 
	 * @deprecated 1.6.5
	 */
	public function get_twitter()
	{
		if (!$this->_check_options(['id', 'key', 'secret', 'token', 'token_secret'], 'sf_twitter_')) {
			return false;
		}
		
		// Twitter API class
		require_once SPHERE_SF_DIR . '../vendor/twitter-api.php';
		
		$settings = [
			'oauth_access_token'        => $this->options['sf_twitter_token'],
			'oauth_access_token_secret' => $this->options['sf_twitter_token_secret'],
			'consumer_key'              => $this->options['sf_twitter_key'],
			'consumer_secret'           => $this->options['sf_twitter_secret']
		];
		
		$url = 'https://api.twitter.com/1.1/users/show.json';
		$twitter = new \TwitterAPIExchange($settings);
		
		// Perform request and get data
		$data = $twitter
					->setGetfield('?screen_name=' . $this->options['sf_twitter_id'])
					->buildOauth($url, 'GET')
					->performRequest();
		
		$data = json_decode($data, true);
		
		return !empty($data['followers_count']) ? $data['followers_count'] : 0;
	}
	
	/**
	 * Get Instagram follower count
	 */
	public function get_instagram()
	{
		if (empty($this->options['sf_instagram_id'])) {
			return false;
		}
		
		// Scrape it from the live site's JSON
		$url   = 'https://www.instagram.com/' . urlencode($this->options['sf_instagram_id']) . '/';
		$data  = $this->remote_get($url);
		$count = 0;

		// Have a match
		if (preg_match('/"edge_followed_by"[^{]+{"count"\:\s?([0-9]+)/', $data, $match)) {
			$count = $match[1];
		}
		
		return intval($count);
	}
	
	/**
	 * Get Pinterest followers
	 */
	public function get_pinterest()
	{
		if (empty($this->options['sf_pinterest_id'])) {
			return false;
		}
		
		$data = $this->remote_get('https://www.pinterest.com/' . urlencode($this->options['sf_pinterest_id']) . '/');
		preg_match('#property\=.?pinterestapp:followers([^>]+?)content\=.?(\d*)#i', $data, $match);
		
		$count = 0;
		
		if (!empty($match[2])) {
			$count = $match[2];
		}
		
		return intval($count);	
	}
	
	/**
	 * Check required data is available in options
	 * 
	 * @param  array $keys
	 * @return bool  True if all exist
	 */
	public function _check_options($keys, $prefix = 'sf_') 
	{
		foreach ($keys as $key) {
			if (!array_key_exists($prefix . $key, $this->options)) {
				return false;
			}
		}
		
		return true;
	}
		
	/**
	 * A wrapper for wp_remote_get()
	 * 
	 * @see wp_remote_get()
	 * @param string $url
	 * @param array  $args
	 * @return string
	 */
	private function remote_get($url, $args = []) 
	{
		$params = array_merge([
			'timeout'    => $this->timeout,
			'user-agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36',
			'headers'    => [
				'Accept-language' => 'en-US,en;q=0.9',
			],
		], $args);

		$response = wp_remote_get($url, $params);
		
		if (is_wp_error($response)) {
			return '';
		}
		
		return $response['body'];
	}
	
}PK03Y�-���.sphere-core/components/social-share/module.php<?php
namespace Sphere\Core\SocialShare;

/**
 * Get social sharing from the APIs.
 */
class Module
{
	/**
	 * Maximum for remote requests
	 * 
	 * @var integer
	 */
	public $timeout = 10;
	
	/**
	 * Get share count for a specific service
	 * 
	 * @param string       $type     The service name
	 * @param integer|null $post_id  Post ID if not in loop 
	 * @param integer|null $url      If explicitly defining the URL
	 */
	public function count($type, $post_id = null, $url = null)
	{
		// Method exists?
		$method = 'get_' . $type;
		if (!method_exists($this, $method)) {
			return 0;
			
		}
		
		// Get the cache transient
		$cache = (array) get_transient('sphere_plugin_social_counts');
		
		if (!$post_id) {
			$post_id = get_the_ID();
		}
		
		$key   = $type . '_' . $post_id;
		$count = isset($cache[$key]) ? $cache[$key] : '';

		if (empty($cache) OR !isset($cache[$key])) {
			
			// Use post permalink if no URL set
			if (!$url) {
				$url = get_permalink($post_id);
			}
			
			$cache[$key] = call_user_func(array($this, $method), $url);
			
			// Cache the results for a day
			set_transient(
				'sphere_plugin_social_counts', 
				$cache, 
				apply_filters('sphere_plugin_social_cache', DAY_IN_SECONDS)
			);
		}

		return $cache[$key];
	}
	
	/**
	 * Twitter shares
	 * 
	 * @param  string $url
	 * @return integer
	 */
	public function get_twitter($url) 
	{
		$json = $this->remote_get('http://public.newsharecounts.com/count.json?url=' . $url);
		$json = json_decode($json, true);
		
		return isset($json['count']) ? intval($json['count']) : 0;
	}

	/**
	 * Get Linked In Shares
	 * 
	 * @param  string $url
	 * @return integer
	 */
	public function get_linkedin($url) 
	{ 
		$json = $this->remote_get('http://www.linkedin.com/countserv/count/share?url=' . $url . '&format=json');
		$json = json_decode($json, true);
		
		return isset($json['count']) ? intval($json['count']) : 0;
	}

	/**
	 * Get Facebook shares
	 * 
	 * @param  string $url
	 * @return integer
	 */
	public function get_facebook($url)
	{
		//$json = $this->remote_get('http://api.facebook.com/restserver.php?method=links.getStats&format=json&urls=' . $url);
		$json = $this->remote_get('http://graph.facebook.com/?id=' . $url);
		$json = json_decode($json, true);
		
		//return !empty($json[0]['total_count']) ? intval($json[0]['total_count']) : 0;
		
		return !empty($json['share']['share_count']) ? intval($json['share']['share_count']) : 0;
	}

	/**
	 * Get Google+ Shares for a URL
	 * 
	 * @param  string $url
	 * @return integer
	 */
	public function get_gplus($url) 
	{
		$response = wp_remote_request('https://clients6.google.com/rpc', array(
			'method'  => 'POST',
			'body'    => '[{"method":"pos.plusones.get","id":"p","params":{"nolog":true,"id":"' . esc_attr(rawurldecode($url)) . '","source":"widget","userId":"@viewer","groupId":"@self"},"jsonrpc":"2.0","key":"p","apiVersion":"v1"}]',
			'headers' => array('Content-Type' => 'application/json')
		));
		
		if (is_wp_error($response)) {
			return 0;
		}
		
		$json = json_decode($response['body'], true);
		
		return !empty($json[0]['result']['metadata']['globalCounts']['count']) ? intval($json[0]['result']['metadata']['globalCounts']['count']) : 0;		
	}

	/**
	 * Get Stumbleupon count
	 * 
	 * @param  string $url
	 * @return integer
	 */
	public function get_stumbleupon($url) 
	{
		$json = $this->remote_get('http://www.stumbleupon.com/services/1.01/badge.getinfo?url=' . $url);
		$json = json_decode($json, true);
		
		return isset($json['result']['views']) ? intval($json['result']['views']) : 0;
	}

	/**
	 * Get Pinterest pins
	 * 
	 * @param  string $url
	 * @return integer
	 */
	public function get_pinterest($url) 
	{
		$return_data = $this->remote_get('http://api.pinterest.com/v1/urls/count.json?url=' .  $url);
		$json = preg_replace('/^receiveCount((.*))$/', "\1", $return_data);
		$json = json_decode($json, true);
		
		return isset($json['count']) ? intval($json['count']) : 0;
	}

	/**
	 * A wrapper for wp_remote_get()
	 * 
	 * @param  string $url
	 * @return string
	 * @see wp_remote_get()
	 */
	private function remote_get($url) 
	{
		$response = wp_remote_get($url, array(
			'timeout' => $this->timeout,
		));
		
		if (is_wp_error($response)) {
			return '';
		}
		
		return $response['body'];
	}
}PK03YZ�̚�,�,-sphere-core/components/vendor/twitter-api.php<?php
/**
 * 
 * NOTE: Modified to be comaptible with PHP 5.2
 * 
 * Twitter-API-PHP : Simple PHP wrapper for the v1.1 API
 *
 * @category Awesomeness
 * @package  Twitter-API-PHP
 * @author   James Mallison <[email protected]>
 * @license  MIT License
 * @version  1.0.4
 * @link     http://github.com/j7mbo/twitter-api-php
 */
if (!class_exists('TwitterAPIExchange')) {
	
	class TwitterAPIExchange
	{
	    /**
	     * @var string
	     */
	    private $oauth_access_token;
	
	    /**
	     * @var string
	     */
	    private $oauth_access_token_secret;
	
	    /**
	     * @var string
	     */
	    private $consumer_key;
	
	    /**
	     * @var string
	     */
	    private $consumer_secret;
	
	    /**
	     * @var array
	     */
	    private $postfields;
	
	    /**
	     * @var string
	     */
	    private $getfield;
	
	    /**
	     * @var mixed
	     */
	    protected $oauth;
	
	    /**
	     * @var string
	     */
	    public $url;
	
	    /**
	     * @var string
	     */
	    public $requestMethod;
	
	    /**
	     * The HTTP status code from the previous request
	     *
	     * @var int
	     */
	    protected $httpStatusCode;
	
	    /**
	     * Create the API access object. Requires an array of settings::
	     * oauth access token, oauth access token secret, consumer key, consumer secret
	     * These are all available by creating your own application on dev.twitter.com
	     * Requires the cURL library
	     *
	     * @throws \RuntimeException When cURL isn't loaded
	     * @throws \InvalidArgumentException When incomplete settings parameters are provided
	     *
	     * @param array $settings
	     */
	    public function __construct(array $settings)
	    {
	        if (!function_exists('curl_init'))
	        {
	            throw new RuntimeException('TwitterAPIExchange requires cURL extension to be loaded, see: http://curl.haxx.se/docs/install.html');
	        }
	
	        if (!isset($settings['oauth_access_token'])
	            || !isset($settings['oauth_access_token_secret'])
	            || !isset($settings['consumer_key'])
	            || !isset($settings['consumer_secret']))
	        {
	            throw new InvalidArgumentException('Incomplete settings passed to TwitterAPIExchange');
	        }
	
	        $this->oauth_access_token = $settings['oauth_access_token'];
	        $this->oauth_access_token_secret = $settings['oauth_access_token_secret'];
	        $this->consumer_key = $settings['consumer_key'];
	        $this->consumer_secret = $settings['consumer_secret'];
	    }
	
	    /**
	     * Set postfields array, example: array('screen_name' => 'J7mbo')
	     *
	     * @param array $array Array of parameters to send to API
	     *
	     * @throws \Exception When you are trying to set both get and post fields
	     *
	     * @return TwitterAPIExchange Instance of self for method chaining
	     */
	    public function setPostfields(array $array)
	    {
	        if (!is_null($this->getGetfield()))
	        {
	            throw new Exception('You can only choose get OR post fields.');
	        }
	
	        if (isset($array['status']) && substr($array['status'], 0, 1) === '@')
	        {
	            $array['status'] = sprintf("\0%s", $array['status']);
	        }
	
	        foreach ($array as $key => &$value)
	        {
	            if (is_bool($value))
	            {
	                $value = ($value === true) ? 'true' : 'false';
	            }
	        }
	
	        $this->postfields = $array;
	
	        // rebuild oAuth
	        if (isset($this->oauth['oauth_signature'])) {
	            $this->buildOauth($this->url, $this->requestMethod);
	        }
	
	        return $this;
	    }
	
	    /**
	     * Set getfield string, example: '?screen_name=J7mbo'
	     *
	     * @param string $string Get key and value pairs as string
	     *
	     * @throws \Exception
	     *
	     * @return \TwitterAPIExchange Instance of self for method chaining
	     */
	    public function setGetfield($string)
	    {
	        if (!is_null($this->getPostfields()))
	        {
	            throw new Exception('You can only choose get OR post fields.');
	        }
	
	        $getfields = preg_replace('/^\?/', '', explode('&', $string));
	        $params = array();
	
	        foreach ($getfields as $field)
	        {
	            if ($field !== '')
	            {
	                list($key, $value) = explode('=', $field);
	                $params[$key] = $value;
	            }
	        }
	
	        $this->getfield = '?' . http_build_query($params);
	
	        return $this;
	    }
	
	    /**
	     * Get getfield string (simple getter)
	     *
	     * @return string $this->getfields
	     */
	    public function getGetfield()
	    {
	        return $this->getfield;
	    }
	
	    /**
	     * Get postfields array (simple getter)
	     *
	     * @return array $this->postfields
	     */
	    public function getPostfields()
	    {
	        return $this->postfields;
	    }
	
	    /**
	     * Build the Oauth object using params set in construct and additionals
	     * passed to this method. For v1.1, see: https://dev.twitter.com/docs/api/1.1
	     *
	     * @param string $url           The API url to use. Example: https://api.twitter.com/1.1/search/tweets.json
	     * @param string $requestMethod Either POST or GET
	     *
	     * @throws \Exception
	     *
	     * @return \TwitterAPIExchange Instance of self for method chaining
	     */
	    public function buildOauth($url, $requestMethod)
	    {
	        if (!in_array(strtolower($requestMethod), array('post', 'get')))
	        {
	            throw new Exception('Request method must be either POST or GET');
	        }
	
	        $consumer_key              = $this->consumer_key;
	        $consumer_secret           = $this->consumer_secret;
	        $oauth_access_token        = $this->oauth_access_token;
	        $oauth_access_token_secret = $this->oauth_access_token_secret;
	
	        $oauth = array(
	            'oauth_consumer_key' => $consumer_key,
	            'oauth_nonce' => time(),
	            'oauth_signature_method' => 'HMAC-SHA1',
	            'oauth_token' => $oauth_access_token,
	            'oauth_timestamp' => time(),
	            'oauth_version' => '1.0'
	        );
	
	        $getfield = $this->getGetfield();
	
	        if (!is_null($getfield))
	        {
	            $getfields = str_replace('?', '', explode('&', $getfield));
	
	            foreach ($getfields as $g)
	            {
	                $split = explode('=', $g);
	
	                /** In case a null is passed through **/
	                if (isset($split[1]))
	                {
	                    $oauth[$split[0]] = urldecode($split[1]);
	                }
	            }
	        }
	
	        $postfields = $this->getPostfields();
	
	        if (!is_null($postfields)) {
	            foreach ($postfields as $key => $value) {
	                $oauth[$key] = $value;
	            }
	        }
	
	        $base_info = $this->buildBaseString($url, $requestMethod, $oauth);
	        $composite_key = rawurlencode($consumer_secret) . '&' . rawurlencode($oauth_access_token_secret);
	        $oauth_signature = base64_encode(hash_hmac('sha1', $base_info, $composite_key, true));
	        $oauth['oauth_signature'] = $oauth_signature;
	
	        $this->url = $url;
	        $this->requestMethod = $requestMethod;
	        $this->oauth = $oauth;
	
	        return $this;
	    }
	
	    /**
	     * Perform the actual data retrieval from the API
	     *
	     * @param boolean $return      If true, returns data. This is left in for backward compatibility reasons
	     * @param array   $curlOptions Additional Curl options for this request
	     *
	     * @throws \Exception
	     *
	     * @return string json If $return param is true, returns json data.
	     */
	    public function performRequest($return = true, $curlOptions = array())
	    {
	        if (!is_bool($return))
	        {
	            throw new Exception('performRequest parameter must be true or false');
	        }
	
	        $header =  array($this->buildAuthorizationHeader($this->oauth), 'Expect:');
	
	        $getfield = $this->getGetfield();
	        $postfields = $this->getPostfields();
	
	        $options = array(
	            CURLOPT_HTTPHEADER => $header,
	            CURLOPT_HEADER => false,
	            CURLOPT_URL => $this->url,
	            CURLOPT_RETURNTRANSFER => true,
	            CURLOPT_TIMEOUT => 10,
	        ) + $curlOptions;
	
	        if (!is_null($postfields))
	        {
	            $options[CURLOPT_POSTFIELDS] = http_build_query($postfields);
	        }
	        else
	        {
	            if ($getfield !== '')
	            {
	                $options[CURLOPT_URL] .= $getfield;
	            }
	        }
	
	        $feed = curl_init();
	        curl_setopt_array($feed, $options);
	        $json = curl_exec($feed);
	
	        $this->httpStatusCode = curl_getinfo($feed, CURLINFO_HTTP_CODE);
	
	        if (($error = curl_error($feed)) !== '')
	        {
	            curl_close($feed);
	
	            throw new Exception($error);
	        }
	
	        curl_close($feed);
	
	        return $json;
	    }
	
	    /**
	     * Private method to generate the base string used by cURL
	     *
	     * @param string $baseURI
	     * @param string $method
	     * @param array  $params
	     *
	     * @return string Built base string
	     */
	    private function buildBaseString($baseURI, $method, $params)
	    {
	        $return = array();
	        ksort($params);
	
	        foreach($params as $key => $value)
	        {
	            $return[] = rawurlencode($key) . '=' . rawurlencode($value);
	        }
	
	        return $method . "&" . rawurlencode($baseURI) . '&' . rawurlencode(implode('&', $return));
	    }
	
	    /**
	     * Private method to generate authorization header used by cURL
	     *
	     * @param array $oauth Array of oauth data generated by buildOauth()
	     *
	     * @return string $return Header used by cURL for request
	     */
	    private function buildAuthorizationHeader(array $oauth)
	    {
	        $return = 'Authorization: OAuth ';
	        $values = array();
	
	        foreach($oauth as $key => $value)
	        {
	            if (in_array($key, array('oauth_consumer_key', 'oauth_nonce', 'oauth_signature',
	                'oauth_signature_method', 'oauth_timestamp', 'oauth_token', 'oauth_version'))) {
	                $values[] = "$key=\"" . rawurlencode($value) . "\"";
	            }
	        }
	
	        $return .= implode(', ', $values);
	        return $return;
	    }
	
	    /**
	     * Helper method to perform our request
	     *
	     * @param string $url
	     * @param string $method
	     * @param string $data
	     * @param array  $curlOptions
	     *
	     * @throws \Exception
	     *
	     * @return string The json response from the server
	     */
	    public function request($url, $method = 'get', $data = null, $curlOptions = array())
	    {
	        if (strtolower($method) === 'get')
	        {
	            $this->setGetfield($data);
	        }
	        else
	        {
	            $this->setPostfields($data);
	        }
	
	        return $this->buildOauth($url, $method)->performRequest(true, $curlOptions);
	    }
	
	    /**
	     * Get the HTTP status code for the previous request
	     *
	     * @return integer
	     */
	    public function getHttpStatusCode()
	    {
	        return $this->httpStatusCode;
	    }
	}
}PK03Y��DC��sphere-core/lib/loader.php<?php

namespace Bunyad\Lib;

/**
 * Autoloader for loading classes off defined namespaces or a class map.
 */
class Loader
{
	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} ");
	}
}PK03Y:�"sphere-core/lib/plugin-updates.php<?php
/**
 * Handle plugin updates for self-hosted ThemeSphere plugins.
 * 
 * @copyright 2023 ThemeSphere
 */
class Bunyad_Plugin_Updates
{
	const UPDATE_URL   = 'https://system.theme-sphere.com/plugin-versions.json';
	const PACKAGES_URL = 'https://updates-cdn.theme-sphere.com';

	/**
	 * @var null|array Remote response data, cached for multiple calls.
	 */
	protected $remote_data;

	public function __construct()
	{
		// Check for version difference via the typical update hook.
		add_filter('pre_set_site_transient_update_plugins', [$this, 'check_update'], 99);

		// Note: With lower priority than admin-notices module.
		add_action('admin_notices', [$this, 'autoupdates_dependence_check'], 1);
	}

	/**
	 * Ensure critical plugin updates are enabled when theme autoupdates are enabled.
	 */
	public function autoupdates_dependence_check()
	{
		if (!class_exists('\Bunyad') || !\Bunyad::admin_notices()) {
			return;
		}

		// Check if auto-updates enabled for current theme.
		$themes_auto_updates = (array) get_site_option('auto_update_themes');
		if (!$themes_auto_updates || !in_array(get_template(), $themes_auto_updates)) {
			return;
		}

		$plugins_auto_updates = (array) get_site_option('auto_update_plugins');
		$plugins_file = get_template_directory() . '/inc/admin/theme-plugins.php';
		if (!file_exists($plugins_file)) {
			return;
		}

		$dependent_plugins = include $plugins_file; // Safe formed above.
		$invalid_plugins   = [];
		foreach ($dependent_plugins as $plugin) {
			if (empty($plugin['required'])) {
				continue;
			}
			
			$plugin_slug = "{$plugin['slug']}/{$plugin['slug']}.php";
			if (!in_array($plugin_slug, $plugins_auto_updates)) {
				$invalid_plugins[] = $plugin['name'];
			}
		}
		
		if (!$invalid_plugins) {
			return;
		}
		
		\Bunyad::admin_notices()->add(
			'auto-updates-required-' . \Bunyad::options()->get_config('theme_version'),
			sprintf(
				'<h3>Required Plugins Autoupdates</h3>
				<p>Since you have enabled auto-updates for the theme, to prevent errors, please also enable auto-updates for these required plugins from the Plugins page:</p>
				<p><strong>%s</strong></p>
				<p>Alternative: If you do not want auto-updates for the above plugins, disable auto-updates for the theme. You can still use one-click updates.</p>
				',
				implode(', ', $invalid_plugins)
			),
			['type' => 'error']
		);
	}

	/**
	 * Check for plugin updates via the remote server.
	 * 
	 * Note: This may be called twice via core or more via 3rd parties.
	 *
	 * @param object $transient
	 */
	public function check_update($transient)
	{
		// Return if already have run the update check, or it's not a TS theme.
		$not_ts_theme = !class_exists('\Bunyad') || !Bunyad::core();
		if (empty($transient->last_checked) || $not_ts_theme) {
			return $transient;
		}

		$releases = $this->get_releases_data();
		if (!$releases) {
			return $transient;
		}
		
		// For auto-updates compatibility.
		if (!isset($transient->no_update)) {
			$transient->no_update = [];
		}

		// Needed for getting version of installed local plugin.
		$local_plugins = get_plugins();

		foreach ($releases as $plugin_slug => $data) {

			// A plugin name contains slug and filename.
			$plugin = $data['plugin'] ?? $plugin_slug . "/{$plugin_slug}.php";

			// Store existing data of any other updater, temporarily.
			$other_updater = $transient->response[$plugin] ?? false;

			// Safeguard against WP.org plugin with the same slug, that may have an update.
			unset($transient->response[$plugin]);

			if (empty($data['releases']) || empty($local_plugins[$plugin]['Version'])) {
				continue;
			}

			$local_plugin_version = $local_plugins[$plugin]['Version'];
			$plugin_info = array_intersect_key(
				$data,
				array_flip([
					'url', 
					'icons',
					'banners',
				])
			);

			$new_version = $this->get_latest_release(
				$local_plugin_version,
				$data['releases']
			);

			/**
			 * Check if we have a newer version from another updated, likely TGMPA packaged.
			 */
			if ($new_version && $other_updater) {
				if (
					!empty($other_updater->new_version)
					&& version_compare($new_version['version'], $other_updater->new_version, '<')
					&& strpos($other_updater->package, get_stylesheet_directory()) !== false
				) {
					$transient->response[$plugin] = $other_updater;
					continue;
				}
			}

			/**
			 * We have a new update with a valid URL.
			 * 
			 * Prevent system compromise: URL has to be valid and start at char 0.
			 */
			if ($new_version && strpos($new_version['package'], self::PACKAGES_URL) === 0) {
				$update_info = $plugin_info + array_intersect_key(
					$new_version,
					array_flip([
						'package',
						'requires', 
						'requires_php',
						'tested',
					])
				);
				
				// Add extra data if not already present.
				$update_info += [
					'slug'        => $plugin_slug,
					'plugin'      => $plugin,
					'new_version' => $new_version['version'],
				];

				$transient->response[$plugin] = (object) $update_info;

				if (!isset($transient->checked)) {
					$transient->checked = [];
				}
				
				$transient->checked[$plugin] = $local_plugin_version;

				if (isset($transient->no_update)) {
					unset($transient->no_update[$plugin]);
				}
			}
			else {
				// Added for auto-update compatibility.
				$transient->no_update[$plugin] = (object) array_replace(
					$plugin_info,
					[
						'slug'        => $plugin_slug,
						'plugin'      => $plugin,
						'new_version' => $local_plugin_version,
					]
				);
			}
		}

		return $transient;
	}

	/**
	 * Get latest compatible release.
	 *
	 * @param string $current
	 * @param array $releases
	 * @return bool|array
	 */
	protected function get_latest_release($current, array $releases = [])
	{
		// Sort in ascending order by version.
		usort($releases, function($a, $b) {
			return version_compare($b['version'], $a['version']);
		});

		$latest = false;
		$theme  = Bunyad::options()->get_config('theme_name');

		if (!$theme) {
			return false;
		}

		foreach ($releases as $release) {

			// First in loop is the latest if no theme compat check.
			if (empty($release['theme_compat']) || !isset($release['theme_compat'][$theme])) {
				$latest = $release;
				break;
			}

			$theme_compatible = version_compare(
				Bunyad::options()->get_config('theme_version'),
				$release['theme_compat'][$theme],
				'>='
			);

			if ($theme_compatible) {
				$latest = $release;
				break;
			}
		}

		// Current version is already newer or at least release.
		if ($latest && version_compare($current, $latest['version'], '>=')) {
			return false;
		}

		return $latest;
	}

	public function get_releases_data()
	{
		/**
		 * Make a remote request if we haven't already done so. Cache remote data and
		 * check for it, as sometimes WP may update 'update_plugins' transient twice, 
		 * hencing calling this method twice.
		 */
		if (!$this->remote_data) {
			$request_args = [];

			// if (class_exists('\Bunyad') && is_callable([Bunyad::core(), 'get_license'])) {
			// 	$api_key = Bunyad::core()->get_license();
			// 	if (!empty($api_key)) {
			// 		$request_args['headers'] = ['X-API-KEY' => $api_key];
			// 	}
			// }

			$this->remote_data = wp_safe_remote_get(
				self::UPDATE_URL,
				$request_args
			);
		}

		if (200 !== wp_remote_retrieve_response_code($this->remote_data)) {
			return false;
		}

		return (array) json_decode($this->remote_data['body'], true);
	}
}PK03Y�Ĕ�����sphere-core/sphere-core.phpPK03Y���^DD0���sphere-core/components/adblock-detect/module.phpPK03YT'����1��Tsphere-core/components/adblock-detect/options.phpPK03Y�\VG3��?4sphere-core/components/adblock-detect/css/modal.cssPK03Y�2n��6���6sphere-core/components/adblock-detect/css/ts-modal.cssPK03Y�ʬDD.��|<sphere-core/components/adblock-detect/js/ad.jsPK03Y�n��	�	2��=sphere-core/components/adblock-detect/js/detect.jsPK03Y�^��AA7��:Gsphere-core/components/adblock-detect/js/micro-modal.jsPK03Y��(	��0���bsphere-core/components/auto-load-post/module.phpPK03YÝ�b��1���ysphere-core/components/auto-load-post/options.phpPK03Y���PVV:��ˁsphere-core/components/auto-load-post/js/auto-load-post.jsPK03Y��l�OO0��y�sphere-core/components/breadcrumbs/generator.phpPK03Yv�O���-���sphere-core/components/breadcrumbs/module.phpPK03Y�zB���-��
�sphere-core/components/breadcrumbs/schema.phpPK03YV�B���8���sphere-core/components/elementor/dynamic-tags/module.phpPK03Y%Qa>>J����sphere-core/components/elementor/dynamic-tags/tags/archive-description.phpPK03Y�YttD����sphere-core/components/elementor/dynamic-tags/tags/archive-title.phpPK03YB��n�sphere-core/components/elementor/dynamic-tags/tags/author-meta.phpPK03YRi0�B����sphere-core/components/elementor/dynamic-tags/tags/author-name.phpPK03Y����@��F�sphere-core/components/elementor/dynamic-tags/tags/copyright.phpPK03Y�p
?����sphere-core/components/elementor/dynamic-tags/tags/site-url.phpPK03Y���J��2��4�sphere-core/components/elementor/layouts/admin.phpPK03YP:t3��1�sphere-core/components/elementor/layouts/module.phpPK03Ys��%%4���
sphere-core/components/elementor/layouts/preview.phpPK03YV=ִ�5��sphere-core/components/elementor/layouts/template.phpPK03YeӬ66��0sphere-core/components/elementor/layouts/css/admin.cssPK03Y�
#/��>���3sphere-core/components/elementor/layouts/documents/archive.phpPK03Yvn��;;;���8sphere-core/components/elementor/layouts/documents/base.phpPK03YR�ؚ��=��Q=sphere-core/components/elementor/layouts/documents/footer.phpPK03YŐ�eKK4���?sphere-core/components/elementor/layouts/js/admin.jsPK03YțZ�PPB��FCsphere-core/components/elementor/layouts/page-templates/canvas.phpPK03Y�"~��E���Dsphere-core/components/elementor/layouts/page-templates/ts-footer.phpPK03Y�����<���Fsphere-core/components/elementor/layouts/views/add-modal.phpPK03Y��ٜ��7���Ksphere-core/components/elementor/layouts/views/tabs.phpPK03Y��j='''���Msphere-core/components/likes/module.phpPK03Y6B�1��/��L\sphere-core/components/social-follow/module.phpPK03Y�-���.����sphere-core/components/social-share/module.phpPK03YZ�̚�,�,-����sphere-core/components/vendor/twitter-api.phpPK03Y��DC�����sphere-core/lib/loader.phpPK03Y:�"���.sphere-core/lib/plugin-updates.phpPK((o�KDownloaded From GPLAstra.com

Youez - 2016 - github.com/yon3zu
LinuXploit